From 74edbcf07f14502450bc5f025b435c91b36b6e9a Mon Sep 17 00:00:00 2001 From: divocat Date: Mon, 13 Oct 2025 22:40:49 +0300 Subject: [PATCH] feat: update diagnostics checks --- .../methods => api}/createBaseApiRequest.ts | 20 +- fe-app-podkop/src/api/index.ts | 2 + fe-app-podkop/src/api/types.ts | 9 + fe-app-podkop/src/clash/methods/getConfig.ts | 4 +- .../src/clash/methods/getGroupDelay.ts | 4 +- fe-app-podkop/src/clash/methods/getProxies.ts | 4 +- fe-app-podkop/src/clash/methods/getVersion.ts | 4 +- fe-app-podkop/src/clash/methods/index.ts | 1 - .../src/clash/methods/triggerLatencyTest.ts | 3 +- .../src/clash/methods/triggerProxySelector.ts | 3 +- fe-app-podkop/src/clash/types.ts | 10 - fe-app-podkop/src/fakeip/index.ts | 1 + .../src/fakeip/methods/getFakeIpCheck.ts | 23 ++ .../src/fakeip/methods/getIpCheck.ts | 23 ++ fe-app-podkop/src/fakeip/methods/index.ts | 2 + fe-app-podkop/src/icons/index.ts | 3 + fe-app-podkop/src/icons/renderCheckIcon24.ts | 23 ++ .../src/icons/renderTriangleAlertIcon24.ts | 25 +++ fe-app-podkop/src/icons/renderXIcon24.ts | 19 ++ .../tabs/diagnostic/checks/runDnsCheck.ts | 6 +- .../tabs/diagnostic/checks/runFakeIPCheck.ts | 18 +- .../tabs/diagnostic/checks/runNftCheck.ts | 24 ++- .../tabs/diagnostic/checks/runSingBoxCheck.ts | 12 +- .../tabs/diagnostic/renderCheckSection.ts | 33 ++- fe-app-podkop/src/styles.ts | 7 +- .../luci-static/resources/view/podkop/main.js | 198 +++++++++++++++--- 26 files changed, 400 insertions(+), 81 deletions(-) rename fe-app-podkop/src/{clash/methods => api}/createBaseApiRequest.ts (53%) create mode 100644 fe-app-podkop/src/api/index.ts create mode 100644 fe-app-podkop/src/api/types.ts create mode 100644 fe-app-podkop/src/fakeip/index.ts create mode 100644 fe-app-podkop/src/fakeip/methods/getFakeIpCheck.ts create mode 100644 fe-app-podkop/src/fakeip/methods/getIpCheck.ts create mode 100644 fe-app-podkop/src/fakeip/methods/index.ts create mode 100644 fe-app-podkop/src/icons/renderCheckIcon24.ts create mode 100644 fe-app-podkop/src/icons/renderTriangleAlertIcon24.ts create mode 100644 fe-app-podkop/src/icons/renderXIcon24.ts diff --git a/fe-app-podkop/src/clash/methods/createBaseApiRequest.ts b/fe-app-podkop/src/api/createBaseApiRequest.ts similarity index 53% rename from fe-app-podkop/src/clash/methods/createBaseApiRequest.ts rename to fe-app-podkop/src/api/createBaseApiRequest.ts index 601a433..c175678 100644 --- a/fe-app-podkop/src/clash/methods/createBaseApiRequest.ts +++ b/fe-app-podkop/src/api/createBaseApiRequest.ts @@ -1,10 +1,26 @@ -import { IBaseApiResponse } from '../types'; +import { IBaseApiResponse } from './types'; +import { withTimeout } from '../helpers'; export async function createBaseApiRequest( fetchFn: () => Promise, + options?: { + timeoutMs?: number; + operationName?: string; + timeoutMessage?: string; + }, ): Promise> { + const wrappedFn = () => + options?.timeoutMs && options?.operationName + ? withTimeout( + fetchFn(), + options.timeoutMs, + options.operationName, + options.timeoutMessage, + ) + : fetchFn(); + try { - const response = await fetchFn(); + const response = await wrappedFn(); if (!response.ok) { return { diff --git a/fe-app-podkop/src/api/index.ts b/fe-app-podkop/src/api/index.ts new file mode 100644 index 0000000..2068b3f --- /dev/null +++ b/fe-app-podkop/src/api/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './createBaseApiRequest'; diff --git a/fe-app-podkop/src/api/types.ts b/fe-app-podkop/src/api/types.ts new file mode 100644 index 0000000..193eb59 --- /dev/null +++ b/fe-app-podkop/src/api/types.ts @@ -0,0 +1,9 @@ +export type IBaseApiResponse = + | { + success: true; + data: T; + } + | { + success: false; + message: string; + }; diff --git a/fe-app-podkop/src/clash/methods/getConfig.ts b/fe-app-podkop/src/clash/methods/getConfig.ts index 8f7135a..03cd5be 100644 --- a/fe-app-podkop/src/clash/methods/getConfig.ts +++ b/fe-app-podkop/src/clash/methods/getConfig.ts @@ -1,6 +1,6 @@ -import { ClashAPI, IBaseApiResponse } from '../types'; -import { createBaseApiRequest } from './createBaseApiRequest'; +import { ClashAPI } from '../types'; import { getClashApiUrl } from '../../helpers'; +import { createBaseApiRequest, IBaseApiResponse } from '../../api'; export async function getClashConfig(): Promise< IBaseApiResponse diff --git a/fe-app-podkop/src/clash/methods/getGroupDelay.ts b/fe-app-podkop/src/clash/methods/getGroupDelay.ts index f160bec..5dda283 100644 --- a/fe-app-podkop/src/clash/methods/getGroupDelay.ts +++ b/fe-app-podkop/src/clash/methods/getGroupDelay.ts @@ -1,6 +1,6 @@ -import { ClashAPI, IBaseApiResponse } from '../types'; -import { createBaseApiRequest } from './createBaseApiRequest'; +import { ClashAPI } from '../types'; import { getClashApiUrl } from '../../helpers'; +import { createBaseApiRequest, IBaseApiResponse } from '../../api'; export async function getClashGroupDelay( group: string, diff --git a/fe-app-podkop/src/clash/methods/getProxies.ts b/fe-app-podkop/src/clash/methods/getProxies.ts index e465c58..27ae08a 100644 --- a/fe-app-podkop/src/clash/methods/getProxies.ts +++ b/fe-app-podkop/src/clash/methods/getProxies.ts @@ -1,6 +1,6 @@ -import { ClashAPI, IBaseApiResponse } from '../types'; -import { createBaseApiRequest } from './createBaseApiRequest'; +import { ClashAPI } from '../types'; import { getClashApiUrl } from '../../helpers'; +import { createBaseApiRequest, IBaseApiResponse } from '../../api'; export async function getClashProxies(): Promise< IBaseApiResponse diff --git a/fe-app-podkop/src/clash/methods/getVersion.ts b/fe-app-podkop/src/clash/methods/getVersion.ts index 119db9f..da2f97d 100644 --- a/fe-app-podkop/src/clash/methods/getVersion.ts +++ b/fe-app-podkop/src/clash/methods/getVersion.ts @@ -1,6 +1,6 @@ -import { ClashAPI, IBaseApiResponse } from '../types'; -import { createBaseApiRequest } from './createBaseApiRequest'; +import { ClashAPI } from '../types'; import { getClashApiUrl } from '../../helpers'; +import { createBaseApiRequest, IBaseApiResponse } from '../../api'; export async function getClashVersion(): Promise< IBaseApiResponse diff --git a/fe-app-podkop/src/clash/methods/index.ts b/fe-app-podkop/src/clash/methods/index.ts index 1feccdb..9d04845 100644 --- a/fe-app-podkop/src/clash/methods/index.ts +++ b/fe-app-podkop/src/clash/methods/index.ts @@ -1,4 +1,3 @@ -export * from './createBaseApiRequest'; export * from './getConfig'; export * from './getGroupDelay'; export * from './getProxies'; diff --git a/fe-app-podkop/src/clash/methods/triggerLatencyTest.ts b/fe-app-podkop/src/clash/methods/triggerLatencyTest.ts index b7fffd9..fd937f7 100644 --- a/fe-app-podkop/src/clash/methods/triggerLatencyTest.ts +++ b/fe-app-podkop/src/clash/methods/triggerLatencyTest.ts @@ -1,6 +1,5 @@ -import { IBaseApiResponse } from '../types'; -import { createBaseApiRequest } from './createBaseApiRequest'; import { getClashApiUrl } from '../../helpers'; +import { createBaseApiRequest, IBaseApiResponse } from '../../api'; export async function triggerLatencyGroupTest( tag: string, diff --git a/fe-app-podkop/src/clash/methods/triggerProxySelector.ts b/fe-app-podkop/src/clash/methods/triggerProxySelector.ts index 16d1f55..5b22b0c 100644 --- a/fe-app-podkop/src/clash/methods/triggerProxySelector.ts +++ b/fe-app-podkop/src/clash/methods/triggerProxySelector.ts @@ -1,6 +1,5 @@ -import { IBaseApiResponse } from '../types'; -import { createBaseApiRequest } from './createBaseApiRequest'; import { getClashApiUrl } from '../../helpers'; +import { createBaseApiRequest, IBaseApiResponse } from '../../api'; export async function triggerProxySelector( selector: string, diff --git a/fe-app-podkop/src/clash/types.ts b/fe-app-podkop/src/clash/types.ts index a54a55f..9f4700c 100644 --- a/fe-app-podkop/src/clash/types.ts +++ b/fe-app-podkop/src/clash/types.ts @@ -1,13 +1,3 @@ -export type IBaseApiResponse = - | { - success: true; - data: T; - } - | { - success: false; - message: string; - }; - // eslint-disable-next-line @typescript-eslint/no-namespace export namespace ClashAPI { export interface Version { diff --git a/fe-app-podkop/src/fakeip/index.ts b/fe-app-podkop/src/fakeip/index.ts new file mode 100644 index 0000000..4f1821b --- /dev/null +++ b/fe-app-podkop/src/fakeip/index.ts @@ -0,0 +1 @@ +export * from './methods'; diff --git a/fe-app-podkop/src/fakeip/methods/getFakeIpCheck.ts b/fe-app-podkop/src/fakeip/methods/getFakeIpCheck.ts new file mode 100644 index 0000000..44df28c --- /dev/null +++ b/fe-app-podkop/src/fakeip/methods/getFakeIpCheck.ts @@ -0,0 +1,23 @@ +import { createBaseApiRequest, IBaseApiResponse } from '../../api'; +import { FAKEIP_CHECK_DOMAIN } from '../../constants'; + +interface IGetFakeIpCheckResponse { + fakeip: boolean; + IP: string; +} + +export async function getFakeIpCheck(): Promise< + IBaseApiResponse +> { + return createBaseApiRequest( + () => + fetch(`https://${FAKEIP_CHECK_DOMAIN}/check`, { + method: 'GET', + headers: { 'Content-Type': 'application/json' }, + }), + { + operationName: 'getFakeIpCheck', + timeoutMs: 5000, + }, + ); +} diff --git a/fe-app-podkop/src/fakeip/methods/getIpCheck.ts b/fe-app-podkop/src/fakeip/methods/getIpCheck.ts new file mode 100644 index 0000000..f54a054 --- /dev/null +++ b/fe-app-podkop/src/fakeip/methods/getIpCheck.ts @@ -0,0 +1,23 @@ +import { createBaseApiRequest, IBaseApiResponse } from '../../api'; +import { IP_CHECK_DOMAIN } from '../../constants'; + +interface IGetIpCheckResponse { + fakeip: boolean; + IP: string; +} + +export async function getIpCheck(): Promise< + IBaseApiResponse +> { + return createBaseApiRequest( + () => + fetch(`https://${IP_CHECK_DOMAIN}/check`, { + method: 'GET', + headers: { 'Content-Type': 'application/json' }, + }), + { + operationName: 'getIpCheck', + timeoutMs: 5000, + }, + ); +} diff --git a/fe-app-podkop/src/fakeip/methods/index.ts b/fe-app-podkop/src/fakeip/methods/index.ts new file mode 100644 index 0000000..aab9ee5 --- /dev/null +++ b/fe-app-podkop/src/fakeip/methods/index.ts @@ -0,0 +1,2 @@ +export * from './getIpCheck'; +export * from './getFakeIpCheck'; diff --git a/fe-app-podkop/src/icons/index.ts b/fe-app-podkop/src/icons/index.ts index 184bcb8..73c766a 100644 --- a/fe-app-podkop/src/icons/index.ts +++ b/fe-app-podkop/src/icons/index.ts @@ -3,3 +3,6 @@ export * from './renderCircleAlertIcon24'; export * from './renderCircleCheckIcon24'; export * from './renderCircleSlashIcon24'; export * from './renderCircleXIcon24'; +export * from './renderCheckIcon24'; +export * from './renderXIcon24'; +export * from './renderTriangleAlertIcon24'; diff --git a/fe-app-podkop/src/icons/renderCheckIcon24.ts b/fe-app-podkop/src/icons/renderCheckIcon24.ts new file mode 100644 index 0000000..b1c9ab2 --- /dev/null +++ b/fe-app-podkop/src/icons/renderCheckIcon24.ts @@ -0,0 +1,23 @@ +import { svgEl } from '../helpers'; + +export function renderCheckIcon24() { + const NS = 'http://www.w3.org/2000/svg'; + return svgEl( + 'svg', + { + xmlns: NS, + viewBox: '0 0 24 24', + fill: 'none', + stroke: 'currentColor', + 'stroke-width': '2', + 'stroke-linecap': 'round', + 'stroke-linejoin': 'round', + class: 'lucide lucide-check-icon lucide-check', + }, + [ + svgEl('path', { + d: 'M20 6 9 17l-5-5', + }), + ], + ); +} diff --git a/fe-app-podkop/src/icons/renderTriangleAlertIcon24.ts b/fe-app-podkop/src/icons/renderTriangleAlertIcon24.ts new file mode 100644 index 0000000..993b317 --- /dev/null +++ b/fe-app-podkop/src/icons/renderTriangleAlertIcon24.ts @@ -0,0 +1,25 @@ +import { svgEl } from '../helpers'; + +export function renderTriangleAlertIcon24() { + const NS = 'http://www.w3.org/2000/svg'; + return svgEl( + 'svg', + { + xmlns: NS, + viewBox: '0 0 24 24', + fill: 'none', + stroke: 'currentColor', + 'stroke-width': '2', + 'stroke-linecap': 'round', + 'stroke-linejoin': 'round', + class: 'lucide lucide-triangle-alert-icon lucide-triangle-alert', + }, + [ + svgEl('path', { + d: 'm21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3', + }), + svgEl('path', { d: 'M12 9v4' }), + svgEl('path', { d: 'M12 17h.01' }), + ], + ); +} diff --git a/fe-app-podkop/src/icons/renderXIcon24.ts b/fe-app-podkop/src/icons/renderXIcon24.ts new file mode 100644 index 0000000..d8b6ce6 --- /dev/null +++ b/fe-app-podkop/src/icons/renderXIcon24.ts @@ -0,0 +1,19 @@ +import { svgEl } from '../helpers'; + +export function renderXIcon24() { + const NS = 'http://www.w3.org/2000/svg'; + return svgEl( + 'svg', + { + xmlns: NS, + viewBox: '0 0 24 24', + fill: 'none', + stroke: 'currentColor', + 'stroke-width': '2', + 'stroke-linecap': 'round', + 'stroke-linejoin': 'round', + class: 'lucide lucide-x-icon lucide-x', + }, + [svgEl('path', { d: 'M18 6 6 18' }), svgEl('path', { d: 'm6 6 12 12' })], + ); +} diff --git a/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runDnsCheck.ts b/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runDnsCheck.ts index 6d9ef0b..6ac19a2 100644 --- a/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runDnsCheck.ts +++ b/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runDnsCheck.ts @@ -66,19 +66,19 @@ export async function runDnsCheck() { { state: data.bootstrap_dns_status ? 'success' : 'error', key: _('Bootsrap DNS'), - value: `${data.bootstrap_dns_server} ${data.bootstrap_dns_status ? '✅' : '❌'}`, + value: data.bootstrap_dns_server, }, ], ), { state: data.dns_status ? 'success' : 'error', key: _('Main DNS'), - value: `${data.dns_server} [${data.dns_type}] ${data.dns_status ? '✅' : '❌'}`, + value: `${data.dns_server} [${data.dns_type}]`, }, { state: data.local_dns_status ? 'success' : 'error', key: _('Local DNS'), - value: data.local_dns_status ? '✅' : '❌', + value: '', }, ], }); diff --git a/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runFakeIPCheck.ts b/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runFakeIPCheck.ts index 1c16ff5..82b4eeb 100644 --- a/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runFakeIPCheck.ts +++ b/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runFakeIPCheck.ts @@ -8,6 +8,22 @@ export async function runFakeIPCheck() { title: _('Fake IP checks'), description: _('Not implemented yet'), state: 'skipped', - items: [], + items: [ + { + state: 'success', + key: 'success', + value: '', + }, + { + state: 'warning', + key: 'warning', + value: '', + }, + { + state: 'error', + key: 'error', + value: '', + }, + ], }); } diff --git a/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runNftCheck.ts b/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runNftCheck.ts index d59eeee..713d474 100644 --- a/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runNftCheck.ts +++ b/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runNftCheck.ts @@ -1,9 +1,13 @@ import { getNftRulesCheck } from '../../../methods'; import { updateDiagnosticsCheck } from '../updateDiagnosticsCheck'; +import { getFakeIpCheck, getIpCheck } from '../../../../fakeip'; export async function runNftCheck() { const code = 'nft_check'; + await getFakeIpCheck(); + await getIpCheck(); + updateDiagnosticsCheck({ code, title: _('Nftables checks'), @@ -73,42 +77,42 @@ export async function runNftCheck() { { state: data.table_exist ? 'success' : 'error', key: _('Table exist'), - value: data.table_exist ? _('Yes') : _('No'), + value: '', }, { state: data.rules_mangle_exist ? 'success' : 'error', key: _('Rules mangle exist'), - value: data.rules_mangle_exist ? _('Yes') : _('No'), + value: '', }, { state: data.rules_mangle_counters ? 'success' : 'error', key: _('Rules mangle counters'), - value: data.rules_mangle_counters ? _('Yes') : _('No'), + value: '', }, { state: data.rules_mangle_output_exist ? 'success' : 'error', key: _('Rules mangle output exist'), - value: data.rules_mangle_output_exist ? _('Yes') : _('No'), + value: '', }, { state: data.rules_mangle_output_counters ? 'success' : 'error', key: _('Rules mangle output counters'), - value: data.rules_mangle_output_counters ? _('Yes') : _('No'), + value: '', }, { state: data.rules_proxy_exist ? 'success' : 'error', key: _('Rules proxy exist'), - value: data.rules_proxy_exist ? _('Yes') : _('No'), + value: '', }, { state: data.rules_proxy_counters ? 'success' : 'error', key: _('Rules proxy counters'), - value: data.rules_proxy_counters ? _('Yes') : _('No'), + value: '', }, { - state: data.rules_other_mark_exist ? 'warning' : 'success', - key: _('Rules other mark exist'), - value: data.rules_other_mark_exist ? _('Yes') : _('No'), + state: !data.rules_other_mark_exist ? 'success' : 'warning', + key: _('None other Mark rules'), + value: '', }, ], }); diff --git a/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts b/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts index 6f4adce..c9e3f12 100644 --- a/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts +++ b/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts @@ -67,32 +67,32 @@ export async function runSingBoxCheck() { { state: data.sing_box_installed ? 'success' : 'error', key: _('Sing-box installed'), - value: data.sing_box_installed ? _('Yes') : _('No'), + value: '', }, { state: data.sing_box_version_ok ? 'success' : 'error', key: _('Sing-box version >= 1.12.4'), - value: data.sing_box_version_ok ? _('Yes') : _('No'), + value: '', }, { state: data.sing_box_service_exist ? 'success' : 'error', key: _('Sing-box service exist'), - value: data.sing_box_service_exist ? _('Yes') : _('No'), + value: '', }, { state: data.sing_box_autostart_disabled ? 'success' : 'error', key: _('Sing-box autostart disabled'), - value: data.sing_box_autostart_disabled ? _('Yes') : _('No'), + value: '', }, { state: data.sing_box_process_running ? 'success' : 'error', key: _('Sing-box process running'), - value: data.sing_box_process_running ? _('Yes') : _('No'), + value: '', }, { state: data.sing_box_ports_listening ? 'success' : 'error', key: _('Sing-box listening ports'), - value: data.sing_box_ports_listening ? _('Yes') : _('No'), + value: '', }, ], }); diff --git a/fe-app-podkop/src/podkop/tabs/diagnostic/renderCheckSection.ts b/fe-app-podkop/src/podkop/tabs/diagnostic/renderCheckSection.ts index 5128516..e7d8098 100644 --- a/fe-app-podkop/src/podkop/tabs/diagnostic/renderCheckSection.ts +++ b/fe-app-podkop/src/podkop/tabs/diagnostic/renderCheckSection.ts @@ -1,9 +1,12 @@ import { + renderCheckIcon24, renderCircleAlertIcon24, renderCircleCheckIcon24, renderCircleSlashIcon24, renderCircleXIcon24, renderLoaderCircleIcon24, + renderTriangleAlertIcon24, + renderXIcon24, } from '../../../icons'; import { IDiagnosticsChecksStoreItem } from '../../../store'; @@ -14,15 +17,35 @@ function renderCheckSummary(items: IRenderCheckSectionProps['items']) { return E('div', {}, ''); } - const renderedItems = items.map((item) => - E( + const renderedItems = items.map((item) => { + function getIcon() { + const iconWrap = E('span', { + class: 'pdk_diagnostic_alert__summary__item__icon', + }); + + if (item.state === 'success') { + iconWrap.appendChild(renderCheckIcon24()); + } + + if (item.state === 'warning') { + iconWrap.appendChild(renderTriangleAlertIcon24()); + } + + if (item.state === 'error') { + iconWrap.appendChild(renderXIcon24()); + } + + return iconWrap; + } + + return E( 'div', { class: `pdk_diagnostic_alert__summary__item pdk_diagnostic_alert__summary__item--${item.state}`, }, - [E('b', {}, item.key), E('div', {}, item.value)], - ), - ); + [getIcon(), E('b', {}, item.key), E('div', {}, item.value)], + ); + }); return E('div', { class: 'pdk_diagnostic_alert__summary' }, renderedItems); } diff --git a/fe-app-podkop/src/styles.ts b/fe-app-podkop/src/styles.ts index 5ed936c..08d7892 100644 --- a/fe-app-podkop/src/styles.ts +++ b/fe-app-podkop/src/styles.ts @@ -267,7 +267,7 @@ export const GlobalStyles = ` .pdk_diagnostic_alert__summary__item { display: grid; - grid-template-columns: auto 1fr; + grid-template-columns: 16px auto 1fr; grid-column-gap: 10px; } @@ -283,4 +283,9 @@ export const GlobalStyles = ` color: var(--success-color-medium, green); } +.pdk_diagnostic_alert__summary__item__icon { + width: 16px; + height: 16px; +} + `; diff --git a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js index 77dadcd..50ff4c8 100644 --- a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js +++ b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js @@ -490,7 +490,7 @@ var GlobalStyles = ` .pdk_diagnostic_alert__summary__item { display: grid; - grid-template-columns: auto 1fr; + grid-template-columns: 16px auto 1fr; grid-column-gap: 10px; } @@ -506,6 +506,11 @@ var GlobalStyles = ` color: var(--success-color-medium, green); } +.pdk_diagnostic_alert__summary__item__icon { + width: 16px; + height: 16px; +} + `; // src/helpers/injectGlobalStyles.ts @@ -942,10 +947,16 @@ function validateProxyUrl(url) { }; } -// src/clash/methods/createBaseApiRequest.ts -async function createBaseApiRequest(fetchFn) { +// src/api/createBaseApiRequest.ts +async function createBaseApiRequest(fetchFn, options) { + const wrappedFn = () => options?.timeoutMs && options?.operationName ? withTimeout( + fetchFn(), + options.timeoutMs, + options.operationName, + options.timeoutMessage + ) : fetchFn(); try { - const response = await fetchFn(); + const response = await wrappedFn(); if (!response.ok) { return { success: false, @@ -2357,20 +2368,102 @@ function renderCircleXIcon24() { ); } +// src/icons/renderCheckIcon24.ts +function renderCheckIcon24() { + const NS = "http://www.w3.org/2000/svg"; + return svgEl( + "svg", + { + xmlns: NS, + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + "stroke-width": "2", + "stroke-linecap": "round", + "stroke-linejoin": "round", + class: "lucide lucide-check-icon lucide-check" + }, + [ + svgEl("path", { + d: "M20 6 9 17l-5-5" + }) + ] + ); +} + +// src/icons/renderXIcon24.ts +function renderXIcon24() { + const NS = "http://www.w3.org/2000/svg"; + return svgEl( + "svg", + { + xmlns: NS, + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + "stroke-width": "2", + "stroke-linecap": "round", + "stroke-linejoin": "round", + class: "lucide lucide-x-icon lucide-x" + }, + [svgEl("path", { d: "M18 6 6 18" }), svgEl("path", { d: "m6 6 12 12" })] + ); +} + +// src/icons/renderTriangleAlertIcon24.ts +function renderTriangleAlertIcon24() { + const NS = "http://www.w3.org/2000/svg"; + return svgEl( + "svg", + { + xmlns: NS, + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + "stroke-width": "2", + "stroke-linecap": "round", + "stroke-linejoin": "round", + class: "lucide lucide-triangle-alert-icon lucide-triangle-alert" + }, + [ + svgEl("path", { + d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" + }), + svgEl("path", { d: "M12 9v4" }), + svgEl("path", { d: "M12 17h.01" }) + ] + ); +} + // src/podkop/tabs/diagnostic/renderCheckSection.ts function renderCheckSummary(items) { if (!items.length) { return E("div", {}, ""); } - const renderedItems = items.map( - (item) => E( + const renderedItems = items.map((item) => { + function getIcon() { + const iconWrap = E("span", { + class: "pdk_diagnostic_alert__summary__item__icon" + }); + if (item.state === "success") { + iconWrap.appendChild(renderCheckIcon24()); + } + if (item.state === "warning") { + iconWrap.appendChild(renderTriangleAlertIcon24()); + } + if (item.state === "error") { + iconWrap.appendChild(renderXIcon24()); + } + return iconWrap; + } + return E( "div", { class: `pdk_diagnostic_alert__summary__item pdk_diagnostic_alert__summary__item--${item.state}` }, - [E("b", {}, item.key), E("div", {}, item.value)] - ) - ); + [getIcon(), E("b", {}, item.key), E("div", {}, item.value)] + ); + }); return E("div", { class: "pdk_diagnostic_alert__summary" }, renderedItems); } function renderLoadingState3(props) { @@ -2552,19 +2645,19 @@ async function runDnsCheck() { { state: data.bootstrap_dns_status ? "success" : "error", key: _("Bootsrap DNS"), - value: `${data.bootstrap_dns_server} ${data.bootstrap_dns_status ? "\u2705" : "\u274C"}` + value: data.bootstrap_dns_server } ] ), { state: data.dns_status ? "success" : "error", key: _("Main DNS"), - value: `${data.dns_server} [${data.dns_type}] ${data.dns_status ? "\u2705" : "\u274C"}` + value: `${data.dns_server} [${data.dns_type}]` }, { state: data.local_dns_status ? "success" : "error", key: _("Local DNS"), - value: data.local_dns_status ? "\u2705" : "\u274C" + value: "" } ] }); @@ -2616,32 +2709,32 @@ async function runSingBoxCheck() { { state: data.sing_box_installed ? "success" : "error", key: _("Sing-box installed"), - value: data.sing_box_installed ? _("Yes") : _("No") + value: "" }, { state: data.sing_box_version_ok ? "success" : "error", key: _("Sing-box version >= 1.12.4"), - value: data.sing_box_version_ok ? _("Yes") : _("No") + value: "" }, { state: data.sing_box_service_exist ? "success" : "error", key: _("Sing-box service exist"), - value: data.sing_box_service_exist ? _("Yes") : _("No") + value: "" }, { state: data.sing_box_autostart_disabled ? "success" : "error", key: _("Sing-box autostart disabled"), - value: data.sing_box_autostart_disabled ? _("Yes") : _("No") + value: "" }, { state: data.sing_box_process_running ? "success" : "error", key: _("Sing-box process running"), - value: data.sing_box_process_running ? _("Yes") : _("No") + value: "" }, { state: data.sing_box_ports_listening ? "success" : "error", key: _("Sing-box listening ports"), - value: data.sing_box_ports_listening ? _("Yes") : _("No") + value: "" } ] }); @@ -2650,9 +2743,39 @@ async function runSingBoxCheck() { } } +// src/fakeip/methods/getIpCheck.ts +async function getIpCheck() { + return createBaseApiRequest( + () => fetch(`https://${IP_CHECK_DOMAIN}/check`, { + method: "GET", + headers: { "Content-Type": "application/json" } + }), + { + operationName: "getIpCheck", + timeoutMs: 5e3 + } + ); +} + +// src/fakeip/methods/getFakeIpCheck.ts +async function getFakeIpCheck() { + return createBaseApiRequest( + () => fetch(`https://${FAKEIP_CHECK_DOMAIN}/check`, { + method: "GET", + headers: { "Content-Type": "application/json" } + }), + { + operationName: "getFakeIpCheck", + timeoutMs: 5e3 + } + ); +} + // src/podkop/tabs/diagnostic/checks/runNftCheck.ts async function runNftCheck() { const code = "nft_check"; + await getFakeIpCheck(); + await getIpCheck(); updateDiagnosticsCheck({ code, title: _("Nftables checks"), @@ -2693,42 +2816,42 @@ async function runNftCheck() { { state: data.table_exist ? "success" : "error", key: _("Table exist"), - value: data.table_exist ? _("Yes") : _("No") + value: "" }, { state: data.rules_mangle_exist ? "success" : "error", key: _("Rules mangle exist"), - value: data.rules_mangle_exist ? _("Yes") : _("No") + value: "" }, { state: data.rules_mangle_counters ? "success" : "error", key: _("Rules mangle counters"), - value: data.rules_mangle_counters ? _("Yes") : _("No") + value: "" }, { state: data.rules_mangle_output_exist ? "success" : "error", key: _("Rules mangle output exist"), - value: data.rules_mangle_output_exist ? _("Yes") : _("No") + value: "" }, { state: data.rules_mangle_output_counters ? "success" : "error", key: _("Rules mangle output counters"), - value: data.rules_mangle_output_counters ? _("Yes") : _("No") + value: "" }, { state: data.rules_proxy_exist ? "success" : "error", key: _("Rules proxy exist"), - value: data.rules_proxy_exist ? _("Yes") : _("No") + value: "" }, { state: data.rules_proxy_counters ? "success" : "error", key: _("Rules proxy counters"), - value: data.rules_proxy_counters ? _("Yes") : _("No") + value: "" }, { - state: data.rules_other_mark_exist ? "warning" : "success", - key: _("Rules other mark exist"), - value: data.rules_other_mark_exist ? _("Yes") : _("No") + state: !data.rules_other_mark_exist ? "success" : "warning", + key: _("None other Mark rules"), + value: "" } ] }); @@ -2745,7 +2868,23 @@ async function runFakeIPCheck() { title: _("Fake IP checks"), description: _("Not implemented yet"), state: "skipped", - items: [] + items: [ + { + state: "success", + key: "success", + value: "" + }, + { + state: "warning", + key: "warning", + value: "" + }, + { + state: "error", + key: "error", + value: "" + } + ] }); } @@ -2804,7 +2943,6 @@ return baseclass.extend({ UPDATE_INTERVAL_OPTIONS, bulkValidate, coreService, - createBaseApiRequest, executeShellCommand, getBaseUrl, getClashApiUrl,