- watchdog: проверка native-секции в slow-тире, авторестарт демона после 2 сбоев, TG-алерт раз в час - AI Doctor: узел Tailscale (готов/не установлен/упал) только при настроенном native - провайдер: режим peers — парсинг status --json через per-section socket - RPC get_tailscale_status/get_tailscale_peers/tailscale_restart - дашборд: карточка Tailscale (состояние, IP роутера, до 5 пиров с онлайн-статусом)
104 lines
2.6 KiB
TypeScript
104 lines
2.6 KiB
TypeScript
import { renderSections, renderWidget } from './partials';
|
|
|
|
export function render() {
|
|
return E(
|
|
'div',
|
|
{
|
|
id: 'dashboard-status',
|
|
class: 'tachyon_dashboard-page',
|
|
},
|
|
[
|
|
E(
|
|
'div',
|
|
{
|
|
class: 'tachyon_dashboard-page__service-stopped',
|
|
role: 'status',
|
|
},
|
|
_(
|
|
'Tachyon service is stopped. Start the service to display the dashboard.',
|
|
),
|
|
),
|
|
E('div', { class: 'tachyon_dashboard-page__content' }, [
|
|
E('div', { class: 'tachyon_dashboard-page__widgets-section' }, [
|
|
E(
|
|
'div',
|
|
{ id: 'dashboard-widget-traffic' },
|
|
renderWidget({
|
|
loading: true,
|
|
failed: false,
|
|
title: '',
|
|
items: [],
|
|
}),
|
|
),
|
|
E(
|
|
'div',
|
|
{ id: 'dashboard-widget-traffic-total' },
|
|
renderWidget({
|
|
loading: true,
|
|
failed: false,
|
|
title: '',
|
|
items: [],
|
|
}),
|
|
),
|
|
E(
|
|
'div',
|
|
{ id: 'dashboard-widget-system-info' },
|
|
renderWidget({
|
|
loading: true,
|
|
failed: false,
|
|
title: '',
|
|
items: [],
|
|
}),
|
|
),
|
|
E(
|
|
'div',
|
|
{ id: 'dashboard-widget-service-info' },
|
|
renderWidget({
|
|
loading: true,
|
|
failed: false,
|
|
title: '',
|
|
items: [],
|
|
}),
|
|
),
|
|
E(
|
|
'div',
|
|
{ id: 'dashboard-widget-tailscale' },
|
|
renderWidget({
|
|
loading: true,
|
|
failed: false,
|
|
title: '',
|
|
items: [],
|
|
}),
|
|
),
|
|
]),
|
|
E('div', { id: 'dashboard-connections-grid' }, []),
|
|
E(
|
|
'div',
|
|
{ id: 'dashboard-sections-grid' },
|
|
renderSections({
|
|
loading: true,
|
|
failed: false,
|
|
section: {
|
|
code: '',
|
|
sectionName: '',
|
|
displayName: '',
|
|
outbounds: [],
|
|
withTagSelect: false,
|
|
},
|
|
onTestLatency: () => {},
|
|
onChooseOutbound: () => {},
|
|
onCopyOutbound: () => {},
|
|
onShowUrlTestInfo: () => {},
|
|
onShowPriorityInfo: () => {},
|
|
onUpdateSubscription: () => {},
|
|
latencyFetching: false,
|
|
latencyProgress: undefined,
|
|
subscriptionUpdating: false,
|
|
selectorSwitchingTag: undefined,
|
|
}),
|
|
),
|
|
]),
|
|
],
|
|
);
|
|
}
|