mirror of
https://github.com/itdoginfo/podkop.git
synced 2026-01-31 14:50:58 +03:00
feat: implement base of diagnostics
This commit is contained in:
@@ -10,3 +10,4 @@ export * from './getClashApiUrl';
|
|||||||
export * from './splitProxyString';
|
export * from './splitProxyString';
|
||||||
export * from './preserveScrollForPage';
|
export * from './preserveScrollForPage';
|
||||||
export * from './parseQueryString';
|
export * from './parseQueryString';
|
||||||
|
export * from './svgEl';
|
||||||
|
|||||||
18
fe-app-podkop/src/helpers/svgEl.ts
Normal file
18
fe-app-podkop/src/helpers/svgEl.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
export function svgEl<K extends keyof SVGElementTagNameMap>(
|
||||||
|
tag: K,
|
||||||
|
attrs: Partial<Record<string, string | number>> = {},
|
||||||
|
children: (SVGElement | null | undefined)[] = [],
|
||||||
|
): SVGElementTagNameMap[K] {
|
||||||
|
const NS = 'http://www.w3.org/2000/svg';
|
||||||
|
const el = document.createElementNS(NS, tag);
|
||||||
|
|
||||||
|
for (const [k, v] of Object.entries(attrs)) {
|
||||||
|
if (v != null) el.setAttribute(k, String(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
(Array.isArray(children) ? children : [children])
|
||||||
|
.filter(Boolean)
|
||||||
|
.forEach((ch) => el.appendChild(ch as SVGElement));
|
||||||
|
|
||||||
|
return el;
|
||||||
|
}
|
||||||
5
fe-app-podkop/src/icons/index.ts
Normal file
5
fe-app-podkop/src/icons/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export * from './renderLoaderCircleIcon24';
|
||||||
|
export * from './renderShieldAlertIcon24';
|
||||||
|
export * from './renderShieldCheckIcon24';
|
||||||
|
export * from './renderShieldIcon24';
|
||||||
|
export * from './renderShieldXIcon24';
|
||||||
34
fe-app-podkop/src/icons/renderLoaderCircleIcon24.ts
Normal file
34
fe-app-podkop/src/icons/renderLoaderCircleIcon24.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { svgEl } from '../helpers';
|
||||||
|
|
||||||
|
export function renderLoaderCircleIcon24() {
|
||||||
|
const NS = 'http://www.w3.org/2000/svg';
|
||||||
|
return svgEl(
|
||||||
|
'svg',
|
||||||
|
{
|
||||||
|
xmlns: NS,
|
||||||
|
width: '24',
|
||||||
|
height: '24',
|
||||||
|
viewBox: '0 0 24 24',
|
||||||
|
fill: 'none',
|
||||||
|
stroke: 'currentColor',
|
||||||
|
'stroke-width': '2',
|
||||||
|
'stroke-linecap': 'round',
|
||||||
|
'stroke-linejoin': 'round',
|
||||||
|
class: 'lucide lucide-loader-circle lucide-rotate',
|
||||||
|
},
|
||||||
|
[
|
||||||
|
svgEl('path', {
|
||||||
|
d: 'M21 12a9 9 0 1 1-6.219-8.56',
|
||||||
|
}),
|
||||||
|
svgEl('animateTransform', {
|
||||||
|
attributeName: 'transform',
|
||||||
|
attributeType: 'XML',
|
||||||
|
type: 'rotate',
|
||||||
|
from: '0 12 12',
|
||||||
|
to: '360 12 12',
|
||||||
|
dur: '1s',
|
||||||
|
repeatCount: 'indefinite',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
27
fe-app-podkop/src/icons/renderShieldAlertIcon24.ts
Normal file
27
fe-app-podkop/src/icons/renderShieldAlertIcon24.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { svgEl } from '../helpers';
|
||||||
|
|
||||||
|
export function renderShieldAlertIcon24() {
|
||||||
|
const NS = 'http://www.w3.org/2000/svg';
|
||||||
|
return svgEl(
|
||||||
|
'svg',
|
||||||
|
{
|
||||||
|
xmlns: NS,
|
||||||
|
width: '24',
|
||||||
|
height: '24',
|
||||||
|
viewBox: '0 0 24 24',
|
||||||
|
fill: 'none',
|
||||||
|
stroke: 'currentColor',
|
||||||
|
'stroke-width': '2',
|
||||||
|
'stroke-linecap': 'round',
|
||||||
|
'stroke-linejoin': 'round',
|
||||||
|
class: 'lucide lucide-shield-alert',
|
||||||
|
},
|
||||||
|
[
|
||||||
|
svgEl('path', {
|
||||||
|
d: 'M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z',
|
||||||
|
}),
|
||||||
|
svgEl('path', { d: 'M12 8v4' }),
|
||||||
|
svgEl('path', { d: 'M12 16h.01' }),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
26
fe-app-podkop/src/icons/renderShieldCheckIcon24.ts
Normal file
26
fe-app-podkop/src/icons/renderShieldCheckIcon24.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { svgEl } from '../helpers';
|
||||||
|
|
||||||
|
export function renderShieldCheckIcon24() {
|
||||||
|
const NS = 'http://www.w3.org/2000/svg';
|
||||||
|
return svgEl(
|
||||||
|
'svg',
|
||||||
|
{
|
||||||
|
xmlns: NS,
|
||||||
|
width: '24',
|
||||||
|
height: '24',
|
||||||
|
viewBox: '0 0 24 24',
|
||||||
|
fill: 'none',
|
||||||
|
stroke: 'currentColor',
|
||||||
|
'stroke-width': '2',
|
||||||
|
'stroke-linecap': 'round',
|
||||||
|
'stroke-linejoin': 'round',
|
||||||
|
class: 'lucide lucide-shield-check',
|
||||||
|
},
|
||||||
|
[
|
||||||
|
svgEl('path', {
|
||||||
|
d: 'M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z',
|
||||||
|
}),
|
||||||
|
svgEl('path', { d: 'm9 12 2 2 4-4' }),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
25
fe-app-podkop/src/icons/renderShieldIcon24.ts
Normal file
25
fe-app-podkop/src/icons/renderShieldIcon24.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { svgEl } from '../helpers';
|
||||||
|
|
||||||
|
export function renderShieldIcon24() {
|
||||||
|
const NS = 'http://www.w3.org/2000/svg';
|
||||||
|
return svgEl(
|
||||||
|
'svg',
|
||||||
|
{
|
||||||
|
xmlns: NS,
|
||||||
|
width: '24',
|
||||||
|
height: '24',
|
||||||
|
viewBox: '0 0 24 24',
|
||||||
|
fill: 'none',
|
||||||
|
stroke: 'currentColor',
|
||||||
|
'stroke-width': '2',
|
||||||
|
'stroke-linecap': 'round',
|
||||||
|
'stroke-linejoin': 'round',
|
||||||
|
class: 'lucide lucide-shield',
|
||||||
|
},
|
||||||
|
[
|
||||||
|
svgEl('path', {
|
||||||
|
d: 'M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
27
fe-app-podkop/src/icons/renderShieldXIcon24.ts
Normal file
27
fe-app-podkop/src/icons/renderShieldXIcon24.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { svgEl } from '../helpers';
|
||||||
|
|
||||||
|
export function renderShieldXIcon24() {
|
||||||
|
const NS = 'http://www.w3.org/2000/svg';
|
||||||
|
return svgEl(
|
||||||
|
'svg',
|
||||||
|
{
|
||||||
|
xmlns: NS,
|
||||||
|
width: '24',
|
||||||
|
height: '24',
|
||||||
|
viewBox: '0 0 24 24',
|
||||||
|
fill: 'none',
|
||||||
|
stroke: 'currentColor',
|
||||||
|
'stroke-width': '2',
|
||||||
|
'stroke-linecap': 'round',
|
||||||
|
'stroke-linejoin': 'round',
|
||||||
|
class: 'lucide lucide-shield-x',
|
||||||
|
},
|
||||||
|
[
|
||||||
|
svgEl('path', {
|
||||||
|
d: 'M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z',
|
||||||
|
}),
|
||||||
|
svgEl('path', { d: 'm14.5 9.5-5 5' }),
|
||||||
|
svgEl('path', { d: 'm9.5 9.5 5 5' }),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import { getDNSCheck } from '../../../methods';
|
||||||
|
import { updateDiagnosticsCheck } from '../updateDiagnosticsCheck';
|
||||||
|
|
||||||
|
export async function runDnsCheck() {
|
||||||
|
const code = 'dns_check';
|
||||||
|
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _('DNS checks'),
|
||||||
|
description: _('Checking dns, please wait'),
|
||||||
|
state: 'loading',
|
||||||
|
items: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const dnsChecks = await getDNSCheck();
|
||||||
|
|
||||||
|
if (!dnsChecks.success) {
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _('DNS checks'),
|
||||||
|
description: _('Cannot receive DNS checks result'),
|
||||||
|
state: 'error',
|
||||||
|
items: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
throw new Error('DNS checks failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = dnsChecks.data;
|
||||||
|
|
||||||
|
const allGood =
|
||||||
|
Boolean(data.local_dns_status) &&
|
||||||
|
Boolean(data.bootstrap_dns_status) &&
|
||||||
|
Boolean(data.dns_status);
|
||||||
|
|
||||||
|
const atLeastOneGood =
|
||||||
|
Boolean(data.local_dns_status) ||
|
||||||
|
Boolean(data.bootstrap_dns_status) ||
|
||||||
|
Boolean(data.dns_status);
|
||||||
|
|
||||||
|
console.log('dnsChecks', dnsChecks);
|
||||||
|
|
||||||
|
function getStatus() {
|
||||||
|
if (allGood) {
|
||||||
|
return 'success';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atLeastOneGood) {
|
||||||
|
return 'warning';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _('DNS checks'),
|
||||||
|
description: _('DNS checks passed'),
|
||||||
|
state: getStatus(),
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
state: data.bootstrap_dns_status ? 'success' : 'error',
|
||||||
|
key: _('Bootsrap DNS'),
|
||||||
|
value: data.bootstrap_dns_server,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.dns_status ? 'success' : 'error',
|
||||||
|
key: _('Main DNS'),
|
||||||
|
value: `${data.dns_server} [${data.dns_type}]`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.local_dns_status ? 'success' : 'error',
|
||||||
|
key: _('Local DNS'),
|
||||||
|
value: data.local_dns_status ? _('Enabled') : _('Failed'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!atLeastOneGood) {
|
||||||
|
throw new Error('DNS checks failed');
|
||||||
|
}
|
||||||
|
}
|
||||||
119
fe-app-podkop/src/podkop/tabs/diagnostic/checks/runNftCheck.ts
Normal file
119
fe-app-podkop/src/podkop/tabs/diagnostic/checks/runNftCheck.ts
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
import { getNftRulesCheck } from '../../../methods';
|
||||||
|
import { updateDiagnosticsCheck } from '../updateDiagnosticsCheck';
|
||||||
|
|
||||||
|
export async function runNftCheck() {
|
||||||
|
const code = 'nft_check';
|
||||||
|
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _('Nftables checks'),
|
||||||
|
description: _('Checking nftables, please wait'),
|
||||||
|
state: 'loading',
|
||||||
|
items: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const nftablesChecks = await getNftRulesCheck();
|
||||||
|
|
||||||
|
if (!nftablesChecks.success) {
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _('Nftables checks'),
|
||||||
|
description: _('Cannot receive nftables checks result'),
|
||||||
|
state: 'error',
|
||||||
|
items: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
throw new Error('Nftables checks failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = nftablesChecks.data;
|
||||||
|
|
||||||
|
const allGood =
|
||||||
|
Boolean(data.table_exist) &&
|
||||||
|
Boolean(data.rules_mangle_exist) &&
|
||||||
|
Boolean(data.rules_mangle_counters) &&
|
||||||
|
Boolean(data.rules_mangle_output_exist) &&
|
||||||
|
Boolean(data.rules_mangle_output_counters) &&
|
||||||
|
Boolean(data.rules_proxy_exist) &&
|
||||||
|
Boolean(data.rules_proxy_counters) &&
|
||||||
|
Boolean(data.rules_other_mark_exist);
|
||||||
|
|
||||||
|
const atLeastOneGood =
|
||||||
|
Boolean(data.table_exist) ||
|
||||||
|
Boolean(data.rules_mangle_exist) ||
|
||||||
|
Boolean(data.rules_mangle_counters) ||
|
||||||
|
Boolean(data.rules_mangle_output_exist) ||
|
||||||
|
Boolean(data.rules_mangle_output_counters) ||
|
||||||
|
Boolean(data.rules_proxy_exist) ||
|
||||||
|
Boolean(data.rules_proxy_counters) ||
|
||||||
|
Boolean(data.rules_other_mark_exist);
|
||||||
|
|
||||||
|
console.log('nftablesChecks', nftablesChecks);
|
||||||
|
|
||||||
|
function getStatus() {
|
||||||
|
if (allGood) {
|
||||||
|
return 'success';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atLeastOneGood) {
|
||||||
|
return 'warning';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _('Nftables checks'),
|
||||||
|
description: allGood
|
||||||
|
? _('Nftables checks passed')
|
||||||
|
: _('Nftables checks partially passed'),
|
||||||
|
state: getStatus(),
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
state: data.table_exist ? 'success' : 'error',
|
||||||
|
key: _('Table exist'),
|
||||||
|
value: data.table_exist ? _('Yes') : _('No'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.rules_mangle_exist ? 'success' : 'error',
|
||||||
|
key: _('Rules mangle exist'),
|
||||||
|
value: data.rules_mangle_exist ? _('Yes') : _('No'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.rules_mangle_counters ? 'success' : 'error',
|
||||||
|
key: _('Rules mangle counters'),
|
||||||
|
value: data.rules_mangle_counters ? _('Yes') : _('No'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.rules_mangle_output_exist ? 'success' : 'error',
|
||||||
|
key: _('Rules mangle output exist'),
|
||||||
|
value: data.rules_mangle_output_exist ? _('Yes') : _('No'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.rules_mangle_output_counters ? 'success' : 'error',
|
||||||
|
key: _('Rules mangle output counters'),
|
||||||
|
value: data.rules_mangle_output_counters ? _('Yes') : _('No'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.rules_proxy_exist ? 'success' : 'error',
|
||||||
|
key: _('Rules proxy exist'),
|
||||||
|
value: data.rules_proxy_exist ? _('Yes') : _('No'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.rules_proxy_counters ? 'success' : 'error',
|
||||||
|
key: _('Rules proxy counters'),
|
||||||
|
value: data.rules_proxy_counters ? _('Yes') : _('No'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.rules_other_mark_exist ? 'warning' : 'success',
|
||||||
|
key: _('Rules other mark exist'),
|
||||||
|
value: data.rules_other_mark_exist ? _('Yes') : _('No'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!atLeastOneGood) {
|
||||||
|
throw new Error('Nftables checks failed');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
import { getSingBoxCheck } from '../../../methods';
|
||||||
|
import { updateDiagnosticsCheck } from '../updateDiagnosticsCheck';
|
||||||
|
|
||||||
|
export async function runSingBoxCheck() {
|
||||||
|
const code = 'sing_box_check';
|
||||||
|
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _('Sing-box checks'),
|
||||||
|
description: _('Checking sing-box, please wait'),
|
||||||
|
state: 'loading',
|
||||||
|
items: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const singBoxChecks = await getSingBoxCheck();
|
||||||
|
|
||||||
|
if (!singBoxChecks.success) {
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _('Sing-box checks'),
|
||||||
|
description: _('Cannot receive Sing-box checks result'),
|
||||||
|
state: 'error',
|
||||||
|
items: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
throw new Error('Sing-box checks failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = singBoxChecks.data;
|
||||||
|
|
||||||
|
const allGood =
|
||||||
|
Boolean(data.sing_box_installed) &&
|
||||||
|
Boolean(data.sing_box_version_ok) &&
|
||||||
|
Boolean(data.sing_box_service_exist) &&
|
||||||
|
Boolean(data.sing_box_autostart_disabled) &&
|
||||||
|
Boolean(data.sing_box_process_running) &&
|
||||||
|
Boolean(data.sing_box_ports_listening);
|
||||||
|
|
||||||
|
const atLeastOneGood =
|
||||||
|
Boolean(data.sing_box_installed) ||
|
||||||
|
Boolean(data.sing_box_version_ok) ||
|
||||||
|
Boolean(data.sing_box_service_exist) ||
|
||||||
|
Boolean(data.sing_box_autostart_disabled) ||
|
||||||
|
Boolean(data.sing_box_process_running) ||
|
||||||
|
Boolean(data.sing_box_ports_listening);
|
||||||
|
|
||||||
|
console.log('singBoxChecks', singBoxChecks);
|
||||||
|
|
||||||
|
function getStatus() {
|
||||||
|
if (allGood) {
|
||||||
|
return 'success';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atLeastOneGood) {
|
||||||
|
return 'warning';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _('Sing-box checks'),
|
||||||
|
description: _('Sing-box checks passed'),
|
||||||
|
state: getStatus(),
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
state: data.sing_box_installed ? 'success' : 'error',
|
||||||
|
key: _('Sing-box installed'),
|
||||||
|
value: data.sing_box_installed ? _('Yes') : _('No'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.sing_box_version_ok ? 'success' : 'error',
|
||||||
|
key: _('Sing-box version >= 1.12.4'),
|
||||||
|
value: data.sing_box_version_ok ? _('Yes') : _('No'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.sing_box_service_exist ? 'success' : 'error',
|
||||||
|
key: _('Sing-box service exist'),
|
||||||
|
value: data.sing_box_service_exist ? _('Yes') : _('No'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.sing_box_autostart_disabled ? 'success' : 'error',
|
||||||
|
key: _('Sing-box autostart disabled'),
|
||||||
|
value: data.sing_box_autostart_disabled ? _('Yes') : _('No'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.sing_box_process_running ? 'success' : 'error',
|
||||||
|
key: _('Sing-box process running'),
|
||||||
|
value: data.sing_box_process_running ? _('Yes') : _('No'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.sing_box_ports_listening ? 'success' : 'error',
|
||||||
|
key: _('Sing-box listening ports'),
|
||||||
|
value: data.sing_box_ports_listening ? _('Yes') : _('No'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!atLeastOneGood) {
|
||||||
|
throw new Error('Sing-box checks failed');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,55 @@
|
|||||||
import { onMount } from '../../../helpers';
|
import { onMount, preserveScrollForPage } from '../../../helpers';
|
||||||
|
import { store, StoreType } from '../../../store';
|
||||||
|
import { renderCheckSection } from './renderCheckSection';
|
||||||
|
import { runDnsCheck } from './checks/runDnsCheck';
|
||||||
|
import { runSingBoxCheck } from './checks/runSingBoxCheck';
|
||||||
|
import { runNftCheck } from './checks/runNftCheck';
|
||||||
|
|
||||||
|
async function renderDiagnosticsChecks() {
|
||||||
|
console.log('renderDiagnosticsChecks');
|
||||||
|
const diagnosticsChecks = store.get().diagnosticsChecks;
|
||||||
|
const container = document.getElementById('pdk_diagnostic-page-checks');
|
||||||
|
|
||||||
|
const renderedDiagnosticsChecks = diagnosticsChecks.map((check) =>
|
||||||
|
renderCheckSection(check),
|
||||||
|
);
|
||||||
|
|
||||||
|
return preserveScrollForPage(() => {
|
||||||
|
container!.replaceChildren(...renderedDiagnosticsChecks);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onStoreUpdate(
|
||||||
|
next: StoreType,
|
||||||
|
prev: StoreType,
|
||||||
|
diff: Partial<StoreType>,
|
||||||
|
) {
|
||||||
|
if (diff.diagnosticsChecks) {
|
||||||
|
renderDiagnosticsChecks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runChecks() {
|
||||||
|
await runDnsCheck();
|
||||||
|
|
||||||
|
await runSingBoxCheck();
|
||||||
|
|
||||||
|
await runNftCheck();
|
||||||
|
}
|
||||||
|
|
||||||
export async function initDiagnosticController(): Promise<void> {
|
export async function initDiagnosticController(): Promise<void> {
|
||||||
onMount('diagnostic-status').then(() => {
|
onMount('diagnostic-status').then(() => {
|
||||||
console.log('diagnostic controller initialized.');
|
console.log('diagnostic controller initialized.');
|
||||||
|
// Remove old listener
|
||||||
|
store.unsubscribe(onStoreUpdate);
|
||||||
|
|
||||||
|
// Clear store
|
||||||
|
store.reset();
|
||||||
|
|
||||||
|
// Add new listener
|
||||||
|
store.subscribe(onStoreUpdate);
|
||||||
|
|
||||||
|
// TMP run checks on mount
|
||||||
|
runChecks();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
167
fe-app-podkop/src/podkop/tabs/diagnostic/renderCheckSection.ts
Normal file
167
fe-app-podkop/src/podkop/tabs/diagnostic/renderCheckSection.ts
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
import {
|
||||||
|
renderLoaderCircleIcon24,
|
||||||
|
renderShieldAlertIcon24,
|
||||||
|
renderShieldCheckIcon24,
|
||||||
|
renderShieldIcon24,
|
||||||
|
renderShieldXIcon24,
|
||||||
|
} from '../../../icons';
|
||||||
|
import { IDiagnosticsChecksStoreItem } from '../../../store';
|
||||||
|
|
||||||
|
type IRenderCheckSectionProps = IDiagnosticsChecksStoreItem;
|
||||||
|
|
||||||
|
function renderCheckSummary(items: IRenderCheckSectionProps['items']) {
|
||||||
|
if (!items.length) {
|
||||||
|
return E('div', {}, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderedItems = items.map((item) =>
|
||||||
|
E(
|
||||||
|
'div',
|
||||||
|
{
|
||||||
|
class: `pdk_diagnostic_alert__summary__item pdk_diagnostic_alert__summary__item--${item.state}`,
|
||||||
|
},
|
||||||
|
[E('b', {}, item.key), E('div', {}, item.value)],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return E('div', { class: 'pdk_diagnostic_alert__summary' }, renderedItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderLoadingState(props: IRenderCheckSectionProps) {
|
||||||
|
const iconWrap = E('span', { class: 'pdk_diagnostic_alert__icon' });
|
||||||
|
iconWrap.appendChild(renderLoaderCircleIcon24());
|
||||||
|
|
||||||
|
return E(
|
||||||
|
'div',
|
||||||
|
{ class: 'pdk_diagnostic_alert pdk_diagnostic_alert--loading' },
|
||||||
|
[
|
||||||
|
iconWrap,
|
||||||
|
E('div', { class: 'pdk_diagnostic_alert__content' }, [
|
||||||
|
E('b', { class: 'pdk_diagnostic_alert__title' }, props.title),
|
||||||
|
E(
|
||||||
|
'div',
|
||||||
|
{ class: 'pdk_diagnostic_alert__description' },
|
||||||
|
props.description,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
E('div', {}, ''),
|
||||||
|
renderCheckSummary(props.items),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderWarningState(props: IRenderCheckSectionProps) {
|
||||||
|
const iconWrap = E('span', { class: 'pdk_diagnostic_alert__icon' });
|
||||||
|
iconWrap.appendChild(renderShieldAlertIcon24());
|
||||||
|
|
||||||
|
return E(
|
||||||
|
'div',
|
||||||
|
{ class: 'pdk_diagnostic_alert pdk_diagnostic_alert--warning' },
|
||||||
|
[
|
||||||
|
iconWrap,
|
||||||
|
E('div', { class: 'pdk_diagnostic_alert__content' }, [
|
||||||
|
E('b', { class: 'pdk_diagnostic_alert__title' }, props.title),
|
||||||
|
E(
|
||||||
|
'div',
|
||||||
|
{ class: 'pdk_diagnostic_alert__description' },
|
||||||
|
props.description,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
E('div', {}, ''),
|
||||||
|
renderCheckSummary(props.items),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderErrorState(props: IRenderCheckSectionProps) {
|
||||||
|
const iconWrap = E('span', { class: 'pdk_diagnostic_alert__icon' });
|
||||||
|
iconWrap.appendChild(renderShieldXIcon24());
|
||||||
|
|
||||||
|
return E(
|
||||||
|
'div',
|
||||||
|
{ class: 'pdk_diagnostic_alert pdk_diagnostic_alert--error' },
|
||||||
|
[
|
||||||
|
iconWrap,
|
||||||
|
E('div', { class: 'pdk_diagnostic_alert__content' }, [
|
||||||
|
E('b', { class: 'pdk_diagnostic_alert__title' }, props.title),
|
||||||
|
E(
|
||||||
|
'div',
|
||||||
|
{ class: 'pdk_diagnostic_alert__description' },
|
||||||
|
props.description,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
E('div', {}, ''),
|
||||||
|
renderCheckSummary(props.items),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSuccessState(props: IRenderCheckSectionProps) {
|
||||||
|
const iconWrap = E('span', { class: 'pdk_diagnostic_alert__icon' });
|
||||||
|
iconWrap.appendChild(renderShieldCheckIcon24());
|
||||||
|
|
||||||
|
return E(
|
||||||
|
'div',
|
||||||
|
{ class: 'pdk_diagnostic_alert pdk_diagnostic_alert--success' },
|
||||||
|
[
|
||||||
|
iconWrap,
|
||||||
|
E('div', { class: 'pdk_diagnostic_alert__content' }, [
|
||||||
|
E('b', { class: 'pdk_diagnostic_alert__title' }, props.title),
|
||||||
|
E(
|
||||||
|
'div',
|
||||||
|
{ class: 'pdk_diagnostic_alert__description' },
|
||||||
|
props.description,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
E('div', {}, ''),
|
||||||
|
renderCheckSummary(props.items),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSkippedState(props: IRenderCheckSectionProps) {
|
||||||
|
const iconWrap = E('span', { class: 'pdk_diagnostic_alert__icon' });
|
||||||
|
iconWrap.appendChild(renderShieldIcon24());
|
||||||
|
|
||||||
|
return E(
|
||||||
|
'div',
|
||||||
|
{ class: 'pdk_diagnostic_alert pdk_diagnostic_alert--skipped' },
|
||||||
|
[
|
||||||
|
iconWrap,
|
||||||
|
E('div', { class: 'pdk_diagnostic_alert__content' }, [
|
||||||
|
E('b', { class: 'pdk_diagnostic_alert__title' }, props.title),
|
||||||
|
E(
|
||||||
|
'div',
|
||||||
|
{ class: 'pdk_diagnostic_alert__description' },
|
||||||
|
props.description,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
E('div', {}, ''),
|
||||||
|
renderCheckSummary(props.items),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderCheckSection(props: IRenderCheckSectionProps) {
|
||||||
|
if (props.state === 'loading') {
|
||||||
|
return renderLoadingState(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.state === 'warning') {
|
||||||
|
return renderWarningState(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.state === 'error') {
|
||||||
|
return renderErrorState(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.state === 'success') {
|
||||||
|
return renderSuccessState(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.state === 'skipped') {
|
||||||
|
return renderSkippedState(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
return E('div', {}, 'Not implement yet');
|
||||||
|
}
|
||||||
@@ -1,10 +1,45 @@
|
|||||||
export function renderDiagnostic() {
|
export function renderDiagnostic() {
|
||||||
return E(
|
return E(
|
||||||
|
'div',
|
||||||
|
{ id: 'diagnostic-status', class: 'pdk_diagnostic-page' },
|
||||||
|
E(
|
||||||
'div',
|
'div',
|
||||||
{
|
{
|
||||||
id: 'diagnostic-status',
|
class: 'pdk_diagnostic-page__checks',
|
||||||
class: 'pdk_diagnostic-page',
|
id: 'pdk_diagnostic-page-checks',
|
||||||
},
|
},
|
||||||
'Not implemented yet',
|
// [
|
||||||
|
// 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: [],
|
||||||
|
// }),
|
||||||
|
// ],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { IDiagnosticsChecksStoreItem, store } from '../../../store';
|
||||||
|
|
||||||
|
export function updateDiagnosticsCheck(check: IDiagnosticsChecksStoreItem) {
|
||||||
|
const diagnosticsChecks = store.get().diagnosticsChecks;
|
||||||
|
const other = diagnosticsChecks.filter((item) => item.code !== check.code);
|
||||||
|
|
||||||
|
store.set({
|
||||||
|
diagnosticsChecks: [...other, check],
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -112,6 +112,18 @@ class Store<T extends Record<string, any>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IDiagnosticsChecksStoreItem {
|
||||||
|
code: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
state: 'loading' | 'warning' | 'success' | 'error' | 'skipped';
|
||||||
|
items: Array<{
|
||||||
|
state: 'error' | 'warning' | 'success';
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface StoreType {
|
export interface StoreType {
|
||||||
tabService: {
|
tabService: {
|
||||||
current: string;
|
current: string;
|
||||||
@@ -143,6 +155,7 @@ export interface StoreType {
|
|||||||
data: Podkop.OutboundGroup[];
|
data: Podkop.OutboundGroup[];
|
||||||
latencyFetching: boolean;
|
latencyFetching: boolean;
|
||||||
};
|
};
|
||||||
|
diagnosticsChecks: Array<IDiagnosticsChecksStoreItem>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialStore: StoreType = {
|
const initialStore: StoreType = {
|
||||||
@@ -176,6 +189,7 @@ const initialStore: StoreType = {
|
|||||||
latencyFetching: false,
|
latencyFetching: false,
|
||||||
data: [],
|
data: [],
|
||||||
},
|
},
|
||||||
|
diagnosticsChecks: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const store = new Store<StoreType>(initialStore);
|
export const store = new Store<StoreType>(initialStore);
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ export const GlobalStyles = `
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cbi-podkop-diagnostic > h3 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.cbi-section-remove {
|
.cbi-section-remove {
|
||||||
margin-bottom: -32px;
|
margin-bottom: -32px;
|
||||||
}
|
}
|
||||||
@@ -194,4 +198,89 @@ export const GlobalStyles = `
|
|||||||
left: 150%;
|
left: 150%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Lucide spinner animate */
|
||||||
|
.lucide-rotate {
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
from { transform: rotate(0deg); }
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#cbi-podkop-diagnostic-_mount_node > div {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic-page__checks {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-row-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert {
|
||||||
|
border: 2px var(--background-color-low, lightgray) solid;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 24px 1fr;
|
||||||
|
grid-column-gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert--loading {
|
||||||
|
border: 2px var(--primary-color-high, dodgerblue) solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert--warning {
|
||||||
|
border: 2px var(--warn-color-medium, orange) solid;
|
||||||
|
color: var(--warn-color-medium, orange);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert--error {
|
||||||
|
border: 2px var(--error-color-medium, red) solid;
|
||||||
|
color: var(--error-color-medium, red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert--success {
|
||||||
|
border: 2px var(--success-color-medium, green) solid;
|
||||||
|
color: var(--success-color-medium, green);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert--skipped {}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__icon {}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__content {}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__title {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__description {}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__summary {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__summary__item {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
grid-column-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__summary__item--error {
|
||||||
|
color: var(--error-color-medium, red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__summary__item--warning {
|
||||||
|
color: var(--warn-color-medium, orange);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__summary__item--success {
|
||||||
|
color: var(--success-color-medium, green);
|
||||||
|
}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -263,6 +263,10 @@ var GlobalStyles = `
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cbi-podkop-diagnostic > h3 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.cbi-section-remove {
|
.cbi-section-remove {
|
||||||
margin-bottom: -32px;
|
margin-bottom: -32px;
|
||||||
}
|
}
|
||||||
@@ -417,6 +421,91 @@ var GlobalStyles = `
|
|||||||
left: 150%;
|
left: 150%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Lucide spinner animate */
|
||||||
|
.lucide-rotate {
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
from { transform: rotate(0deg); }
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#cbi-podkop-diagnostic-_mount_node > div {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic-page__checks {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-row-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert {
|
||||||
|
border: 2px var(--background-color-low, lightgray) solid;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 24px 1fr;
|
||||||
|
grid-column-gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert--loading {
|
||||||
|
border: 2px var(--primary-color-high, dodgerblue) solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert--warning {
|
||||||
|
border: 2px var(--warn-color-medium, orange) solid;
|
||||||
|
color: var(--warn-color-medium, orange);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert--error {
|
||||||
|
border: 2px var(--error-color-medium, red) solid;
|
||||||
|
color: var(--error-color-medium, red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert--success {
|
||||||
|
border: 2px var(--success-color-medium, green) solid;
|
||||||
|
color: var(--success-color-medium, green);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert--skipped {}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__icon {}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__content {}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__title {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__description {}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__summary {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__summary__item {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
grid-column-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__summary__item--error {
|
||||||
|
color: var(--error-color-medium, red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__summary__item--warning {
|
||||||
|
color: var(--warn-color-medium, orange);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdk_diagnostic_alert__summary__item--success {
|
||||||
|
color: var(--success-color-medium, green);
|
||||||
|
}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// src/helpers/injectGlobalStyles.ts
|
// src/helpers/injectGlobalStyles.ts
|
||||||
@@ -668,6 +757,17 @@ function parseQueryString(query) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// src/helpers/svgEl.ts
|
||||||
|
function svgEl(tag, attrs = {}, children = []) {
|
||||||
|
const NS = "http://www.w3.org/2000/svg";
|
||||||
|
const el = document.createElementNS(NS, tag);
|
||||||
|
for (const [k, v] of Object.entries(attrs)) {
|
||||||
|
if (v != null) el.setAttribute(k, String(v));
|
||||||
|
}
|
||||||
|
(Array.isArray(children) ? children : [children]).filter(Boolean).forEach((ch) => el.appendChild(ch));
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
// src/validators/validateVlessUrl.ts
|
// src/validators/validateVlessUrl.ts
|
||||||
function validateVlessUrl(url) {
|
function validateVlessUrl(url) {
|
||||||
try {
|
try {
|
||||||
@@ -1329,7 +1429,8 @@ var initialStore = {
|
|||||||
failed: false,
|
failed: false,
|
||||||
latencyFetching: false,
|
latencyFetching: false,
|
||||||
data: []
|
data: []
|
||||||
}
|
},
|
||||||
|
diagnosticsChecks: []
|
||||||
};
|
};
|
||||||
var store = new Store(initialStore);
|
var store = new Store(initialStore);
|
||||||
|
|
||||||
@@ -2035,19 +2136,593 @@ async function initDashboardController() {
|
|||||||
// src/podkop/tabs/diagnostic/renderDiagnostic.ts
|
// src/podkop/tabs/diagnostic/renderDiagnostic.ts
|
||||||
function renderDiagnostic() {
|
function renderDiagnostic() {
|
||||||
return E(
|
return E(
|
||||||
|
"div",
|
||||||
|
{ id: "diagnostic-status", class: "pdk_diagnostic-page" },
|
||||||
|
E(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
id: "diagnostic-status",
|
class: "pdk_diagnostic-page__checks",
|
||||||
class: "pdk_diagnostic-page"
|
id: "pdk_diagnostic-page-checks"
|
||||||
},
|
}
|
||||||
"Not implemented yet"
|
// [
|
||||||
|
// 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: [],
|
||||||
|
// }),
|
||||||
|
// ],
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// src/icons/renderLoaderCircleIcon24.ts
|
||||||
|
function renderLoaderCircleIcon24() {
|
||||||
|
const NS = "http://www.w3.org/2000/svg";
|
||||||
|
return svgEl(
|
||||||
|
"svg",
|
||||||
|
{
|
||||||
|
xmlns: NS,
|
||||||
|
width: "24",
|
||||||
|
height: "24",
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
fill: "none",
|
||||||
|
stroke: "currentColor",
|
||||||
|
"stroke-width": "2",
|
||||||
|
"stroke-linecap": "round",
|
||||||
|
"stroke-linejoin": "round",
|
||||||
|
class: "lucide lucide-loader-circle lucide-rotate"
|
||||||
|
},
|
||||||
|
[
|
||||||
|
svgEl("path", {
|
||||||
|
d: "M21 12a9 9 0 1 1-6.219-8.56"
|
||||||
|
}),
|
||||||
|
svgEl("animateTransform", {
|
||||||
|
attributeName: "transform",
|
||||||
|
attributeType: "XML",
|
||||||
|
type: "rotate",
|
||||||
|
from: "0 12 12",
|
||||||
|
to: "360 12 12",
|
||||||
|
dur: "1s",
|
||||||
|
repeatCount: "indefinite"
|
||||||
|
})
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/icons/renderShieldAlertIcon24.ts
|
||||||
|
function renderShieldAlertIcon24() {
|
||||||
|
const NS = "http://www.w3.org/2000/svg";
|
||||||
|
return svgEl(
|
||||||
|
"svg",
|
||||||
|
{
|
||||||
|
xmlns: NS,
|
||||||
|
width: "24",
|
||||||
|
height: "24",
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
fill: "none",
|
||||||
|
stroke: "currentColor",
|
||||||
|
"stroke-width": "2",
|
||||||
|
"stroke-linecap": "round",
|
||||||
|
"stroke-linejoin": "round",
|
||||||
|
class: "lucide lucide-shield-alert"
|
||||||
|
},
|
||||||
|
[
|
||||||
|
svgEl("path", {
|
||||||
|
d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"
|
||||||
|
}),
|
||||||
|
svgEl("path", { d: "M12 8v4" }),
|
||||||
|
svgEl("path", { d: "M12 16h.01" })
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/icons/renderShieldCheckIcon24.ts
|
||||||
|
function renderShieldCheckIcon24() {
|
||||||
|
const NS = "http://www.w3.org/2000/svg";
|
||||||
|
return svgEl(
|
||||||
|
"svg",
|
||||||
|
{
|
||||||
|
xmlns: NS,
|
||||||
|
width: "24",
|
||||||
|
height: "24",
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
fill: "none",
|
||||||
|
stroke: "currentColor",
|
||||||
|
"stroke-width": "2",
|
||||||
|
"stroke-linecap": "round",
|
||||||
|
"stroke-linejoin": "round",
|
||||||
|
class: "lucide lucide-shield-check"
|
||||||
|
},
|
||||||
|
[
|
||||||
|
svgEl("path", {
|
||||||
|
d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"
|
||||||
|
}),
|
||||||
|
svgEl("path", { d: "m9 12 2 2 4-4" })
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/icons/renderShieldIcon24.ts
|
||||||
|
function renderShieldIcon24() {
|
||||||
|
const NS = "http://www.w3.org/2000/svg";
|
||||||
|
return svgEl(
|
||||||
|
"svg",
|
||||||
|
{
|
||||||
|
xmlns: NS,
|
||||||
|
width: "24",
|
||||||
|
height: "24",
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
fill: "none",
|
||||||
|
stroke: "currentColor",
|
||||||
|
"stroke-width": "2",
|
||||||
|
"stroke-linecap": "round",
|
||||||
|
"stroke-linejoin": "round",
|
||||||
|
class: "lucide lucide-shield"
|
||||||
|
},
|
||||||
|
[
|
||||||
|
svgEl("path", {
|
||||||
|
d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"
|
||||||
|
})
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/icons/renderShieldXIcon24.ts
|
||||||
|
function renderShieldXIcon24() {
|
||||||
|
const NS = "http://www.w3.org/2000/svg";
|
||||||
|
return svgEl(
|
||||||
|
"svg",
|
||||||
|
{
|
||||||
|
xmlns: NS,
|
||||||
|
width: "24",
|
||||||
|
height: "24",
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
fill: "none",
|
||||||
|
stroke: "currentColor",
|
||||||
|
"stroke-width": "2",
|
||||||
|
"stroke-linecap": "round",
|
||||||
|
"stroke-linejoin": "round",
|
||||||
|
class: "lucide lucide-shield-x"
|
||||||
|
},
|
||||||
|
[
|
||||||
|
svgEl("path", {
|
||||||
|
d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"
|
||||||
|
}),
|
||||||
|
svgEl("path", { d: "m14.5 9.5-5 5" }),
|
||||||
|
svgEl("path", { d: "m9.5 9.5 5 5" })
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/podkop/tabs/diagnostic/renderCheckSection.ts
|
||||||
|
function renderCheckSummary(items) {
|
||||||
|
if (!items.length) {
|
||||||
|
return E("div", {}, "");
|
||||||
|
}
|
||||||
|
const renderedItems = items.map(
|
||||||
|
(item) => E(
|
||||||
|
"div",
|
||||||
|
{
|
||||||
|
class: `pdk_diagnostic_alert__summary__item pdk_diagnostic_alert__summary__item--${item.state}`
|
||||||
|
},
|
||||||
|
[E("b", {}, item.key), E("div", {}, item.value)]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return E("div", { class: "pdk_diagnostic_alert__summary" }, renderedItems);
|
||||||
|
}
|
||||||
|
function renderLoadingState3(props) {
|
||||||
|
const iconWrap = E("span", { class: "pdk_diagnostic_alert__icon" });
|
||||||
|
iconWrap.appendChild(renderLoaderCircleIcon24());
|
||||||
|
return E(
|
||||||
|
"div",
|
||||||
|
{ class: "pdk_diagnostic_alert pdk_diagnostic_alert--loading" },
|
||||||
|
[
|
||||||
|
iconWrap,
|
||||||
|
E("div", { class: "pdk_diagnostic_alert__content" }, [
|
||||||
|
E("b", { class: "pdk_diagnostic_alert__title" }, props.title),
|
||||||
|
E(
|
||||||
|
"div",
|
||||||
|
{ class: "pdk_diagnostic_alert__description" },
|
||||||
|
props.description
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
E("div", {}, ""),
|
||||||
|
renderCheckSummary(props.items)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function renderWarningState(props) {
|
||||||
|
const iconWrap = E("span", { class: "pdk_diagnostic_alert__icon" });
|
||||||
|
iconWrap.appendChild(renderShieldAlertIcon24());
|
||||||
|
return E(
|
||||||
|
"div",
|
||||||
|
{ class: "pdk_diagnostic_alert pdk_diagnostic_alert--warning" },
|
||||||
|
[
|
||||||
|
iconWrap,
|
||||||
|
E("div", { class: "pdk_diagnostic_alert__content" }, [
|
||||||
|
E("b", { class: "pdk_diagnostic_alert__title" }, props.title),
|
||||||
|
E(
|
||||||
|
"div",
|
||||||
|
{ class: "pdk_diagnostic_alert__description" },
|
||||||
|
props.description
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
E("div", {}, ""),
|
||||||
|
renderCheckSummary(props.items)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function renderErrorState(props) {
|
||||||
|
const iconWrap = E("span", { class: "pdk_diagnostic_alert__icon" });
|
||||||
|
iconWrap.appendChild(renderShieldXIcon24());
|
||||||
|
return E(
|
||||||
|
"div",
|
||||||
|
{ class: "pdk_diagnostic_alert pdk_diagnostic_alert--error" },
|
||||||
|
[
|
||||||
|
iconWrap,
|
||||||
|
E("div", { class: "pdk_diagnostic_alert__content" }, [
|
||||||
|
E("b", { class: "pdk_diagnostic_alert__title" }, props.title),
|
||||||
|
E(
|
||||||
|
"div",
|
||||||
|
{ class: "pdk_diagnostic_alert__description" },
|
||||||
|
props.description
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
E("div", {}, ""),
|
||||||
|
renderCheckSummary(props.items)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function renderSuccessState(props) {
|
||||||
|
const iconWrap = E("span", { class: "pdk_diagnostic_alert__icon" });
|
||||||
|
iconWrap.appendChild(renderShieldCheckIcon24());
|
||||||
|
return E(
|
||||||
|
"div",
|
||||||
|
{ class: "pdk_diagnostic_alert pdk_diagnostic_alert--success" },
|
||||||
|
[
|
||||||
|
iconWrap,
|
||||||
|
E("div", { class: "pdk_diagnostic_alert__content" }, [
|
||||||
|
E("b", { class: "pdk_diagnostic_alert__title" }, props.title),
|
||||||
|
E(
|
||||||
|
"div",
|
||||||
|
{ class: "pdk_diagnostic_alert__description" },
|
||||||
|
props.description
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
E("div", {}, ""),
|
||||||
|
renderCheckSummary(props.items)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function renderSkippedState(props) {
|
||||||
|
const iconWrap = E("span", { class: "pdk_diagnostic_alert__icon" });
|
||||||
|
iconWrap.appendChild(renderShieldIcon24());
|
||||||
|
return E(
|
||||||
|
"div",
|
||||||
|
{ class: "pdk_diagnostic_alert pdk_diagnostic_alert--skipped" },
|
||||||
|
[
|
||||||
|
iconWrap,
|
||||||
|
E("div", { class: "pdk_diagnostic_alert__content" }, [
|
||||||
|
E("b", { class: "pdk_diagnostic_alert__title" }, props.title),
|
||||||
|
E(
|
||||||
|
"div",
|
||||||
|
{ class: "pdk_diagnostic_alert__description" },
|
||||||
|
props.description
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
E("div", {}, ""),
|
||||||
|
renderCheckSummary(props.items)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function renderCheckSection(props) {
|
||||||
|
if (props.state === "loading") {
|
||||||
|
return renderLoadingState3(props);
|
||||||
|
}
|
||||||
|
if (props.state === "warning") {
|
||||||
|
return renderWarningState(props);
|
||||||
|
}
|
||||||
|
if (props.state === "error") {
|
||||||
|
return renderErrorState(props);
|
||||||
|
}
|
||||||
|
if (props.state === "success") {
|
||||||
|
return renderSuccessState(props);
|
||||||
|
}
|
||||||
|
if (props.state === "skipped") {
|
||||||
|
return renderSkippedState(props);
|
||||||
|
}
|
||||||
|
return E("div", {}, "Not implement yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/podkop/tabs/diagnostic/updateDiagnosticsCheck.ts
|
||||||
|
function updateDiagnosticsCheck(check) {
|
||||||
|
const diagnosticsChecks = store.get().diagnosticsChecks;
|
||||||
|
const other = diagnosticsChecks.filter((item) => item.code !== check.code);
|
||||||
|
store.set({
|
||||||
|
diagnosticsChecks: [...other, check]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/podkop/tabs/diagnostic/checks/runDnsCheck.ts
|
||||||
|
async function runDnsCheck() {
|
||||||
|
const code = "dns_check";
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _("DNS checks"),
|
||||||
|
description: _("Checking dns, please wait"),
|
||||||
|
state: "loading",
|
||||||
|
items: []
|
||||||
|
});
|
||||||
|
const dnsChecks = await getDNSCheck();
|
||||||
|
if (!dnsChecks.success) {
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _("DNS checks"),
|
||||||
|
description: _("Cannot receive DNS checks result"),
|
||||||
|
state: "error",
|
||||||
|
items: []
|
||||||
|
});
|
||||||
|
throw new Error("DNS checks failed");
|
||||||
|
}
|
||||||
|
const data = dnsChecks.data;
|
||||||
|
const allGood = Boolean(data.local_dns_status) && Boolean(data.bootstrap_dns_status) && Boolean(data.dns_status);
|
||||||
|
const atLeastOneGood = Boolean(data.local_dns_status) || Boolean(data.bootstrap_dns_status) || Boolean(data.dns_status);
|
||||||
|
console.log("dnsChecks", dnsChecks);
|
||||||
|
function getStatus() {
|
||||||
|
if (allGood) {
|
||||||
|
return "success";
|
||||||
|
}
|
||||||
|
if (atLeastOneGood) {
|
||||||
|
return "warning";
|
||||||
|
}
|
||||||
|
return "error";
|
||||||
|
}
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _("DNS checks"),
|
||||||
|
description: _("DNS checks passed"),
|
||||||
|
state: getStatus(),
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
state: data.bootstrap_dns_status ? "success" : "error",
|
||||||
|
key: _("Bootsrap DNS"),
|
||||||
|
value: data.bootstrap_dns_server
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.dns_status ? "success" : "error",
|
||||||
|
key: _("Main DNS"),
|
||||||
|
value: `${data.dns_server} [${data.dns_type}]`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.local_dns_status ? "success" : "error",
|
||||||
|
key: _("Local DNS"),
|
||||||
|
value: data.local_dns_status ? _("Enabled") : _("Failed")
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
if (!atLeastOneGood) {
|
||||||
|
throw new Error("DNS checks failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts
|
||||||
|
async function runSingBoxCheck() {
|
||||||
|
const code = "sing_box_check";
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _("Sing-box checks"),
|
||||||
|
description: _("Checking sing-box, please wait"),
|
||||||
|
state: "loading",
|
||||||
|
items: []
|
||||||
|
});
|
||||||
|
const singBoxChecks = await getSingBoxCheck();
|
||||||
|
if (!singBoxChecks.success) {
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _("Sing-box checks"),
|
||||||
|
description: _("Cannot receive Sing-box checks result"),
|
||||||
|
state: "error",
|
||||||
|
items: []
|
||||||
|
});
|
||||||
|
throw new Error("Sing-box checks failed");
|
||||||
|
}
|
||||||
|
const data = singBoxChecks.data;
|
||||||
|
const allGood = Boolean(data.sing_box_installed) && Boolean(data.sing_box_version_ok) && Boolean(data.sing_box_service_exist) && Boolean(data.sing_box_autostart_disabled) && Boolean(data.sing_box_process_running) && Boolean(data.sing_box_ports_listening);
|
||||||
|
const atLeastOneGood = Boolean(data.sing_box_installed) || Boolean(data.sing_box_version_ok) || Boolean(data.sing_box_service_exist) || Boolean(data.sing_box_autostart_disabled) || Boolean(data.sing_box_process_running) || Boolean(data.sing_box_ports_listening);
|
||||||
|
console.log("singBoxChecks", singBoxChecks);
|
||||||
|
function getStatus() {
|
||||||
|
if (allGood) {
|
||||||
|
return "success";
|
||||||
|
}
|
||||||
|
if (atLeastOneGood) {
|
||||||
|
return "warning";
|
||||||
|
}
|
||||||
|
return "error";
|
||||||
|
}
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _("Sing-box checks"),
|
||||||
|
description: _("Sing-box checks passed"),
|
||||||
|
state: getStatus(),
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
state: data.sing_box_installed ? "success" : "error",
|
||||||
|
key: _("Sing-box installed"),
|
||||||
|
value: data.sing_box_installed ? _("Yes") : _("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.sing_box_version_ok ? "success" : "error",
|
||||||
|
key: _("Sing-box version >= 1.12.4"),
|
||||||
|
value: data.sing_box_version_ok ? _("Yes") : _("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.sing_box_service_exist ? "success" : "error",
|
||||||
|
key: _("Sing-box service exist"),
|
||||||
|
value: data.sing_box_service_exist ? _("Yes") : _("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.sing_box_autostart_disabled ? "success" : "error",
|
||||||
|
key: _("Sing-box autostart disabled"),
|
||||||
|
value: data.sing_box_autostart_disabled ? _("Yes") : _("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.sing_box_process_running ? "success" : "error",
|
||||||
|
key: _("Sing-box process running"),
|
||||||
|
value: data.sing_box_process_running ? _("Yes") : _("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.sing_box_ports_listening ? "success" : "error",
|
||||||
|
key: _("Sing-box listening ports"),
|
||||||
|
value: data.sing_box_ports_listening ? _("Yes") : _("No")
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
if (!atLeastOneGood) {
|
||||||
|
throw new Error("Sing-box checks failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/podkop/tabs/diagnostic/checks/runNftCheck.ts
|
||||||
|
async function runNftCheck() {
|
||||||
|
const code = "nft_check";
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _("Nftables checks"),
|
||||||
|
description: _("Checking nftables, please wait"),
|
||||||
|
state: "loading",
|
||||||
|
items: []
|
||||||
|
});
|
||||||
|
const nftablesChecks = await getNftRulesCheck();
|
||||||
|
if (!nftablesChecks.success) {
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _("Nftables checks"),
|
||||||
|
description: _("Cannot receive nftables checks result"),
|
||||||
|
state: "error",
|
||||||
|
items: []
|
||||||
|
});
|
||||||
|
throw new Error("Nftables checks failed");
|
||||||
|
}
|
||||||
|
const data = nftablesChecks.data;
|
||||||
|
const allGood = Boolean(data.table_exist) && Boolean(data.rules_mangle_exist) && Boolean(data.rules_mangle_counters) && Boolean(data.rules_mangle_output_exist) && Boolean(data.rules_mangle_output_counters) && Boolean(data.rules_proxy_exist) && Boolean(data.rules_proxy_counters) && Boolean(data.rules_other_mark_exist);
|
||||||
|
const atLeastOneGood = Boolean(data.table_exist) || Boolean(data.rules_mangle_exist) || Boolean(data.rules_mangle_counters) || Boolean(data.rules_mangle_output_exist) || Boolean(data.rules_mangle_output_counters) || Boolean(data.rules_proxy_exist) || Boolean(data.rules_proxy_counters) || Boolean(data.rules_other_mark_exist);
|
||||||
|
console.log("nftablesChecks", nftablesChecks);
|
||||||
|
function getStatus() {
|
||||||
|
if (allGood) {
|
||||||
|
return "success";
|
||||||
|
}
|
||||||
|
if (atLeastOneGood) {
|
||||||
|
return "warning";
|
||||||
|
}
|
||||||
|
return "error";
|
||||||
|
}
|
||||||
|
updateDiagnosticsCheck({
|
||||||
|
code,
|
||||||
|
title: _("Nftables checks"),
|
||||||
|
description: allGood ? _("Nftables checks passed") : _("Nftables checks partially passed"),
|
||||||
|
state: getStatus(),
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
state: data.table_exist ? "success" : "error",
|
||||||
|
key: _("Table exist"),
|
||||||
|
value: data.table_exist ? _("Yes") : _("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.rules_mangle_exist ? "success" : "error",
|
||||||
|
key: _("Rules mangle exist"),
|
||||||
|
value: data.rules_mangle_exist ? _("Yes") : _("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.rules_mangle_counters ? "success" : "error",
|
||||||
|
key: _("Rules mangle counters"),
|
||||||
|
value: data.rules_mangle_counters ? _("Yes") : _("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.rules_mangle_output_exist ? "success" : "error",
|
||||||
|
key: _("Rules mangle output exist"),
|
||||||
|
value: data.rules_mangle_output_exist ? _("Yes") : _("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.rules_mangle_output_counters ? "success" : "error",
|
||||||
|
key: _("Rules mangle output counters"),
|
||||||
|
value: data.rules_mangle_output_counters ? _("Yes") : _("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.rules_proxy_exist ? "success" : "error",
|
||||||
|
key: _("Rules proxy exist"),
|
||||||
|
value: data.rules_proxy_exist ? _("Yes") : _("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.rules_proxy_counters ? "success" : "error",
|
||||||
|
key: _("Rules proxy counters"),
|
||||||
|
value: data.rules_proxy_counters ? _("Yes") : _("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: data.rules_other_mark_exist ? "warning" : "success",
|
||||||
|
key: _("Rules other mark exist"),
|
||||||
|
value: data.rules_other_mark_exist ? _("Yes") : _("No")
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
if (!atLeastOneGood) {
|
||||||
|
throw new Error("Nftables checks failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// src/podkop/tabs/diagnostic/initDiagnosticController.ts
|
// src/podkop/tabs/diagnostic/initDiagnosticController.ts
|
||||||
|
async function renderDiagnosticsChecks() {
|
||||||
|
console.log("renderDiagnosticsChecks");
|
||||||
|
const diagnosticsChecks = store.get().diagnosticsChecks;
|
||||||
|
const container = document.getElementById("pdk_diagnostic-page-checks");
|
||||||
|
const renderedDiagnosticsChecks = diagnosticsChecks.map(
|
||||||
|
(check) => renderCheckSection(check)
|
||||||
|
);
|
||||||
|
return preserveScrollForPage(() => {
|
||||||
|
container.replaceChildren(...renderedDiagnosticsChecks);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async function onStoreUpdate2(next, prev, diff) {
|
||||||
|
if (diff.diagnosticsChecks) {
|
||||||
|
renderDiagnosticsChecks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function runChecks() {
|
||||||
|
await runDnsCheck();
|
||||||
|
await runSingBoxCheck();
|
||||||
|
await runNftCheck();
|
||||||
|
}
|
||||||
async function initDiagnosticController() {
|
async function initDiagnosticController() {
|
||||||
onMount("diagnostic-status").then(() => {
|
onMount("diagnostic-status").then(() => {
|
||||||
console.log("diagnostic controller initialized.");
|
console.log("diagnostic controller initialized.");
|
||||||
|
store.unsubscribe(onStoreUpdate2);
|
||||||
|
store.reset();
|
||||||
|
store.subscribe(onStoreUpdate2);
|
||||||
|
runChecks();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return baseclass.extend({
|
return baseclass.extend({
|
||||||
@@ -2102,6 +2777,7 @@ return baseclass.extend({
|
|||||||
renderDashboard,
|
renderDashboard,
|
||||||
renderDiagnostic,
|
renderDiagnostic,
|
||||||
splitProxyString,
|
splitProxyString,
|
||||||
|
svgEl,
|
||||||
triggerLatencyGroupTest,
|
triggerLatencyGroupTest,
|
||||||
triggerLatencyProxyTest,
|
triggerLatencyProxyTest,
|
||||||
triggerProxySelector,
|
triggerProxySelector,
|
||||||
|
|||||||
Reference in New Issue
Block a user