Refine subscription import and refresh flow
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { flushSync } from 'react-dom';
|
||||
import { api, validationStatusForError } from '../api.js';
|
||||
import { api } from '../api.js';
|
||||
import {
|
||||
connectionAction,
|
||||
connectionDurationParts,
|
||||
copyText,
|
||||
isSubscriptionUrlValid,
|
||||
localProxyUrls,
|
||||
subscriptionDomain,
|
||||
subscriptionDaysLeft,
|
||||
@@ -12,7 +13,7 @@ import {
|
||||
} from '../utils/clientControls.js';
|
||||
import { formatBytes } from '../utils/format.js';
|
||||
import { instructionBlocks } from '../instructions.js';
|
||||
import { createLatestRequest, operationBlocked } from '../state/operations.js';
|
||||
import { operationBlocked } from '../state/operations.js';
|
||||
import { ConfirmationPopup } from './ConfirmationPopup.jsx';
|
||||
import { canAppendRouteRule } from '../../shared/routingRules.js';
|
||||
import {
|
||||
@@ -594,8 +595,6 @@ export function ClientOverviewPage({
|
||||
}
|
||||
});
|
||||
const [editingSubscription, setEditingSubscription] = useState(!state?.hasSubscription);
|
||||
const [subscriptionValidation, setSubscriptionValidation] = useState({ url: '', status: 'idle' });
|
||||
const [validationAttempt, setValidationAttempt] = useState(0);
|
||||
const [showIntro, setShowIntro] = useState(!hasSubscription);
|
||||
const [subscriptionContentReady, setSubscriptionContentReady] = useState(hasSubscription);
|
||||
const [pings, setPings] = useState({});
|
||||
@@ -621,8 +620,6 @@ export function ClientOverviewPage({
|
||||
const localRulesToggleRef = useRef(null);
|
||||
const localRulesBaselineRef = useRef('[]');
|
||||
const previousHasSubscriptionRef = useRef(hasSubscription);
|
||||
const validationRequests = useRef(null);
|
||||
if (!validationRequests.current) validationRequests.current = createLatestRequest();
|
||||
const serverKey = servers.map((server) => `${server.tag}:${server.server}:${server.server_port}`).join('|');
|
||||
const gatewayAddress = isGateway ? window.location.hostname : '127.0.0.1';
|
||||
const proxyUrls = localProxyUrls(state?.proxyPort, gatewayAddress);
|
||||
@@ -646,12 +643,9 @@ export function ClientOverviewPage({
|
||||
? [openInstruction, ...instructionGuides.filter((block) => block.id !== openInstructionId)]
|
||||
: instructionGuides;
|
||||
const normalizedSubscriptionUrl = subscriptionUrl.trim();
|
||||
const subscriptionValidationStatus = subscriptionValidation.url === normalizedSubscriptionUrl
|
||||
? subscriptionValidation.status
|
||||
: normalizedSubscriptionUrl ? 'checking' : 'idle';
|
||||
const subscriptionError = subscriptionValidation.url === normalizedSubscriptionUrl
|
||||
? subscriptionValidation.error
|
||||
: null;
|
||||
const subscriptionValidationStatus = !normalizedSubscriptionUrl
|
||||
? 'idle'
|
||||
: isSubscriptionUrlValid(normalizedSubscriptionUrl) ? 'valid' : 'invalid';
|
||||
const subscriptionWaiting = hasSubscription && !subscriptionContentReady;
|
||||
const connectionBlocked = operationBlocked(operations, 'connection');
|
||||
const serverApplyBlocked = operationBlocked(operations, 'serverApply');
|
||||
@@ -729,54 +723,6 @@ export function ClientOverviewPage({
|
||||
return () => clearTimeout(timer);
|
||||
}, [hasSubscription]);
|
||||
|
||||
useEffect(() => {
|
||||
validationRequests.current.cancel();
|
||||
if (!normalizedSubscriptionUrl) {
|
||||
setSubscriptionValidation({ url: '', status: 'idle' });
|
||||
return undefined;
|
||||
}
|
||||
|
||||
setSubscriptionValidation({ url: normalizedSubscriptionUrl, status: 'checking' });
|
||||
const timer = setTimeout(() => {
|
||||
validationRequests.current
|
||||
.run((signal) => api.subscription.validate(normalizedSubscriptionUrl, signal))
|
||||
.then((result) => {
|
||||
if (!result) return;
|
||||
setSubscriptionValidation({
|
||||
url: normalizedSubscriptionUrl,
|
||||
status: 'valid',
|
||||
error: null,
|
||||
});
|
||||
})
|
||||
.catch((validationError) => {
|
||||
setSubscriptionValidation({
|
||||
url: normalizedSubscriptionUrl,
|
||||
status: validationStatusForError(validationError),
|
||||
error: {
|
||||
context: 'subscription',
|
||||
message: validationError.message,
|
||||
correlationId: validationError.correlationId,
|
||||
retry: validationError.retryable
|
||||
? () => {
|
||||
setSubscriptionValidation({
|
||||
url: normalizedSubscriptionUrl,
|
||||
status: 'checking',
|
||||
error: null,
|
||||
});
|
||||
setValidationAttempt((attempt) => attempt + 1);
|
||||
}
|
||||
: null,
|
||||
},
|
||||
});
|
||||
});
|
||||
}, 350);
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer);
|
||||
validationRequests.current.cancel();
|
||||
};
|
||||
}, [normalizedSubscriptionUrl, validationAttempt]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasSubscription) {
|
||||
setEditingSubscription(true);
|
||||
@@ -1317,22 +1263,16 @@ export function ClientOverviewPage({
|
||||
type="submit"
|
||||
aria-label={subscriptionValidationStatus === 'valid'
|
||||
? 'Сохранить подписку'
|
||||
: subscriptionValidationStatus === 'invalid'
|
||||
? 'Ссылка подписки не распознана'
|
||||
: subscriptionValidationStatus === 'unavailable'
|
||||
? 'Проверка подписки временно недоступна'
|
||||
: 'Проверяем ссылку подписки'}
|
||||
: 'Ссылка подписки не распознана'}
|
||||
disabled={subscriptionImportBlocked || subscriptionValidationStatus !== 'valid'}
|
||||
>
|
||||
{subscriptionValidationStatus === 'valid'
|
||||
? '✓'
|
||||
: subscriptionValidationStatus === 'invalid'
|
||||
? '×'
|
||||
: subscriptionValidationStatus === 'unavailable' ? '!' : '…'}
|
||||
: '×'}
|
||||
</button>
|
||||
)}
|
||||
</form>
|
||||
<InlineError error={subscriptionError || error} context="subscription" />
|
||||
<InlineError error={error} context="subscription" />
|
||||
<InlineProgress operations={operations} context="subscription" />
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user