Добавлена диагностика источника настроек в админке
Этот коммит содержится в:
@@ -5,6 +5,7 @@ import {
|
|||||||
Bot,
|
Bot,
|
||||||
CheckCircle,
|
CheckCircle,
|
||||||
Clock,
|
Clock,
|
||||||
|
Database,
|
||||||
KeyRound,
|
KeyRound,
|
||||||
MessageCircle,
|
MessageCircle,
|
||||||
PlugZap,
|
PlugZap,
|
||||||
@@ -61,12 +62,14 @@ 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 [telegramBridge, setTelegramBridge] = useState(null);
|
||||||
const [telegramDirty, setTelegramDirty] = useState(false);
|
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);
|
||||||
const [lastUpdate, setLastUpdate] = useState(null);
|
const [lastUpdate, setLastUpdate] = useState(null);
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
|
const [telegramError, setTelegramError] = useState('');
|
||||||
const [telegramNotice, setTelegramNotice] = useState('');
|
const [telegramNotice, setTelegramNotice] = useState('');
|
||||||
const [proxyTestResult, setProxyTestResult] = useState(null);
|
const [proxyTestResult, setProxyTestResult] = useState(null);
|
||||||
|
|
||||||
@@ -104,10 +107,12 @@ function App() {
|
|||||||
async function loadTelegramSettings({ force = false } = {}) {
|
async function loadTelegramSettings({ force = false } = {}) {
|
||||||
if (telegramDirty && !force) return;
|
if (telegramDirty && !force) return;
|
||||||
|
|
||||||
|
setTelegramError('');
|
||||||
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);
|
||||||
|
setTelegramBridge(data.bridge || null);
|
||||||
setTelegramDirty(false);
|
setTelegramDirty(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,9 +136,15 @@ function App() {
|
|||||||
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 (healthData.telegram) setTelegramBridge(healthData.telegram);
|
||||||
|
if (statsData.telegram) setTelegramBridge(statsData.telegram);
|
||||||
|
|
||||||
if (includeTelegram) {
|
if (includeTelegram) {
|
||||||
await loadTelegramSettings({ force: false });
|
try {
|
||||||
|
await loadTelegramSettings({ force: false });
|
||||||
|
} catch (telegramRequestError) {
|
||||||
|
setTelegramError(telegramRequestError.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setLastUpdate(new Date());
|
setLastUpdate(new Date());
|
||||||
@@ -149,6 +160,7 @@ function App() {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setSavingTelegram(true);
|
setSavingTelegram(true);
|
||||||
setTelegramNotice('');
|
setTelegramNotice('');
|
||||||
|
setTelegramError('');
|
||||||
setProxyTestResult(null);
|
setProxyTestResult(null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -171,8 +183,9 @@ 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);
|
||||||
|
setTelegramBridge(data.bridge || telegramBridge);
|
||||||
setTelegramDirty(false);
|
setTelegramDirty(false);
|
||||||
setTelegramNotice('Настройки Telegram/SOCKS5 сохранены.');
|
setTelegramNotice(data.message || 'Настройки Telegram/SOCKS5 сохранены.');
|
||||||
} catch (saveError) {
|
} catch (saveError) {
|
||||||
setTelegramNotice(`Ошибка сохранения: ${saveError.message}`);
|
setTelegramNotice(`Ошибка сохранения: ${saveError.message}`);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -183,6 +196,7 @@ function App() {
|
|||||||
async function testProxy() {
|
async function testProxy() {
|
||||||
setTestingProxy(true);
|
setTestingProxy(true);
|
||||||
setTelegramNotice('');
|
setTelegramNotice('');
|
||||||
|
setTelegramError('');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(API_URL + '/api/admin/telegram/test-proxy', {
|
const response = await fetch(API_URL + '/api/admin/telegram/test-proxy', {
|
||||||
@@ -191,6 +205,7 @@ function App() {
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setProxyTestResult(data);
|
setProxyTestResult(data);
|
||||||
if (data.settings && !telegramDirty) setTelegramSettings(data.settings);
|
if (data.settings && !telegramDirty) setTelegramSettings(data.settings);
|
||||||
|
if (data.bridge) setTelegramBridge(data.bridge);
|
||||||
} catch (testError) {
|
} catch (testError) {
|
||||||
setProxyTestResult({ ok: false, status: 'error', message: testError.message });
|
setProxyTestResult({ ok: false, status: 'error', message: testError.message });
|
||||||
} finally {
|
} finally {
|
||||||
@@ -198,9 +213,31 @@ function App() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function restartBridge() {
|
||||||
|
setTestingProxy(true);
|
||||||
|
setTelegramNotice('');
|
||||||
|
setTelegramError('');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(API_URL + '/api/admin/telegram/restart', {
|
||||||
|
method: 'POST'
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
if (!data.ok) throw new Error(data.error || 'Bridge restart failed');
|
||||||
|
setTelegramBridge(data.bridge || null);
|
||||||
|
setTelegramNotice(data.bridge?.running ? 'Telegram bridge перезапущен.' : `Bridge не запущен: ${data.bridge?.error || 'unknown error'}`);
|
||||||
|
await loadDashboard({ silent: true, includeTelegram: true });
|
||||||
|
} catch (restartError) {
|
||||||
|
setTelegramError(restartError.message);
|
||||||
|
} finally {
|
||||||
|
setTestingProxy(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function resetTelegramForm() {
|
async function resetTelegramForm() {
|
||||||
setTelegramDirty(false);
|
setTelegramDirty(false);
|
||||||
setTelegramNotice('');
|
setTelegramNotice('');
|
||||||
|
setTelegramError('');
|
||||||
setProxyTestResult(null);
|
setProxyTestResult(null);
|
||||||
await loadTelegramSettings({ force: true });
|
await loadTelegramSettings({ force: true });
|
||||||
}
|
}
|
||||||
@@ -225,6 +262,9 @@ 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>
|
||||||
|
<span className={telegramBridge?.running ? 'status-pill ok' : 'status-pill bad'}>
|
||||||
|
<Bot size={14} /> bridge: {telegramBridge?.running ? 'online' : 'offline'}
|
||||||
|
</span>
|
||||||
{telegramDirty ? (
|
{telegramDirty ? (
|
||||||
<span className="status-pill warn">
|
<span className="status-pill warn">
|
||||||
<Save size={14} /> есть несохранённые изменения
|
<Save size={14} /> есть несохранённые изменения
|
||||||
@@ -235,13 +275,14 @@ function App() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button className="button" onClick={() => loadDashboard({ includeTelegram: false })} disabled={loading}>
|
<button className="button" onClick={() => loadDashboard({ includeTelegram: true })} disabled={loading}>
|
||||||
<RefreshCw size={18} className={loading ? 'spin' : ''} />
|
<RefreshCw size={18} className={loading ? 'spin' : ''} />
|
||||||
{loading ? 'Обновляю...' : 'Обновить'}
|
{loading ? 'Обновляю...' : 'Обновить'}
|
||||||
</button>
|
</button>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{error ? <div className="alert">Ошибка API: {error}</div> : null}
|
{error ? <div className="alert">Ошибка API: {error}</div> : null}
|
||||||
|
{telegramError ? <div className="alert">Ошибка Telegram settings API: {telegramError}</div> : null}
|
||||||
|
|
||||||
<section className="stats-grid">
|
<section className="stats-grid">
|
||||||
{statCards.map((card) => <StatCard key={card.label} {...card} />)}
|
{statCards.map((card) => <StatCard key={card.label} {...card} />)}
|
||||||
@@ -259,6 +300,13 @@ function App() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="diagnostics-grid">
|
||||||
|
<span><Server size={14} /> API: {API_URL}</span>
|
||||||
|
<span><Database size={14} /> DB: {health?.dbPath || 'неизвестно'}</span>
|
||||||
|
<span><Bot size={14} /> Bot: {telegramBridge?.username || 'неизвестно'}</span>
|
||||||
|
<span><Activity size={14} /> Error: {telegramBridge?.error || 'нет'}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<form className="settings-form" onSubmit={saveTelegramSettings}>
|
<form className="settings-form" onSubmit={saveTelegramSettings}>
|
||||||
<label className="field wide-field">
|
<label className="field wide-field">
|
||||||
<span>Telegram Bot Token</span>
|
<span>Telegram Bot Token</span>
|
||||||
@@ -343,9 +391,13 @@ function App() {
|
|||||||
<PlugZap size={18} className={testingProxy ? 'spin' : ''} />
|
<PlugZap size={18} className={testingProxy ? 'spin' : ''} />
|
||||||
{testingProxy ? 'Проверяю...' : 'Проверить прокси'}
|
{testingProxy ? 'Проверяю...' : 'Проверить прокси'}
|
||||||
</button>
|
</button>
|
||||||
|
<button className="button secondary-button" type="button" onClick={restartBridge} disabled={testingProxy || telegramDirty}>
|
||||||
|
<RefreshCw size={18} className={testingProxy ? 'spin' : ''} />
|
||||||
|
Restart bridge
|
||||||
|
</button>
|
||||||
<button className="ghost-button" type="button" onClick={resetTelegramForm}>Сбросить форму</button>
|
<button className="ghost-button" type="button" onClick={resetTelegramForm}>Сбросить форму</button>
|
||||||
</div>
|
</div>
|
||||||
{telegramDirty ? <small className="wide-field form-hint">Сначала сохраните изменения, потом проверяйте прокси.</small> : null}
|
{telegramDirty ? <small className="wide-field form-hint">Сначала сохраните изменения, потом проверяйте прокси или перезапускайте bridge.</small> : null}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{telegramNotice ? <div className="notice"><CheckCircle size={16} /> {telegramNotice}</div> : null}
|
{telegramNotice ? <div className="notice"><CheckCircle size={16} /> {telegramNotice}</div> : null}
|
||||||
@@ -395,7 +447,7 @@ function App() {
|
|||||||
<article className="panel compact-panel">
|
<article className="panel compact-panel">
|
||||||
<Wifi />
|
<Wifi />
|
||||||
<h2>Telegram / SOCKS5</h2>
|
<h2>Telegram / SOCKS5</h2>
|
||||||
<p>Прокси уже сохраняется в SQLite. Следующий шаг — подключить Telegraf bridge и отправлять сообщения сайта операторам.</p>
|
<p>Источник настроек: SQLite через API. Сверяйте блок диагностики выше: API URL, DB path и bridge status.</p>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<article className="panel compact-panel">
|
<article className="panel compact-panel">
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user