Исправлено автообновление формы SOCKS5

Этот коммит содержится в:
Виктор
2026-05-08 17:59:51 +09:00
родитель 53fad336d3
Коммит 9999139ab5
+36 -15
Просмотреть файл
@@ -61,6 +61,7 @@ function App() {
const [stats, setStats] = useState(null); const [stats, setStats] = useState(null);
const [messages, setMessages] = useState([]); const [messages, setMessages] = useState([]);
const [telegramSettings, setTelegramSettings] = useState(emptyTelegramSettings); const [telegramSettings, setTelegramSettings] = useState(emptyTelegramSettings);
const [telegramDirty, setTelegramDirty] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [savingTelegram, setSavingTelegram] = useState(false); const [savingTelegram, setSavingTelegram] = useState(false);
const [testingProxy, setTestingProxy] = useState(false); const [testingProxy, setTestingProxy] = useState(false);
@@ -80,6 +81,7 @@ function App() {
]), [stats]); ]), [stats]);
function patchTelegramSettings(path, value) { function patchTelegramSettings(path, value) {
setTelegramDirty(true);
setTelegramSettings((current) => { setTelegramSettings((current) => {
if (path.startsWith('proxy.')) { if (path.startsWith('proxy.')) {
const key = path.replace('proxy.', ''); const key = path.replace('proxy.', '');
@@ -99,36 +101,41 @@ function App() {
}); });
} }
async function loadTelegramSettings() { async function loadTelegramSettings({ force = false } = {}) {
if (telegramDirty && !force) return;
const response = await fetch(API_URL + '/api/admin/telegram/settings'); const response = await fetch(API_URL + '/api/admin/telegram/settings');
const data = await response.json(); const data = await response.json();
if (!data.ok) throw new Error(data.error || 'Telegram settings load failed'); if (!data.ok) throw new Error(data.error || 'Telegram settings load failed');
setTelegramSettings(data.settings || emptyTelegramSettings); setTelegramSettings(data.settings || emptyTelegramSettings);
setTelegramDirty(false);
} }
async function loadDashboard({ silent = false } = {}) { async function loadDashboard({ silent = false, includeTelegram = false } = {}) {
if (!silent) setLoading(true); if (!silent) setLoading(true);
setError(''); setError('');
try { try {
const [healthResponse, statsResponse, messagesResponse, telegramResponse] = await Promise.all([ const [healthResponse, statsResponse, messagesResponse] = await Promise.all([
fetch(API_URL + '/health'), fetch(API_URL + '/health'),
fetch(API_URL + '/api/admin/stats'), fetch(API_URL + '/api/admin/stats'),
fetch(API_URL + '/api/admin/messages?limit=25'), fetch(API_URL + '/api/admin/messages?limit=25')
fetch(API_URL + '/api/admin/telegram/settings')
]); ]);
const [healthData, statsData, messagesData, telegramData] = await Promise.all([ const [healthData, statsData, messagesData] = await Promise.all([
healthResponse.json(), healthResponse.json(),
statsResponse.json(), statsResponse.json(),
messagesResponse.json(), messagesResponse.json()
telegramResponse.json()
]); ]);
setHealth(healthData); setHealth(healthData);
setStats(statsData.stats || null); setStats(statsData.stats || null);
setMessages(Array.isArray(messagesData.messages) ? messagesData.messages : []); setMessages(Array.isArray(messagesData.messages) ? messagesData.messages : []);
if (telegramData.ok) setTelegramSettings(telegramData.settings || emptyTelegramSettings);
if (includeTelegram) {
await loadTelegramSettings({ force: false });
}
setLastUpdate(new Date()); setLastUpdate(new Date());
} catch (requestError) { } catch (requestError) {
setHealth({ ok: false, error: requestError.message }); setHealth({ ok: false, error: requestError.message });
@@ -164,6 +171,7 @@ function App() {
const data = await response.json(); const data = await response.json();
if (!data.ok) throw new Error(data.error || 'Save failed'); if (!data.ok) throw new Error(data.error || 'Save failed');
setTelegramSettings(data.settings || emptyTelegramSettings); setTelegramSettings(data.settings || emptyTelegramSettings);
setTelegramDirty(false);
setTelegramNotice('Настройки Telegram/SOCKS5 сохранены.'); setTelegramNotice('Настройки Telegram/SOCKS5 сохранены.');
} catch (saveError) { } catch (saveError) {
setTelegramNotice(`Ошибка сохранения: ${saveError.message}`); setTelegramNotice(`Ошибка сохранения: ${saveError.message}`);
@@ -182,7 +190,7 @@ function App() {
}); });
const data = await response.json(); const data = await response.json();
setProxyTestResult(data); setProxyTestResult(data);
if (data.settings) setTelegramSettings(data.settings); if (data.settings && !telegramDirty) setTelegramSettings(data.settings);
} catch (testError) { } catch (testError) {
setProxyTestResult({ ok: false, status: 'error', message: testError.message }); setProxyTestResult({ ok: false, status: 'error', message: testError.message });
} finally { } finally {
@@ -190,9 +198,16 @@ function App() {
} }
} }
async function resetTelegramForm() {
setTelegramDirty(false);
setTelegramNotice('');
setProxyTestResult(null);
await loadTelegramSettings({ force: true });
}
useEffect(() => { useEffect(() => {
loadDashboard(); loadDashboard({ includeTelegram: true });
const timer = setInterval(() => loadDashboard({ silent: true }), REFRESH_MS); const timer = setInterval(() => loadDashboard({ silent: true, includeTelegram: false }), REFRESH_MS);
return () => clearInterval(timer); return () => clearInterval(timer);
}, []); }, []);
@@ -210,12 +225,17 @@ function App() {
<span className={telegramSettings.proxy.enabled ? 'status-pill ok' : 'status-pill muted'}> <span className={telegramSettings.proxy.enabled ? 'status-pill ok' : 'status-pill muted'}>
<Wifi size={14} /> SOCKS5: {telegramSettings.proxy.enabled ? 'включен' : 'выключен'} <Wifi size={14} /> SOCKS5: {telegramSettings.proxy.enabled ? 'включен' : 'выключен'}
</span> </span>
{telegramDirty ? (
<span className="status-pill warn">
<Save size={14} /> есть несохранённые изменения
</span>
) : null}
<span className="status-pill muted"> <span className="status-pill muted">
<Clock size={14} /> {lastUpdate ? `обновлено ${formatDate(lastUpdate)}` : 'ожидает данных'} <Clock size={14} /> {lastUpdate ? `обновлено ${formatDate(lastUpdate)}` : 'ожидает данных'}
</span> </span>
</div> </div>
</div> </div>
<button className="button" onClick={() => loadDashboard()} disabled={loading}> <button className="button" onClick={() => loadDashboard({ includeTelegram: false })} disabled={loading}>
<RefreshCw size={18} className={loading ? 'spin' : ''} /> <RefreshCw size={18} className={loading ? 'spin' : ''} />
{loading ? 'Обновляю...' : 'Обновить'} {loading ? 'Обновляю...' : 'Обновить'}
</button> </button>
@@ -319,12 +339,13 @@ function App() {
<Save size={18} className={savingTelegram ? 'spin' : ''} /> <Save size={18} className={savingTelegram ? 'spin' : ''} />
{savingTelegram ? 'Сохраняю...' : 'Сохранить'} {savingTelegram ? 'Сохраняю...' : 'Сохранить'}
</button> </button>
<button className="button secondary-button" type="button" onClick={testProxy} disabled={testingProxy}> <button className="button secondary-button" type="button" onClick={testProxy} disabled={testingProxy || telegramDirty}>
<PlugZap size={18} className={testingProxy ? 'spin' : ''} /> <PlugZap size={18} className={testingProxy ? 'spin' : ''} />
{testingProxy ? 'Проверяю...' : 'Проверить прокси'} {testingProxy ? 'Проверяю...' : 'Проверить прокси'}
</button> </button>
<button className="ghost-button" type="button" onClick={loadTelegramSettings}>Сбросить форму</button> <button className="ghost-button" type="button" onClick={resetTelegramForm}>Сбросить форму</button>
</div> </div>
{telegramDirty ? <small className="wide-field form-hint">Сначала сохраните изменения, потом проверяйте прокси.</small> : null}
</form> </form>
{telegramNotice ? <div className="notice"><CheckCircle size={16} /> {telegramNotice}</div> : null} {telegramNotice ? <div className="notice"><CheckCircle size={16} /> {telegramNotice}</div> : null}