feat: implement most diagnostics actions

This commit is contained in:
divocat
2025-10-15 01:11:30 +03:00
parent b8ccb4abfa
commit 6772b83861
23 changed files with 1346 additions and 62 deletions

View File

@@ -6,3 +6,12 @@ export * from './renderCircleXIcon24';
export * from './renderCheckIcon24'; export * from './renderCheckIcon24';
export * from './renderXIcon24'; export * from './renderXIcon24';
export * from './renderTriangleAlertIcon24'; export * from './renderTriangleAlertIcon24';
export * from './renderPauseIcon24';
export * from './renderPlayIcon24';
export * from './renderRotateCcwIcon24';
export * from './renderCircleStopIcon24';
export * from './renderCirclePlayIcon24';
export * from './renderCircleCheckBigIcon24';
export * from './renderSquareChartGanttIcon24';
export * from './renderCogIcon24';
export * from './renderSearchIcon24';

View File

@@ -0,0 +1,26 @@
import { svgEl } from '../helpers';
export function renderCircleCheckBigIcon24() {
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-circle-check-big-icon lucide-circle-check-big',
},
[
svgEl('path', {
d: 'M21.801 10A10 10 0 1 1 17 3.335',
}),
svgEl('path', {
d: 'm9 11 3 3L22 4',
}),
],
);
}

View File

@@ -0,0 +1,28 @@
import { svgEl } from '../helpers';
export function renderCirclePlayIcon24() {
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-circle-play-icon lucide-circle-play',
},
[
svgEl('path', {
d: 'M9 9.003a1 1 0 0 1 1.517-.859l4.997 2.997a1 1 0 0 1 0 1.718l-4.997 2.997A1 1 0 0 1 9 14.996z',
}),
svgEl('circle', {
cx: '12',
cy: '12',
r: '10',
}),
],
);
}

View File

@@ -0,0 +1,32 @@
import { svgEl } from '../helpers';
export function renderCircleStopIcon24() {
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-circle-stop-icon lucide-circle-stop',
},
[
svgEl('circle', {
cx: '12',
cy: '12',
r: '10',
}),
svgEl('rect', {
x: '9',
y: '9',
width: '6',
height: '6',
rx: '1',
}),
],
);
}

View File

@@ -0,0 +1,34 @@
import { svgEl } from '../helpers';
export function renderCogIcon24() {
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-cog-icon lucide-cog',
},
[
svgEl('path', { d: 'M11 10.27 7 3.34' }),
svgEl('path', { d: 'm11 13.73-4 6.93' }),
svgEl('path', { d: 'M12 22v-2' }),
svgEl('path', { d: 'M12 2v2' }),
svgEl('path', { d: 'M14 12h8' }),
svgEl('path', { d: 'm17 20.66-1-1.73' }),
svgEl('path', { d: 'm17 3.34-1 1.73' }),
svgEl('path', { d: 'M2 12h2' }),
svgEl('path', { d: 'm20.66 17-1.73-1' }),
svgEl('path', { d: 'm20.66 7-1.73 1' }),
svgEl('path', { d: 'm3.34 17 1.73-1' }),
svgEl('path', { d: 'm3.34 7 1.73 1' }),
svgEl('circle', { cx: '12', cy: '12', r: '2' }),
svgEl('circle', { cx: '12', cy: '12', r: '8' }),
],
);
}

View File

@@ -6,8 +6,6 @@ export function renderLoaderCircleIcon24() {
'svg', 'svg',
{ {
xmlns: NS, xmlns: NS,
width: '24',
height: '24',
viewBox: '0 0 24 24', viewBox: '0 0 24 24',
fill: 'none', fill: 'none',
stroke: 'currentColor', stroke: 'currentColor',

View File

@@ -0,0 +1,34 @@
import { svgEl } from '../helpers';
export function renderPauseIcon24() {
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-pause-icon lucide-pause',
},
[
svgEl('rect', {
x: '14',
y: '3',
width: '5',
height: '18',
rx: '1',
}),
svgEl('rect', {
x: '5',
y: '3',
width: '5',
height: '18',
rx: '1',
}),
],
);
}

View File

@@ -0,0 +1,23 @@
import { svgEl } from '../helpers';
export function renderPlayIcon24() {
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-play-icon lucide-play',
},
[
svgEl('path', {
d: 'M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z',
}),
],
);
}

View File

@@ -0,0 +1,26 @@
import { svgEl } from '../helpers';
export function renderRotateCcwIcon24() {
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-rotate-ccw-icon lucide-rotate-ccw',
},
[
svgEl('path', {
d: 'M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8',
}),
svgEl('path', {
d: 'M3 3v5h5',
}),
],
);
}

View File

@@ -0,0 +1,22 @@
import { svgEl } from '../helpers';
export function renderSearchIcon24() {
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-search-icon lucide-search',
},
[
svgEl('path', { d: 'm21 21-4.34-4.34' }),
svgEl('circle', { cx: '11', cy: '11', r: '8' }),
],
);
}

View File

@@ -0,0 +1,30 @@
import { svgEl } from '../helpers';
export function renderSquareChartGanttIcon24() {
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-square-chart-gantt-icon lucide-square-chart-gantt',
},
[
svgEl('rect', {
width: '18',
height: '18',
x: '3',
y: '3',
rx: '2',
}),
svgEl('path', { d: 'M9 8h7' }),
svgEl('path', { d: 'M8 12h6' }),
svgEl('path', { d: 'M11 16h5' }),
],
);
}

View File

@@ -0,0 +1,69 @@
import { insertIf } from '../../helpers';
import { renderLoaderCircleIcon24 } from '../../icons';
interface IRenderButtonProps {
classNames?: string[];
disabled?: boolean;
loading?: boolean;
icon?: () => SVGSVGElement;
onClick: () => void;
text: string;
}
export function renderButton({
classNames = [],
disabled,
loading,
onClick,
text,
icon,
}: IRenderButtonProps) {
const hasIcon = !!loading || !!icon;
function getWrappedIcon() {
const iconWrap = E('span', {
class: 'pdk-partial-button__icon',
});
if (loading) {
iconWrap.appendChild(renderLoaderCircleIcon24());
return iconWrap;
}
if (icon) {
iconWrap.appendChild(icon());
return iconWrap;
}
return iconWrap;
}
function getClass() {
return [
'btn',
'pdk-partial-button',
...insertIf(Boolean(disabled), ['pdk-partial-button--disabled']),
...insertIf(Boolean(loading), ['pdk-partial-button--loading']),
...insertIf(Boolean(hasIcon), ['pdk-partial-button--with-icon']),
...classNames,
]
.filter(Boolean)
.join(' ');
}
function getDisabled() {
if (loading || disabled) {
return true;
}
return undefined;
}
return E(
'button',
{ class: getClass(), disabled: getDisabled(), click: onClick },
[...insertIf(hasIcon, [getWrappedIcon()]), E('span', {}, text)],
);
}

View File

@@ -0,0 +1,33 @@
// language=CSS
export const styles = `
.pdk-partial-button {
text-align: center;
}
.pdk-partial-button--with-icon {
display: flex;
align-items: center;
justify-content: center;
}
.pdk-partial-button--loading {
}
.pdk-partial-button--disabled {
}
.pdk-partial-button__icon {
margin-right: 5px;
}
.pdk-partial-button__icon {
display: flex;
align-items: center;
justify-content: center;
}
.pdk-partial-button__icon svg {
width: 16px;
height: 16px;
}
`;

View File

@@ -0,0 +1,7 @@
import { styles as ButtonStyles } from './button/styles';
export * from './button/renderButton';
export const PartialStyles = `
${ButtonStyles}
`;

View File

@@ -12,10 +12,17 @@ export async function callBaseMethod<T>(
}); });
if (response.stdout) { if (response.stdout) {
try {
return { return {
success: true, success: true,
data: JSON.parse(response.stdout) as T, data: JSON.parse(response.stdout) as T,
}; };
} catch (_e) {
return {
success: true,
data: response.stdout as T,
};
}
} }
return { return {

View File

@@ -44,16 +44,11 @@ export const PodkopShellMethods = {
group, group,
proxy, proxy,
]), ]),
restart: async () => restart: async () => callBaseMethod<unknown>(Podkop.AvailableMethods.RESTART),
callBaseMethod<unknown>(Podkop.AvailableMethods.RESTART), start: async () => callBaseMethod<unknown>(Podkop.AvailableMethods.START),
start: async () => stop: async () => callBaseMethod<unknown>(Podkop.AvailableMethods.STOP),
callBaseMethod<unknown>(Podkop.AvailableMethods.START), enable: async () => callBaseMethod<unknown>(Podkop.AvailableMethods.ENABLE),
stop: async () => disable: async () => callBaseMethod<unknown>(Podkop.AvailableMethods.DISABLE),
callBaseMethod<unknown>(Podkop.AvailableMethods.STOP),
enable: async () =>
callBaseMethod<unknown>(Podkop.AvailableMethods.ENABLE),
disable: async () =>
callBaseMethod<unknown>(Podkop.AvailableMethods.DISABLE),
globalCheck: async () => globalCheck: async () =>
callBaseMethod<unknown>(Podkop.AvailableMethods.GLOBAL_CHECK), callBaseMethod<unknown>(Podkop.AvailableMethods.GLOBAL_CHECK),
showSingBoxConfig: async () => showSingBoxConfig: async () =>

View File

@@ -171,6 +171,16 @@ export interface StoreType {
loading: boolean; loading: boolean;
}; };
diagnosticsChecks: Array<IDiagnosticsChecksStoreItem>; diagnosticsChecks: Array<IDiagnosticsChecksStoreItem>;
diagnosticsActions: {
restart: { loading: boolean };
start: { loading: boolean };
stop: { loading: boolean };
enable: { loading: boolean };
disable: { loading: boolean };
globalCheck: { loading: boolean };
viewLogs: { loading: boolean };
showSingBoxConfig: { loading: boolean };
};
} }
const initialStore: StoreType = { const initialStore: StoreType = {

View File

@@ -6,8 +6,34 @@ import { StoreType } from '../../services';
export const initialDiagnosticStore: Pick< export const initialDiagnosticStore: Pick<
StoreType, StoreType,
'diagnosticsChecks' | 'diagnosticsRunAction' 'diagnosticsChecks' | 'diagnosticsRunAction' | 'diagnosticsActions'
> = { > = {
diagnosticsActions: {
restart: {
loading: false,
},
start: {
loading: false,
},
stop: {
loading: false,
},
enable: {
loading: false,
},
disable: {
loading: false,
},
globalCheck: {
loading: false,
},
viewLogs: {
loading: false,
},
showSingBoxConfig: {
loading: false,
},
},
diagnosticsRunAction: { loading: false }, diagnosticsRunAction: { loading: false },
diagnosticsChecks: [ diagnosticsChecks: [
{ {

View File

@@ -11,6 +11,7 @@ import {
renderRunAction, renderRunAction,
renderSystemInfo, renderSystemInfo,
} from './partials'; } from './partials';
import { PodkopShellMethods } from '../../methods';
function renderDiagnosticsChecks() { function renderDiagnosticsChecks() {
console.log('renderDiagnosticsChecks'); console.log('renderDiagnosticsChecks');
@@ -44,12 +45,174 @@ function renderDiagnosticRunActionWidget() {
}); });
} }
async function handleRestart() {
const diagnosticsActions = store.get().diagnosticsActions;
store.set({
diagnosticsActions: {
...diagnosticsActions,
restart: { loading: true },
},
});
try {
await PodkopShellMethods.restart();
} catch (e) {
console.log('handleRestart - e', e);
} finally {
store.set({
diagnosticsActions: {
...diagnosticsActions,
restart: { loading: false },
},
});
location.reload();
}
}
async function handleStop() {
const diagnosticsActions = store.get().diagnosticsActions;
store.set({
diagnosticsActions: {
...diagnosticsActions,
stop: { loading: true },
},
});
try {
await PodkopShellMethods.stop();
} catch (e) {
console.log('handleStop - e', e);
} finally {
store.set({
diagnosticsActions: {
...diagnosticsActions,
stop: { loading: false },
},
});
// TODO actualize dashboard
}
}
async function handleStart() {
const diagnosticsActions = store.get().diagnosticsActions;
store.set({
diagnosticsActions: {
...diagnosticsActions,
start: { loading: true },
},
});
try {
await PodkopShellMethods.start();
} catch (e) {
console.log('handleStart - e', e);
} finally {
store.set({
diagnosticsActions: {
...diagnosticsActions,
start: { loading: false },
},
});
location.reload();
}
}
async function handleEnable() {
const diagnosticsActions = store.get().diagnosticsActions;
store.set({
diagnosticsActions: {
...diagnosticsActions,
enable: { loading: true },
},
});
try {
await PodkopShellMethods.enable();
} catch (e) {
console.log('handleEnable - e', e);
} finally {
store.set({
diagnosticsActions: {
...diagnosticsActions,
enable: { loading: false },
},
});
//TODO actualize dashboard
}
}
async function handleDisable() {
const diagnosticsActions = store.get().diagnosticsActions;
store.set({
diagnosticsActions: {
...diagnosticsActions,
disable: { loading: true },
},
});
try {
await PodkopShellMethods.disable();
} catch (e) {
console.log('handleDisable - e', e);
} finally {
store.set({
diagnosticsActions: {
...diagnosticsActions,
disable: { loading: false },
},
});
//TODO actualize dashboard
}
}
function renderDiagnosticAvailableActionsWidget() { function renderDiagnosticAvailableActionsWidget() {
const diagnosticsActions = store.get().diagnosticsActions;
console.log('renderDiagnosticActionsWidget'); console.log('renderDiagnosticActionsWidget');
const container = document.getElementById('pdk_diagnostic-page-actions'); const container = document.getElementById('pdk_diagnostic-page-actions');
const renderedActions = renderAvailableActions(); const renderedActions = renderAvailableActions({
restart: {
loading: diagnosticsActions.restart.loading,
visible: true,
onClick: handleRestart,
},
start: {
loading: diagnosticsActions.start.loading,
visible: true,
onClick: handleStart,
},
stop: {
loading: diagnosticsActions.stop.loading,
visible: true,
onClick: handleStop,
},
enable: {
loading: diagnosticsActions.enable.loading,
visible: true,
onClick: handleEnable,
},
disable: {
loading: diagnosticsActions.disable.loading,
visible: true,
onClick: handleDisable,
},
globalCheck: {
loading: diagnosticsActions.globalCheck.loading,
visible: true,
onClick: () => {},
},
viewLogs: {
loading: diagnosticsActions.viewLogs.loading,
visible: true,
onClick: () => {},
},
showSingBoxConfig: {
loading: diagnosticsActions.showSingBoxConfig.loading,
visible: true,
onClick: () => {},
},
});
return preserveScrollForPage(() => { return preserveScrollForPage(() => {
container!.replaceChildren(renderedActions); container!.replaceChildren(renderedActions);
@@ -103,6 +266,10 @@ async function onStoreUpdate(
if (diff.diagnosticsRunAction) { if (diff.diagnosticsRunAction) {
renderDiagnosticRunActionWidget(); renderDiagnosticRunActionWidget();
} }
if (diff.diagnosticsActions) {
renderDiagnosticAvailableActionsWidget();
}
} }
async function runChecks() { async function runChecks() {

View File

@@ -1,11 +1,113 @@
export function renderAvailableActions() { import { renderButton } from '../../../../partials';
import {
renderCircleCheckBigIcon24,
renderCirclePlayIcon24,
renderCircleStopIcon24,
renderCogIcon24,
renderPauseIcon24,
renderPlayIcon24,
renderRotateCcwIcon24,
renderSquareChartGanttIcon24,
} from '../../../../icons';
import { insertIf } from '../../../../helpers';
interface ActionProps {
loading: boolean;
visible: boolean;
onClick: () => void;
}
interface IRenderAvailableActionsProps {
restart: ActionProps;
start: ActionProps;
stop: ActionProps;
enable: ActionProps;
disable: ActionProps;
globalCheck: ActionProps;
viewLogs: ActionProps;
showSingBoxConfig: ActionProps;
}
export function renderAvailableActions({
restart,
start,
stop,
enable,
disable,
globalCheck,
viewLogs,
showSingBoxConfig,
}: IRenderAvailableActionsProps) {
return E('div', { class: 'pdk_diagnostic-page__right-bar__actions' }, [ return E('div', { class: 'pdk_diagnostic-page__right-bar__actions' }, [
E('b', {}, 'Available actions'), E('b', {}, 'Available actions'),
E('button', { class: 'btn' }, 'Restart podkop'), ...insertIf(restart.visible, [
E('button', { class: 'btn' }, 'Stop podkop'), renderButton({
E('button', { class: 'btn' }, 'Disable podkop'), classNames: ['cbi-button-apply'],
E('button', { class: 'btn' }, 'Get global check'), onClick: restart.onClick,
E('button', { class: 'btn' }, 'View logs'), icon: renderRotateCcwIcon24,
E('button', { class: 'btn' }, 'Show sing-box config'), text: 'Restart podkop',
loading: restart.loading,
}),
]),
...insertIf(stop.visible, [
renderButton({
classNames: ['cbi-button-remove'],
onClick: stop.onClick,
icon: renderCircleStopIcon24,
text: 'Stop podkop',
loading: stop.loading,
}),
]),
...insertIf(start.visible, [
renderButton({
classNames: ['cbi-button-save'],
onClick: start.onClick,
icon: renderCirclePlayIcon24,
text: 'Start podkop',
loading: start.loading,
}),
]),
...insertIf(disable.visible, [
renderButton({
classNames: ['cbi-button-remove'],
onClick: disable.onClick,
icon: renderPauseIcon24,
text: 'Disable podkop',
loading: disable.loading,
}),
]),
...insertIf(enable.visible, [
renderButton({
classNames: ['cbi-button-save'],
onClick: enable.onClick,
icon: renderPlayIcon24,
text: 'Enable podkop',
loading: enable.loading,
}),
]),
...insertIf(globalCheck.visible, [
renderButton({
onClick: globalCheck.onClick,
icon: renderCircleCheckBigIcon24,
text: 'Get global check',
loading: globalCheck.loading,
}),
]),
...insertIf(viewLogs.visible, [
renderButton({
onClick: viewLogs.onClick,
icon: renderSquareChartGanttIcon24,
text: 'View logs',
loading: viewLogs.loading,
}),
]),
...insertIf(showSingBoxConfig.visible, [
renderButton({
onClick: showSingBoxConfig.onClick,
icon: renderCogIcon24,
text: 'Show sing-box config',
loading: showSingBoxConfig.loading,
}),
]),
]); ]);
} }

View File

@@ -1,3 +1,6 @@
import { renderButton } from '../../../../partials';
import { renderSearchIcon24 } from '../../../../icons';
interface IRenderDiagnosticRunActionProps { interface IRenderDiagnosticRunActionProps {
loading: boolean; loading: boolean;
click: () => void; click: () => void;
@@ -8,10 +11,12 @@ export function renderRunAction({
click, click,
}: IRenderDiagnosticRunActionProps) { }: IRenderDiagnosticRunActionProps) {
return E('div', { class: 'pdk_diagnostic-page__run_check_wrapper' }, [ return E('div', { class: 'pdk_diagnostic-page__run_check_wrapper' }, [
E( renderButton({
'button', text: 'Run Diagnostic',
{ class: 'btn', disabled: loading ? true : undefined, click }, onClick: click,
loading ? _('Running... please wait') : _('Run Diagnostic'), icon: renderSearchIcon24,
), loading,
classNames: ['cbi-button-apply'],
}),
]); ]);
} }

View File

@@ -1,9 +1,11 @@
// language=CSS // language=CSS
import { DashboardTab, DiagnosticTab } from './podkop'; import { DashboardTab, DiagnosticTab } from './podkop';
import { PartialStyles } from './partials';
export const GlobalStyles = ` export const GlobalStyles = `
${DashboardTab.styles} ${DashboardTab.styles}
${DiagnosticTab.styles} ${DiagnosticTab.styles}
${PartialStyles}
/* Hide extra H3 for settings tab */ /* Hide extra H3 for settings tab */

View File

@@ -411,10 +411,17 @@ async function callBaseMethod(method, args = []) {
timeout: 1e4 timeout: 1e4
}); });
if (response.stdout) { if (response.stdout) {
try {
return { return {
success: true, success: true,
data: JSON.parse(response.stdout) data: JSON.parse(response.stdout)
}; };
} catch (_e) {
return {
success: true,
data: response.stdout
};
}
} }
return { return {
success: false, success: false,
@@ -895,6 +902,32 @@ var DIAGNOSTICS_CHECKS_MAP = {
// src/podkop/tabs/diagnostic/diagnostic.store.ts // src/podkop/tabs/diagnostic/diagnostic.store.ts
var initialDiagnosticStore = { var initialDiagnosticStore = {
diagnosticsActions: {
restart: {
loading: false
},
start: {
loading: false
},
stop: {
loading: false
},
enable: {
loading: false
},
disable: {
loading: false
},
globalCheck: {
loading: false
},
viewLogs: {
loading: false
},
showSingBoxConfig: {
loading: false
}
},
diagnosticsRunAction: { loading: false }, diagnosticsRunAction: { loading: false },
diagnosticsChecks: [ diagnosticsChecks: [
{ {
@@ -2283,19 +2316,40 @@ async function runFakeIPCheck() {
}); });
} }
// src/podkop/tabs/diagnostic/partials/renderAvailableActions.ts // src/partials/button/styles.ts
function renderAvailableActions() { var styles2 = `
return E("div", { class: "pdk_diagnostic-page__right-bar__actions" }, [ .pdk-partial-button {
E("b", {}, "Available actions"), text-align: center;
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")
]);
} }
.pdk-partial-button--with-icon {
display: flex;
align-items: center;
justify-content: center;
}
.pdk-partial-button--loading {
}
.pdk-partial-button--disabled {
}
.pdk-partial-button__icon {
margin-right: 5px;
}
.pdk-partial-button__icon {
display: flex;
align-items: center;
justify-content: center;
}
.pdk-partial-button__icon svg {
width: 16px;
height: 16px;
}
`;
// src/icons/renderLoaderCircleIcon24.ts // src/icons/renderLoaderCircleIcon24.ts
function renderLoaderCircleIcon24() { function renderLoaderCircleIcon24() {
const NS = "http://www.w3.org/2000/svg"; const NS = "http://www.w3.org/2000/svg";
@@ -2303,8 +2357,6 @@ function renderLoaderCircleIcon24() {
"svg", "svg",
{ {
xmlns: NS, xmlns: NS,
width: "24",
height: "24",
viewBox: "0 0 24 24", viewBox: "0 0 24 24",
fill: "none", fill: "none",
stroke: "currentColor", stroke: "currentColor",
@@ -2532,6 +2584,398 @@ function renderTriangleAlertIcon24() {
); );
} }
// src/icons/renderPauseIcon24.ts
function renderPauseIcon24() {
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-pause-icon lucide-pause"
},
[
svgEl("rect", {
x: "14",
y: "3",
width: "5",
height: "18",
rx: "1"
}),
svgEl("rect", {
x: "5",
y: "3",
width: "5",
height: "18",
rx: "1"
})
]
);
}
// src/icons/renderPlayIcon24.ts
function renderPlayIcon24() {
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-play-icon lucide-play"
},
[
svgEl("path", {
d: "M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z"
})
]
);
}
// src/icons/renderRotateCcwIcon24.ts
function renderRotateCcwIcon24() {
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-rotate-ccw-icon lucide-rotate-ccw"
},
[
svgEl("path", {
d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"
}),
svgEl("path", {
d: "M3 3v5h5"
})
]
);
}
// src/icons/renderCircleStopIcon24.ts
function renderCircleStopIcon24() {
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-circle-stop-icon lucide-circle-stop"
},
[
svgEl("circle", {
cx: "12",
cy: "12",
r: "10"
}),
svgEl("rect", {
x: "9",
y: "9",
width: "6",
height: "6",
rx: "1"
})
]
);
}
// src/icons/renderCirclePlayIcon24.ts
function renderCirclePlayIcon24() {
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-circle-play-icon lucide-circle-play"
},
[
svgEl("path", {
d: "M9 9.003a1 1 0 0 1 1.517-.859l4.997 2.997a1 1 0 0 1 0 1.718l-4.997 2.997A1 1 0 0 1 9 14.996z"
}),
svgEl("circle", {
cx: "12",
cy: "12",
r: "10"
})
]
);
}
// src/icons/renderCircleCheckBigIcon24.ts
function renderCircleCheckBigIcon24() {
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-circle-check-big-icon lucide-circle-check-big"
},
[
svgEl("path", {
d: "M21.801 10A10 10 0 1 1 17 3.335"
}),
svgEl("path", {
d: "m9 11 3 3L22 4"
})
]
);
}
// src/icons/renderSquareChartGanttIcon24.ts
function renderSquareChartGanttIcon24() {
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-square-chart-gantt-icon lucide-square-chart-gantt"
},
[
svgEl("rect", {
width: "18",
height: "18",
x: "3",
y: "3",
rx: "2"
}),
svgEl("path", { d: "M9 8h7" }),
svgEl("path", { d: "M8 12h6" }),
svgEl("path", { d: "M11 16h5" })
]
);
}
// src/icons/renderCogIcon24.ts
function renderCogIcon24() {
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-cog-icon lucide-cog"
},
[
svgEl("path", { d: "M11 10.27 7 3.34" }),
svgEl("path", { d: "m11 13.73-4 6.93" }),
svgEl("path", { d: "M12 22v-2" }),
svgEl("path", { d: "M12 2v2" }),
svgEl("path", { d: "M14 12h8" }),
svgEl("path", { d: "m17 20.66-1-1.73" }),
svgEl("path", { d: "m17 3.34-1 1.73" }),
svgEl("path", { d: "M2 12h2" }),
svgEl("path", { d: "m20.66 17-1.73-1" }),
svgEl("path", { d: "m20.66 7-1.73 1" }),
svgEl("path", { d: "m3.34 17 1.73-1" }),
svgEl("path", { d: "m3.34 7 1.73 1" }),
svgEl("circle", { cx: "12", cy: "12", r: "2" }),
svgEl("circle", { cx: "12", cy: "12", r: "8" })
]
);
}
// src/icons/renderSearchIcon24.ts
function renderSearchIcon24() {
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-search-icon lucide-search"
},
[
svgEl("path", { d: "m21 21-4.34-4.34" }),
svgEl("circle", { cx: "11", cy: "11", r: "8" })
]
);
}
// src/partials/button/renderButton.ts
function renderButton({
classNames = [],
disabled,
loading,
onClick,
text,
icon
}) {
const hasIcon = !!loading || !!icon;
function getWrappedIcon() {
const iconWrap = E("span", {
class: "pdk-partial-button__icon"
});
if (loading) {
iconWrap.appendChild(renderLoaderCircleIcon24());
return iconWrap;
}
if (icon) {
iconWrap.appendChild(icon());
return iconWrap;
}
return iconWrap;
}
function getClass() {
return [
"btn",
"pdk-partial-button",
...insertIf(Boolean(disabled), ["pdk-partial-button--disabled"]),
...insertIf(Boolean(loading), ["pdk-partial-button--loading"]),
...insertIf(Boolean(hasIcon), ["pdk-partial-button--with-icon"]),
...classNames
].filter(Boolean).join(" ");
}
function getDisabled() {
if (loading || disabled) {
return true;
}
return void 0;
}
return E(
"button",
{ class: getClass(), disabled: getDisabled(), click: onClick },
[...insertIf(hasIcon, [getWrappedIcon()]), E("span", {}, text)]
);
}
// src/partials/index.ts
var PartialStyles = `
${styles2}
`;
// src/podkop/tabs/diagnostic/partials/renderAvailableActions.ts
function renderAvailableActions({
restart,
start,
stop,
enable,
disable,
globalCheck,
viewLogs,
showSingBoxConfig
}) {
return E("div", { class: "pdk_diagnostic-page__right-bar__actions" }, [
E("b", {}, "Available actions"),
...insertIf(restart.visible, [
renderButton({
classNames: ["cbi-button-apply"],
onClick: restart.onClick,
icon: renderRotateCcwIcon24,
text: "Restart podkop",
loading: restart.loading
})
]),
...insertIf(stop.visible, [
renderButton({
classNames: ["cbi-button-remove"],
onClick: stop.onClick,
icon: renderCircleStopIcon24,
text: "Stop podkop",
loading: stop.loading
})
]),
...insertIf(start.visible, [
renderButton({
classNames: ["cbi-button-save"],
onClick: start.onClick,
icon: renderCirclePlayIcon24,
text: "Start podkop",
loading: start.loading
})
]),
...insertIf(disable.visible, [
renderButton({
classNames: ["cbi-button-remove"],
onClick: disable.onClick,
icon: renderPauseIcon24,
text: "Disable podkop",
loading: disable.loading
})
]),
...insertIf(enable.visible, [
renderButton({
classNames: ["cbi-button-save"],
onClick: enable.onClick,
icon: renderPlayIcon24,
text: "Enable podkop",
loading: enable.loading
})
]),
...insertIf(globalCheck.visible, [
renderButton({
onClick: globalCheck.onClick,
icon: renderCircleCheckBigIcon24,
text: "Get global check",
loading: globalCheck.loading
})
]),
...insertIf(viewLogs.visible, [
renderButton({
onClick: viewLogs.onClick,
icon: renderSquareChartGanttIcon24,
text: "View logs",
loading: viewLogs.loading
})
]),
...insertIf(showSingBoxConfig.visible, [
renderButton({
onClick: showSingBoxConfig.onClick,
icon: renderCogIcon24,
text: "Show sing-box config",
loading: showSingBoxConfig.loading
})
])
]);
}
// src/podkop/tabs/diagnostic/partials/renderCheckSection.ts // src/podkop/tabs/diagnostic/partials/renderCheckSection.ts
function renderCheckSummary(items) { function renderCheckSummary(items) {
if (!items.length) { if (!items.length) {
@@ -2693,11 +3137,13 @@ function renderRunAction({
click click
}) { }) {
return E("div", { class: "pdk_diagnostic-page__run_check_wrapper" }, [ return E("div", { class: "pdk_diagnostic-page__run_check_wrapper" }, [
E( renderButton({
"button", text: "Run Diagnostic",
{ class: "btn", disabled: loading ? true : void 0, click }, onClick: click,
loading ? _("Running... please wait") : _("Run Diagnostic") icon: renderSearchIcon24,
) loading,
classNames: ["cbi-button-apply"]
})
]); ]);
} }
@@ -2742,10 +3188,162 @@ function renderDiagnosticRunActionWidget() {
container.replaceChildren(renderedAction); container.replaceChildren(renderedAction);
}); });
} }
async function handleRestart() {
const diagnosticsActions = store.get().diagnosticsActions;
store.set({
diagnosticsActions: {
...diagnosticsActions,
restart: { loading: true }
}
});
try {
await PodkopShellMethods.restart();
} catch (e) {
console.log("handleRestart - e", e);
} finally {
store.set({
diagnosticsActions: {
...diagnosticsActions,
restart: { loading: false }
}
});
location.reload();
}
}
async function handleStop() {
const diagnosticsActions = store.get().diagnosticsActions;
store.set({
diagnosticsActions: {
...diagnosticsActions,
stop: { loading: true }
}
});
try {
await PodkopShellMethods.stop();
} catch (e) {
console.log("handleStop - e", e);
} finally {
store.set({
diagnosticsActions: {
...diagnosticsActions,
stop: { loading: false }
}
});
}
}
async function handleStart() {
const diagnosticsActions = store.get().diagnosticsActions;
store.set({
diagnosticsActions: {
...diagnosticsActions,
start: { loading: true }
}
});
try {
await PodkopShellMethods.start();
} catch (e) {
console.log("handleStart - e", e);
} finally {
store.set({
diagnosticsActions: {
...diagnosticsActions,
start: { loading: false }
}
});
location.reload();
}
}
async function handleEnable() {
const diagnosticsActions = store.get().diagnosticsActions;
store.set({
diagnosticsActions: {
...diagnosticsActions,
enable: { loading: true }
}
});
try {
await PodkopShellMethods.enable();
} catch (e) {
console.log("handleEnable - e", e);
} finally {
store.set({
diagnosticsActions: {
...diagnosticsActions,
enable: { loading: false }
}
});
}
}
async function handleDisable() {
const diagnosticsActions = store.get().diagnosticsActions;
store.set({
diagnosticsActions: {
...diagnosticsActions,
disable: { loading: true }
}
});
try {
await PodkopShellMethods.disable();
} catch (e) {
console.log("handleDisable - e", e);
} finally {
store.set({
diagnosticsActions: {
...diagnosticsActions,
disable: { loading: false }
}
});
}
}
function renderDiagnosticAvailableActionsWidget() { function renderDiagnosticAvailableActionsWidget() {
const diagnosticsActions = store.get().diagnosticsActions;
console.log("renderDiagnosticActionsWidget"); console.log("renderDiagnosticActionsWidget");
const container = document.getElementById("pdk_diagnostic-page-actions"); const container = document.getElementById("pdk_diagnostic-page-actions");
const renderedActions = renderAvailableActions(); const renderedActions = renderAvailableActions({
restart: {
loading: diagnosticsActions.restart.loading,
visible: true,
onClick: handleRestart
},
start: {
loading: diagnosticsActions.start.loading,
visible: true,
onClick: handleStart
},
stop: {
loading: diagnosticsActions.stop.loading,
visible: true,
onClick: handleStop
},
enable: {
loading: diagnosticsActions.enable.loading,
visible: true,
onClick: handleEnable
},
disable: {
loading: diagnosticsActions.disable.loading,
visible: true,
onClick: handleDisable
},
globalCheck: {
loading: diagnosticsActions.globalCheck.loading,
visible: true,
onClick: () => {
}
},
viewLogs: {
loading: diagnosticsActions.viewLogs.loading,
visible: true,
onClick: () => {
}
},
showSingBoxConfig: {
loading: diagnosticsActions.showSingBoxConfig.loading,
visible: true,
onClick: () => {
}
}
});
return preserveScrollForPage(() => { return preserveScrollForPage(() => {
container.replaceChildren(renderedActions); container.replaceChildren(renderedActions);
}); });
@@ -2761,7 +3359,7 @@ function renderDiagnosticSystemInfoWidget() {
}, },
{ {
key: "Luci App", key: "Luci App",
value: PODKOP_LUCI_APP_VERSION value: "1"
}, },
{ {
key: "Sing-box", key: "Sing-box",
@@ -2788,6 +3386,9 @@ async function onStoreUpdate2(next, prev, diff) {
if (diff.diagnosticsRunAction) { if (diff.diagnosticsRunAction) {
renderDiagnosticRunActionWidget(); renderDiagnosticRunActionWidget();
} }
if (diff.diagnosticsActions) {
renderDiagnosticAvailableActionsWidget();
}
} }
async function runChecks() { async function runChecks() {
try { try {
@@ -2805,8 +3406,6 @@ async function runChecks() {
store.set({ diagnosticsRunAction: { loading: false } }); store.set({ diagnosticsRunAction: { loading: false } });
} }
} }
async function test() {
}
async function initController2() { async function initController2() {
onMount("diagnostic-status").then(() => { onMount("diagnostic-status").then(() => {
console.log("diagnostic controller initialized."); console.log("diagnostic controller initialized.");
@@ -2816,12 +3415,11 @@ async function initController2() {
renderDiagnosticRunActionWidget(); renderDiagnosticRunActionWidget();
renderDiagnosticAvailableActionsWidget(); renderDiagnosticAvailableActionsWidget();
renderDiagnosticSystemInfoWidget(); renderDiagnosticSystemInfoWidget();
test();
}); });
} }
// src/podkop/tabs/diagnostic/styles.ts // src/podkop/tabs/diagnostic/styles.ts
var styles2 = ` var styles3 = `
#cbi-podkop-diagnostic-_mount_node > div { #cbi-podkop-diagnostic-_mount_node > div {
width: 100%; width: 100%;
@@ -2967,13 +3565,14 @@ var styles2 = `
var DiagnosticTab = { var DiagnosticTab = {
render: render2, render: render2,
initController: initController2, initController: initController2,
styles: styles2 styles: styles3
}; };
// src/styles.ts // src/styles.ts
var GlobalStyles = ` var GlobalStyles = `
${DashboardTab.styles} ${DashboardTab.styles}
${DiagnosticTab.styles} ${DiagnosticTab.styles}
${PartialStyles}
/* Hide extra H3 for settings tab */ /* Hide extra H3 for settings tab */