feat: implement some diagnostics widget

This commit is contained in:
divocat
2025-10-14 20:17:19 +03:00
parent d39ee3a666
commit dbf7e39599
15 changed files with 713 additions and 139 deletions

View File

@@ -431,7 +431,13 @@ export async function initDashboardController(): Promise<void> {
// Remove old listener
store.unsubscribe(onStoreUpdate);
// Clear store
store.reset();
store.reset([
'bandwidthWidget',
'trafficTotalWidget',
'systemInfoWidget',
'servicesInfoWidget',
'sectionsWidget',
]);
// Add new listener
store.subscribe(onStoreUpdate);

View File

@@ -0,0 +1,32 @@
export enum DIAGNOSTICS_CHECKS {
DNS = 'DNS',
SINGBOX = 'SINGBOX',
NFT = 'NFT',
FAKEIP = 'FAKEIP',
}
export const DIAGNOSTICS_CHECKS_MAP: Record<
DIAGNOSTICS_CHECKS,
{ order: number; title: string; code: DIAGNOSTICS_CHECKS }
> = {
[DIAGNOSTICS_CHECKS.DNS]: {
order: 1,
title: _('DNS checks'),
code: DIAGNOSTICS_CHECKS.DNS,
},
[DIAGNOSTICS_CHECKS.SINGBOX]: {
order: 2,
title: _('Sing-box checks'),
code: DIAGNOSTICS_CHECKS.SINGBOX,
},
[DIAGNOSTICS_CHECKS.NFT]: {
order: 3,
title: _('Nftables checks'),
code: DIAGNOSTICS_CHECKS.NFT,
},
[DIAGNOSTICS_CHECKS.FAKEIP]: {
order: 4,
title: _('FakeIP checks'),
code: DIAGNOSTICS_CHECKS.FAKEIP,
},
};

View File

@@ -2,13 +2,15 @@ import { getDNSCheck } from '../../../methods';
import { updateDiagnosticsCheck } from '../updateDiagnosticsCheck';
import { insertIf } from '../../../../helpers';
import { IDiagnosticsChecksItem } from '../../../../store';
import { DIAGNOSTICS_CHECKS_MAP } from './contstants';
export async function runDnsCheck() {
const code = 'dns_check';
const { order, title, code } = DIAGNOSTICS_CHECKS_MAP.DNS;
updateDiagnosticsCheck({
order,
code,
title: _('DNS checks'),
title,
description: _('Checking dns, please wait'),
state: 'loading',
items: [],
@@ -18,8 +20,9 @@ export async function runDnsCheck() {
if (!dnsChecks.success) {
updateDiagnosticsCheck({
order,
code,
title: _('DNS checks'),
title,
description: _('Cannot receive DNS checks result'),
state: 'error',
items: [],
@@ -55,8 +58,9 @@ export async function runDnsCheck() {
}
updateDiagnosticsCheck({
order,
code,
title: _('DNS checks'),
title,
description: _('DNS checks passed'),
state: getStatus(),
items: [

View File

@@ -3,13 +3,15 @@ import * as fakeIPMethods from '../../../../fakeip/methods';
import { updateDiagnosticsCheck } from '../updateDiagnosticsCheck';
import { insertIf } from '../../../../helpers';
import { IDiagnosticsChecksItem } from '../../../../store';
import { DIAGNOSTICS_CHECKS_MAP } from './contstants';
export async function runFakeIPCheck() {
const code = 'fake_ip_check';
const { order, title, code } = DIAGNOSTICS_CHECKS_MAP.FAKEIP;
updateDiagnosticsCheck({
order,
code,
title: _('FakeIP checks'),
title,
description: _('Checking FakeIP, please wait'),
state: 'loading',
items: [],
@@ -68,8 +70,9 @@ export async function runFakeIPCheck() {
const { state, description } = getMeta();
updateDiagnosticsCheck({
order,
code,
title: _('FakeIP checks'),
title,
description,
state,
items: [

View File

@@ -1,13 +1,15 @@
import { getNftRulesCheck } from '../../../methods';
import { updateDiagnosticsCheck } from '../updateDiagnosticsCheck';
import { getFakeIpCheck, getIpCheck } from '../../../../fakeip';
import { DIAGNOSTICS_CHECKS_MAP } from './contstants';
export async function runNftCheck() {
const code = 'nft_check';
const { order, title, code } = DIAGNOSTICS_CHECKS_MAP.NFT;
updateDiagnosticsCheck({
order,
code,
title: _('Nftables checks'),
title,
description: _('Checking nftables, please wait'),
state: 'loading',
items: [],
@@ -20,8 +22,9 @@ export async function runNftCheck() {
if (!nftablesChecks.success) {
updateDiagnosticsCheck({
order,
code,
title: _('Nftables checks'),
title,
description: _('Cannot receive nftables checks result'),
state: 'error',
items: [],
@@ -67,8 +70,9 @@ export async function runNftCheck() {
}
updateDiagnosticsCheck({
order,
code,
title: _('Nftables checks'),
title,
description: allGood
? _('Nftables checks passed')
: _('Nftables checks partially passed'),

View File

@@ -1,12 +1,14 @@
import { getSingBoxCheck } from '../../../methods';
import { updateDiagnosticsCheck } from '../updateDiagnosticsCheck';
import { DIAGNOSTICS_CHECKS_MAP } from './contstants';
export async function runSingBoxCheck() {
const code = 'sing_box_check';
const { order, title, code } = DIAGNOSTICS_CHECKS_MAP.SINGBOX;
updateDiagnosticsCheck({
order,
code,
title: _('Sing-box checks'),
title,
description: _('Checking sing-box, please wait'),
state: 'loading',
items: [],
@@ -16,8 +18,9 @@ export async function runSingBoxCheck() {
if (!singBoxChecks.success) {
updateDiagnosticsCheck({
order,
code,
title: _('Sing-box checks'),
title,
description: _('Cannot receive Sing-box checks result'),
state: 'error',
items: [],
@@ -59,8 +62,9 @@ export async function runSingBoxCheck() {
}
updateDiagnosticsCheck({
order,
code,
title: _('Sing-box checks'),
title,
description: _('Sing-box checks passed'),
state: getStatus(),
items: [

View File

@@ -0,0 +1,86 @@
import {
DIAGNOSTICS_CHECKS,
DIAGNOSTICS_CHECKS_MAP,
} from './checks/contstants';
import { StoreType } from '../../../store';
export const initialDiagnosticStore: Pick<
StoreType,
'diagnosticsChecks' | 'diagnosticsRunAction'
> = {
diagnosticsRunAction: { loading: false },
diagnosticsChecks: [
{
code: DIAGNOSTICS_CHECKS.DNS,
title: DIAGNOSTICS_CHECKS_MAP.DNS.title,
order: DIAGNOSTICS_CHECKS_MAP.DNS.order,
description: _('Not running'),
items: [],
state: 'skipped',
},
{
code: DIAGNOSTICS_CHECKS.SINGBOX,
title: DIAGNOSTICS_CHECKS_MAP.SINGBOX.title,
order: DIAGNOSTICS_CHECKS_MAP.SINGBOX.order,
description: _('Not running'),
items: [],
state: 'skipped',
},
{
code: DIAGNOSTICS_CHECKS.NFT,
title: DIAGNOSTICS_CHECKS_MAP.NFT.title,
order: DIAGNOSTICS_CHECKS_MAP.NFT.order,
description: _('Not running'),
items: [],
state: 'skipped',
},
{
code: DIAGNOSTICS_CHECKS.FAKEIP,
title: DIAGNOSTICS_CHECKS_MAP.FAKEIP.title,
order: DIAGNOSTICS_CHECKS_MAP.FAKEIP.order,
description: _('Not running'),
items: [],
state: 'skipped',
},
],
};
export const loadingDiagnosticsChecksStore: Pick<
StoreType,
'diagnosticsChecks'
> = {
diagnosticsChecks: [
{
code: DIAGNOSTICS_CHECKS.DNS,
title: DIAGNOSTICS_CHECKS_MAP.DNS.title,
order: DIAGNOSTICS_CHECKS_MAP.DNS.order,
description: _('Queued'),
items: [],
state: 'skipped',
},
{
code: DIAGNOSTICS_CHECKS.SINGBOX,
title: DIAGNOSTICS_CHECKS_MAP.SINGBOX.title,
order: DIAGNOSTICS_CHECKS_MAP.SINGBOX.order,
description: _('Queued'),
items: [],
state: 'skipped',
},
{
code: DIAGNOSTICS_CHECKS.NFT,
title: DIAGNOSTICS_CHECKS_MAP.NFT.title,
order: DIAGNOSTICS_CHECKS_MAP.NFT.order,
description: _('Queued'),
items: [],
state: 'skipped',
},
{
code: DIAGNOSTICS_CHECKS.FAKEIP,
title: DIAGNOSTICS_CHECKS_MAP.FAKEIP.title,
order: DIAGNOSTICS_CHECKS_MAP.FAKEIP.order,
description: _('Queued'),
items: [],
state: 'skipped',
},
],
};

View File

@@ -5,10 +5,16 @@ import { runDnsCheck } from './checks/runDnsCheck';
import { runSingBoxCheck } from './checks/runSingBoxCheck';
import { runNftCheck } from './checks/runNftCheck';
import { runFakeIPCheck } from './checks/runFakeIPCheck';
import { renderDiagnosticRunAction } from './renderDiagnosticRunAction';
import { renderAvailableActions } from './renderAvailableActions';
import { renderSystemInfo } from './renderSystemInfo';
import { loadingDiagnosticsChecksStore } from './diagnostic.store';
async function renderDiagnosticsChecks() {
function renderDiagnosticsChecks() {
console.log('renderDiagnosticsChecks');
const diagnosticsChecks = store.get().diagnosticsChecks;
const diagnosticsChecks = store
.get()
.diagnosticsChecks.sort((a, b) => a.order - b.order);
const container = document.getElementById('pdk_diagnostic-page-checks');
const renderedDiagnosticsChecks = diagnosticsChecks.map((check) =>
@@ -20,6 +26,69 @@ async function renderDiagnosticsChecks() {
});
}
function renderDiagnosticRunActionWidget() {
console.log('renderDiagnosticRunActionWidget');
const { loading } = store.get().diagnosticsRunAction;
const container = document.getElementById('pdk_diagnostic-page-run-check');
const renderedAction = renderDiagnosticRunAction({
loading,
click: () => runChecks(),
});
return preserveScrollForPage(() => {
container!.replaceChildren(renderedAction);
});
}
function renderDiagnosticAvailableActionsWidget() {
console.log('renderDiagnosticActionsWidget');
const container = document.getElementById('pdk_diagnostic-page-actions');
const renderedActions = renderAvailableActions();
return preserveScrollForPage(() => {
container!.replaceChildren(renderedActions);
});
}
function renderDiagnosticSystemInfoWidget() {
console.log('renderDiagnosticSystemInfoWidget');
const container = document.getElementById('pdk_diagnostic-page-system-info');
const renderedSystemInfo = renderSystemInfo({
items: [
{
key: 'Podkop',
value: '1',
},
{
key: 'Luci App',
value: '1',
},
{
key: 'Sing-box',
value: '1',
},
{
key: 'OS',
value: '1',
},
{
key: 'Device',
value: '1',
},
],
});
return preserveScrollForPage(() => {
container!.replaceChildren(renderedSystemInfo);
});
}
async function onStoreUpdate(
next: StoreType,
prev: StoreType,
@@ -28,16 +97,31 @@ async function onStoreUpdate(
if (diff.diagnosticsChecks) {
renderDiagnosticsChecks();
}
if (diff.diagnosticsRunAction) {
renderDiagnosticRunActionWidget();
}
}
async function runChecks() {
await runDnsCheck();
try {
store.set({
diagnosticsRunAction: { loading: true },
diagnosticsChecks: loadingDiagnosticsChecksStore.diagnosticsChecks,
});
await runSingBoxCheck();
await runDnsCheck();
await runNftCheck();
await runSingBoxCheck();
await runFakeIPCheck();
await runNftCheck();
await runFakeIPCheck();
} catch (e) {
console.log('runChecks - e', e);
} finally {
store.set({ diagnosticsRunAction: { loading: false } });
}
}
export async function initDiagnosticController(): Promise<void> {
@@ -46,13 +130,19 @@ export async function initDiagnosticController(): Promise<void> {
// Remove old listener
store.unsubscribe(onStoreUpdate);
// Clear store
store.reset();
// Add new listener
store.subscribe(onStoreUpdate);
// TMP run checks on mount
runChecks();
// Initial checks render
renderDiagnosticsChecks();
// Initial run checks action render
renderDiagnosticRunActionWidget();
// Initial available actions render
renderDiagnosticAvailableActionsWidget();
// Initial system info render
renderDiagnosticSystemInfoWidget();
});
}

View File

@@ -0,0 +1,11 @@
export function renderAvailableActions() {
return E('div', { class: 'pdk_diagnostic-page__right-bar__actions' }, [
E('b', {}, 'Available actions'),
E('button', { class: 'btn' }, 'Restart podkop'),
E('button', { class: 'btn' }, 'Stop podkop'),
E('button', { class: 'btn' }, 'Disable podkop'),
E('button', { class: 'btn' }, 'Get global check'),
E('button', { class: 'btn' }, 'View logs'),
E('button', { class: 'btn' }, 'Show sing-box config'),
]);
}

View File

@@ -1,45 +1,15 @@
export function renderDiagnostic() {
return E(
'div',
{ id: 'diagnostic-status', class: 'pdk_diagnostic-page' },
E(
'div',
{
return E('div', { id: 'diagnostic-status', class: 'pdk_diagnostic-page' }, [
E('div', { class: 'pdk_diagnostic-page__left-bar' }, [
E('div', { id: 'pdk_diagnostic-page-run-check' }),
E('div', {
class: 'pdk_diagnostic-page__checks',
id: 'pdk_diagnostic-page-checks',
},
// [
// renderCheckSection({
// state: 'loading',
// title: _('DNS Checks'),
// description: _('Checking, please wait'),
// items: [],
// }),
// renderCheckSection({
// state: 'warning',
// title: _('DNS Checks'),
// description: _('Some checks was failed'),
// items: [],
// }),
// renderCheckSection({
// state: 'error',
// title: _('DNS Checks'),
// description: _('Checks was failed'),
// items: [],
// }),
// renderCheckSection({
// state: 'success',
// title: _('DNS Checks'),
// description: _('Checks was passed'),
// items: [],
// }),
// renderCheckSection({
// state: 'skipped',
// title: _('DNS Checks'),
// description: _('Checks was skipped'),
// items: [],
// }),
// ],
),
);
}),
]),
E('div', { class: 'pdk_diagnostic-page__right-bar' }, [
E('div', { id: 'pdk_diagnostic-page-actions' }),
E('div', { id: 'pdk_diagnostic-page-system-info' }),
]),
]);
}

View File

@@ -0,0 +1,17 @@
interface IRenderDiagnosticRunActionProps {
loading: boolean;
click: () => void;
}
export function renderDiagnosticRunAction({
loading,
click,
}: IRenderDiagnosticRunActionProps) {
return E('div', { class: 'pdk_diagnostic-page__run_check_wrapper' }, [
E(
'button',
{ class: 'btn', disabled: loading ? true : undefined, click },
loading ? _('Running... please wait') : _('Run Diagnostic'),
),
]);
}

View File

@@ -0,0 +1,19 @@
interface IRenderSystemInfoProps {
items: Array<{ key: string; value: string }>;
}
export function renderSystemInfo({ items }: IRenderSystemInfoProps) {
return E('div', { class: 'pdk_diagnostic-page__right-bar__system-info' }, [
E(
'b',
{ class: 'pdk_diagnostic-page__right-bar__system-info__title' },
'System information',
),
...items.map((item) =>
E('div', { class: 'pdk_diagnostic-page__right-bar__system-info__row' }, [
E('b', {}, item.key),
E('div', {}, item.value),
]),
),
]);
}

View File

@@ -1,4 +1,5 @@
import { Podkop } from './podkop/types';
import { initialDiagnosticStore } from './podkop/tabs/diagnostic/diagnostic.store';
function jsonStableStringify<T, V>(obj: T): string {
return JSON.stringify(obj, (_, value) => {
@@ -61,9 +62,17 @@ class Store<T extends Record<string, any>> {
this.listeners.forEach((cb) => cb(this.value, prev, diff));
}
reset(): void {
reset<K extends keyof T>(keys?: K[]): void {
const prev = this.value;
const next = structuredClone(this.initial);
const next = structuredClone(this.value);
if (keys && keys.length > 0) {
keys.forEach((key) => {
next[key] = structuredClone(this.initial[key]);
});
} else {
Object.assign(next, structuredClone(this.initial));
}
if (jsonEqual(prev, next)) return;
@@ -119,6 +128,7 @@ export interface IDiagnosticsChecksItem {
}
export interface IDiagnosticsChecksStoreItem {
order: number;
code: string;
title: string;
description: string;
@@ -157,6 +167,9 @@ export interface StoreType {
data: Podkop.OutboundGroup[];
latencyFetching: boolean;
};
diagnosticsRunAction: {
loading: boolean;
};
diagnosticsChecks: Array<IDiagnosticsChecksStoreItem>;
}
@@ -191,7 +204,7 @@ const initialStore: StoreType = {
latencyFetching: false,
data: [],
},
diagnosticsChecks: [],
...initialDiagnosticStore,
};
export const store = new Store<StoreType>(initialStore);

View File

@@ -213,6 +213,62 @@ export const GlobalStyles = `
width: 100%;
}
.pdk_diagnostic-page {
display: grid;
grid-template-columns: 2fr 1fr;
grid-column-gap: 10px;
align-items: start;
}
.pdk_diagnostic-page__right-bar {
display: grid;
grid-template-columns: 1fr;
grid-row-gap: 10px;
}
.pdk_diagnostic-page__right-bar__actions {
border: 2px var(--background-color-low, lightgray) solid;
border-radius: 4px;
padding: 10px;
display: grid;
grid-template-columns: auto;
grid-row-gap: 10px;
}
.pdk_diagnostic-page__right-bar__system-info {
border: 2px var(--background-color-low, lightgray) solid;
border-radius: 4px;
padding: 10px;
display: grid;
grid-template-columns: auto;
grid-row-gap: 10px;
}
.pdk_diagnostic-page__right-bar__system-info__title {
}
.pdk_diagnostic-page__right-bar__system-info__row {
display: grid;
grid-template-columns: auto 1fr;
grid-column-gap: 5px;
}
.pdk_diagnostic-page__left-bar {
display: grid;
grid-template-columns: 1fr;
grid-row-gap: 10px;
}
.pdk_diagnostic-page__run_check_wrapper {}
.pdk_diagnostic-page__run_check_wrapper button {
width: 100%;
}
.pdk_diagnostic-page__checks {
display: grid;
grid-template-columns: 1fr;

View File

@@ -436,6 +436,62 @@ var GlobalStyles = `
width: 100%;
}
.pdk_diagnostic-page {
display: grid;
grid-template-columns: 2fr 1fr;
grid-column-gap: 10px;
align-items: start;
}
.pdk_diagnostic-page__right-bar {
display: grid;
grid-template-columns: 1fr;
grid-row-gap: 10px;
}
.pdk_diagnostic-page__right-bar__actions {
border: 2px var(--background-color-low, lightgray) solid;
border-radius: 4px;
padding: 10px;
display: grid;
grid-template-columns: auto;
grid-row-gap: 10px;
}
.pdk_diagnostic-page__right-bar__system-info {
border: 2px var(--background-color-low, lightgray) solid;
border-radius: 4px;
padding: 10px;
display: grid;
grid-template-columns: auto;
grid-row-gap: 10px;
}
.pdk_diagnostic-page__right-bar__system-info__title {
}
.pdk_diagnostic-page__right-bar__system-info__row {
display: grid;
grid-template-columns: auto 1fr;
grid-column-gap: 5px;
}
.pdk_diagnostic-page__left-bar {
display: grid;
grid-template-columns: 1fr;
grid-row-gap: 10px;
}
.pdk_diagnostic-page__run_check_wrapper {}
.pdk_diagnostic-page__run_check_wrapper button {
width: 100%;
}
.pdk_diagnostic-page__checks {
display: grid;
grid-template-columns: 1fr;
@@ -1354,6 +1410,105 @@ var TabService = class _TabService {
};
var TabServiceInstance = TabService.getInstance();
// src/podkop/tabs/diagnostic/checks/contstants.ts
var DIAGNOSTICS_CHECKS_MAP = {
["DNS" /* DNS */]: {
order: 1,
title: _("DNS checks"),
code: "DNS" /* DNS */
},
["SINGBOX" /* SINGBOX */]: {
order: 2,
title: _("Sing-box checks"),
code: "SINGBOX" /* SINGBOX */
},
["NFT" /* NFT */]: {
order: 3,
title: _("Nftables checks"),
code: "NFT" /* NFT */
},
["FAKEIP" /* FAKEIP */]: {
order: 4,
title: _("FakeIP checks"),
code: "FAKEIP" /* FAKEIP */
}
};
// src/podkop/tabs/diagnostic/diagnostic.store.ts
var initialDiagnosticStore = {
diagnosticsRunAction: { loading: false },
diagnosticsChecks: [
{
code: "DNS" /* DNS */,
title: DIAGNOSTICS_CHECKS_MAP.DNS.title,
order: DIAGNOSTICS_CHECKS_MAP.DNS.order,
description: _("Not running"),
items: [],
state: "skipped"
},
{
code: "SINGBOX" /* SINGBOX */,
title: DIAGNOSTICS_CHECKS_MAP.SINGBOX.title,
order: DIAGNOSTICS_CHECKS_MAP.SINGBOX.order,
description: _("Not running"),
items: [],
state: "skipped"
},
{
code: "NFT" /* NFT */,
title: DIAGNOSTICS_CHECKS_MAP.NFT.title,
order: DIAGNOSTICS_CHECKS_MAP.NFT.order,
description: _("Not running"),
items: [],
state: "skipped"
},
{
code: "FAKEIP" /* FAKEIP */,
title: DIAGNOSTICS_CHECKS_MAP.FAKEIP.title,
order: DIAGNOSTICS_CHECKS_MAP.FAKEIP.order,
description: _("Not running"),
items: [],
state: "skipped"
}
]
};
var loadingDiagnosticsChecksStore = {
diagnosticsChecks: [
{
code: "DNS" /* DNS */,
title: DIAGNOSTICS_CHECKS_MAP.DNS.title,
order: DIAGNOSTICS_CHECKS_MAP.DNS.order,
description: _("Queued"),
items: [],
state: "skipped"
},
{
code: "SINGBOX" /* SINGBOX */,
title: DIAGNOSTICS_CHECKS_MAP.SINGBOX.title,
order: DIAGNOSTICS_CHECKS_MAP.SINGBOX.order,
description: _("Queued"),
items: [],
state: "skipped"
},
{
code: "NFT" /* NFT */,
title: DIAGNOSTICS_CHECKS_MAP.NFT.title,
order: DIAGNOSTICS_CHECKS_MAP.NFT.order,
description: _("Queued"),
items: [],
state: "skipped"
},
{
code: "FAKEIP" /* FAKEIP */,
title: DIAGNOSTICS_CHECKS_MAP.FAKEIP.title,
order: DIAGNOSTICS_CHECKS_MAP.FAKEIP.order,
description: _("Queued"),
items: [],
state: "skipped"
}
]
};
// src/store.ts
function jsonStableStringify(obj) {
return JSON.stringify(obj, (_2, value) => {
@@ -1399,9 +1554,16 @@ var Store = class {
}
this.listeners.forEach((cb) => cb(this.value, prev, diff));
}
reset() {
reset(keys) {
const prev = this.value;
const next = structuredClone(this.initial);
const next = structuredClone(this.value);
if (keys && keys.length > 0) {
keys.forEach((key) => {
next[key] = structuredClone(this.initial[key]);
});
} else {
Object.assign(next, structuredClone(this.initial));
}
if (jsonEqual(prev, next)) return;
this.value = next;
this.lastHash = jsonStableStringify(next);
@@ -1468,7 +1630,7 @@ var initialStore = {
latencyFetching: false,
data: []
},
diagnosticsChecks: []
...initialDiagnosticStore
};
var store = new Store(initialStore);
@@ -2163,7 +2325,13 @@ async function onStoreUpdate(next, prev, diff) {
async function initDashboardController() {
onMount("dashboard-status").then(() => {
store.unsubscribe(onStoreUpdate);
store.reset();
store.reset([
"bandwidthWidget",
"trafficTotalWidget",
"systemInfoWidget",
"servicesInfoWidget",
"sectionsWidget"
]);
store.subscribe(onStoreUpdate);
fetchDashboardSections();
fetchServicesInfo();
@@ -2173,49 +2341,19 @@ async function initDashboardController() {
// src/podkop/tabs/diagnostic/renderDiagnostic.ts
function renderDiagnostic() {
return E(
"div",
{ id: "diagnostic-status", class: "pdk_diagnostic-page" },
E(
"div",
{
return E("div", { id: "diagnostic-status", class: "pdk_diagnostic-page" }, [
E("div", { class: "pdk_diagnostic-page__left-bar" }, [
E("div", { id: "pdk_diagnostic-page-run-check" }),
E("div", {
class: "pdk_diagnostic-page__checks",
id: "pdk_diagnostic-page-checks"
}
// [
// renderCheckSection({
// state: 'loading',
// title: _('DNS Checks'),
// description: _('Checking, please wait'),
// items: [],
// }),
// renderCheckSection({
// state: 'warning',
// title: _('DNS Checks'),
// description: _('Some checks was failed'),
// items: [],
// }),
// renderCheckSection({
// state: 'error',
// title: _('DNS Checks'),
// description: _('Checks was failed'),
// items: [],
// }),
// renderCheckSection({
// state: 'success',
// title: _('DNS Checks'),
// description: _('Checks was passed'),
// items: [],
// }),
// renderCheckSection({
// state: 'skipped',
// title: _('DNS Checks'),
// description: _('Checks was skipped'),
// items: [],
// }),
// ],
)
);
})
]),
E("div", { class: "pdk_diagnostic-page__right-bar" }, [
E("div", { id: "pdk_diagnostic-page-actions" }),
E("div", { id: "pdk_diagnostic-page-system-info" })
])
]);
}
// src/icons/renderLoaderCircleIcon24.ts
@@ -2625,10 +2763,11 @@ function updateDiagnosticsCheck(check, minified) {
// src/podkop/tabs/diagnostic/checks/runDnsCheck.ts
async function runDnsCheck() {
const code = "dns_check";
const { order, title, code } = DIAGNOSTICS_CHECKS_MAP.DNS;
updateDiagnosticsCheck({
order,
code,
title: _("DNS checks"),
title,
description: _("Checking dns, please wait"),
state: "loading",
items: []
@@ -2636,8 +2775,9 @@ async function runDnsCheck() {
const dnsChecks = await getDNSCheck();
if (!dnsChecks.success) {
updateDiagnosticsCheck({
order,
code,
title: _("DNS checks"),
title,
description: _("Cannot receive DNS checks result"),
state: "error",
items: []
@@ -2658,8 +2798,9 @@ async function runDnsCheck() {
return "error";
}
updateDiagnosticsCheck({
order,
code,
title: _("DNS checks"),
title,
description: _("DNS checks passed"),
state: getStatus(),
items: [
@@ -2692,10 +2833,11 @@ async function runDnsCheck() {
// src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts
async function runSingBoxCheck() {
const code = "sing_box_check";
const { order, title, code } = DIAGNOSTICS_CHECKS_MAP.SINGBOX;
updateDiagnosticsCheck({
order,
code,
title: _("Sing-box checks"),
title,
description: _("Checking sing-box, please wait"),
state: "loading",
items: []
@@ -2703,8 +2845,9 @@ async function runSingBoxCheck() {
const singBoxChecks = await getSingBoxCheck();
if (!singBoxChecks.success) {
updateDiagnosticsCheck({
order,
code,
title: _("Sing-box checks"),
title,
description: _("Cannot receive Sing-box checks result"),
state: "error",
items: []
@@ -2725,8 +2868,9 @@ async function runSingBoxCheck() {
return "error";
}
updateDiagnosticsCheck({
order,
code,
title: _("Sing-box checks"),
title,
description: _("Sing-box checks passed"),
state: getStatus(),
items: [
@@ -2797,10 +2941,11 @@ async function getFakeIpCheck() {
// src/podkop/tabs/diagnostic/checks/runNftCheck.ts
async function runNftCheck() {
const code = "nft_check";
const { order, title, code } = DIAGNOSTICS_CHECKS_MAP.NFT;
updateDiagnosticsCheck({
order,
code,
title: _("Nftables checks"),
title,
description: _("Checking nftables, please wait"),
state: "loading",
items: []
@@ -2810,8 +2955,9 @@ async function runNftCheck() {
const nftablesChecks = await getNftRulesCheck();
if (!nftablesChecks.success) {
updateDiagnosticsCheck({
order,
code,
title: _("Nftables checks"),
title,
description: _("Cannot receive nftables checks result"),
state: "error",
items: []
@@ -2832,8 +2978,9 @@ async function runNftCheck() {
return "error";
}
updateDiagnosticsCheck({
order,
code,
title: _("Nftables checks"),
title,
description: allGood ? _("Nftables checks passed") : _("Nftables checks partially passed"),
state: getStatus(),
items: [
@@ -2886,10 +3033,11 @@ async function runNftCheck() {
// src/podkop/tabs/diagnostic/checks/runFakeIPCheck.ts
async function runFakeIPCheck() {
const code = "fake_ip_check";
const { order, title, code } = DIAGNOSTICS_CHECKS_MAP.FAKEIP;
updateDiagnosticsCheck({
order,
code,
title: _("FakeIP checks"),
title,
description: _("Checking FakeIP, please wait"),
state: "loading",
items: []
@@ -2930,8 +3078,9 @@ async function runFakeIPCheck() {
}
const { state, description } = getMeta();
updateDiagnosticsCheck({
order,
code,
title: _("FakeIP checks"),
title,
description,
state,
items: [
@@ -2956,10 +3105,54 @@ async function runFakeIPCheck() {
});
}
// src/podkop/tabs/diagnostic/renderDiagnosticRunAction.ts
function renderDiagnosticRunAction({
loading,
click
}) {
return E("div", { class: "pdk_diagnostic-page__run_check_wrapper" }, [
E(
"button",
{ class: "btn", disabled: loading ? true : void 0, click },
loading ? _("Running... please wait") : _("Run Diagnostic")
)
]);
}
// src/podkop/tabs/diagnostic/renderAvailableActions.ts
function renderAvailableActions() {
return E("div", { class: "pdk_diagnostic-page__right-bar__actions" }, [
E("b", {}, "Available actions"),
E("button", { class: "btn" }, "Restart podkop"),
E("button", { class: "btn" }, "Stop podkop"),
E("button", { class: "btn" }, "Disable podkop"),
E("button", { class: "btn" }, "Get global check"),
E("button", { class: "btn" }, "View logs"),
E("button", { class: "btn" }, "Show sing-box config")
]);
}
// src/podkop/tabs/diagnostic/renderSystemInfo.ts
function renderSystemInfo({ items }) {
return E("div", { class: "pdk_diagnostic-page__right-bar__system-info" }, [
E(
"b",
{ class: "pdk_diagnostic-page__right-bar__system-info__title" },
"System information"
),
...items.map(
(item) => E("div", { class: "pdk_diagnostic-page__right-bar__system-info__row" }, [
E("b", {}, item.key),
E("div", {}, item.value)
])
)
]);
}
// src/podkop/tabs/diagnostic/initDiagnosticController.ts
async function renderDiagnosticsChecks() {
function renderDiagnosticsChecks() {
console.log("renderDiagnosticsChecks");
const diagnosticsChecks = store.get().diagnosticsChecks;
const diagnosticsChecks = store.get().diagnosticsChecks.sort((a, b) => a.order - b.order);
const container = document.getElementById("pdk_diagnostic-page-checks");
const renderedDiagnosticsChecks = diagnosticsChecks.map(
(check) => renderCheckSection(check)
@@ -2968,24 +3161,90 @@ async function renderDiagnosticsChecks() {
container.replaceChildren(...renderedDiagnosticsChecks);
});
}
function renderDiagnosticRunActionWidget() {
console.log("renderDiagnosticRunActionWidget");
const { loading } = store.get().diagnosticsRunAction;
const container = document.getElementById("pdk_diagnostic-page-run-check");
const renderedAction = renderDiagnosticRunAction({
loading,
click: () => runChecks()
});
return preserveScrollForPage(() => {
container.replaceChildren(renderedAction);
});
}
function renderDiagnosticAvailableActionsWidget() {
console.log("renderDiagnosticActionsWidget");
const container = document.getElementById("pdk_diagnostic-page-actions");
const renderedActions = renderAvailableActions();
return preserveScrollForPage(() => {
container.replaceChildren(renderedActions);
});
}
function renderDiagnosticSystemInfoWidget() {
console.log("renderDiagnosticSystemInfoWidget");
const container = document.getElementById("pdk_diagnostic-page-system-info");
const renderedSystemInfo = renderSystemInfo({
items: [
{
key: "Podkop",
value: "1"
},
{
key: "Luci App",
value: "1"
},
{
key: "Sing-box",
value: "1"
},
{
key: "OS",
value: "1"
},
{
key: "Device",
value: "1"
}
]
});
return preserveScrollForPage(() => {
container.replaceChildren(renderedSystemInfo);
});
}
async function onStoreUpdate2(next, prev, diff) {
if (diff.diagnosticsChecks) {
renderDiagnosticsChecks();
}
if (diff.diagnosticsRunAction) {
renderDiagnosticRunActionWidget();
}
}
async function runChecks() {
await runDnsCheck();
await runSingBoxCheck();
await runNftCheck();
await runFakeIPCheck();
try {
store.set({
diagnosticsRunAction: { loading: true },
diagnosticsChecks: loadingDiagnosticsChecksStore.diagnosticsChecks
});
await runDnsCheck();
await runSingBoxCheck();
await runNftCheck();
await runFakeIPCheck();
} catch (e) {
console.log("runChecks - e", e);
} finally {
store.set({ diagnosticsRunAction: { loading: false } });
}
}
async function initDiagnosticController() {
onMount("diagnostic-status").then(() => {
console.log("diagnostic controller initialized.");
store.unsubscribe(onStoreUpdate2);
store.reset();
store.subscribe(onStoreUpdate2);
runChecks();
renderDiagnosticsChecks();
renderDiagnosticRunActionWidget();
renderDiagnosticAvailableActionsWidget();
renderDiagnosticSystemInfoWidget();
});
}
return baseclass.extend({