feat: actualize system actions behavior

This commit is contained in:
divocat
2025-10-15 21:13:52 +03:00
parent c35a174708
commit c0b35c865d
7 changed files with 184 additions and 116 deletions

View File

@@ -0,0 +1,29 @@
import { PodkopShellMethods } from '../methods';
import { store } from '../services';
export async function fetchServicesInfo() {
const [podkop, singbox] = await Promise.all([
PodkopShellMethods.getStatus(),
PodkopShellMethods.getSingBoxStatus(),
]);
if (!podkop.success || !singbox.success) {
store.set({
servicesInfoWidget: {
loading: false,
failed: true,
data: { singbox: 0, podkop: 0 },
},
});
}
if (podkop.success && singbox.success) {
store.set({
servicesInfoWidget: {
loading: false,
failed: false,
data: { singbox: singbox.data.running, podkop: podkop.data.enabled },
},
});
}
}

View File

@@ -0,0 +1 @@
export * from './fetchServicesInfo';

View File

@@ -7,6 +7,7 @@ import { prettyBytes } from '../../../helpers/prettyBytes';
import { CustomPodkopMethods, PodkopShellMethods } from '../../methods'; import { CustomPodkopMethods, PodkopShellMethods } from '../../methods';
import { socket, store, StoreType } from '../../services'; import { socket, store, StoreType } from '../../services';
import { renderSections, renderWidget } from './partials'; import { renderSections, renderWidget } from './partials';
import { fetchServicesInfo } from '../../fetchers';
// Fetchers // Fetchers
@@ -36,33 +37,6 @@ async function fetchDashboardSections() {
}); });
} }
async function fetchServicesInfo() {
const [podkop, singbox] = await Promise.all([
PodkopShellMethods.getStatus(),
PodkopShellMethods.getSingBoxStatus(),
]);
if (!podkop.success || !singbox.success) {
store.set({
servicesInfoWidget: {
loading: false,
failed: true,
data: { singbox: 0, podkop: 0 },
},
});
}
if (podkop.success && singbox.success) {
store.set({
servicesInfoWidget: {
loading: false,
failed: false,
data: { singbox: singbox.data.running, podkop: podkop.data.enabled },
},
});
}
}
async function connectToClashSockets() { async function connectToClashSockets() {
socket.subscribe( socket.subscribe(
`${getClashWsUrl()}/traffic?token=`, `${getClashWsUrl()}/traffic?token=`,

View File

@@ -40,10 +40,10 @@ export async function runDnsCheck() {
Boolean(data.dns_status); Boolean(data.dns_status);
const atLeastOneGood = const atLeastOneGood =
Boolean(data.dns_on_router) || Boolean(data.dns_on_router) ||
Boolean(data.dhcp_has_dns_server) || Boolean(data.dhcp_has_dns_server) ||
Boolean(data.bootstrap_dns_status) || Boolean(data.bootstrap_dns_status) ||
Boolean(data.dns_status); Boolean(data.dns_status);
console.log('dnsChecks', dnsChecks); console.log('dnsChecks', dnsChecks);
@@ -88,7 +88,7 @@ export async function runDnsCheck() {
}, },
{ {
state: data.dhcp_has_dns_server ? 'success' : 'error', state: data.dhcp_has_dns_server ? 'success' : 'error',
key: _('Dhcp has dns server'), key: _('DHCP has DNS server'),
value: '', value: '',
}, },
], ],

View File

@@ -12,6 +12,7 @@ import {
renderSystemInfo, renderSystemInfo,
} from './partials'; } from './partials';
import { PodkopShellMethods } from '../../methods'; import { PodkopShellMethods } from '../../methods';
import { fetchServicesInfo } from '../../fetchers';
function renderDiagnosticsChecks() { function renderDiagnosticsChecks() {
console.log('renderDiagnosticsChecks'); console.log('renderDiagnosticsChecks');
@@ -59,13 +60,15 @@ async function handleRestart() {
} catch (e) { } catch (e) {
console.log('handleRestart - e', e); console.log('handleRestart - e', e);
} finally { } finally {
store.set({ setTimeout(async () => {
diagnosticsActions: { await fetchServicesInfo();
...diagnosticsActions, store.set({
restart: { loading: false }, diagnosticsActions: {
}, ...diagnosticsActions,
}); restart: { loading: false },
location.reload(); },
});
}, 5000);
} }
} }
@@ -83,13 +86,13 @@ async function handleStop() {
} catch (e) { } catch (e) {
console.log('handleStop - e', e); console.log('handleStop - e', e);
} finally { } finally {
await fetchServicesInfo();
store.set({ store.set({
diagnosticsActions: { diagnosticsActions: {
...diagnosticsActions, ...diagnosticsActions,
stop: { loading: false }, stop: { loading: false },
}, },
}); });
// TODO actualize dashboard
} }
} }
@@ -107,13 +110,15 @@ async function handleStart() {
} catch (e) { } catch (e) {
console.log('handleStart - e', e); console.log('handleStart - e', e);
} finally { } finally {
store.set({ setTimeout(async () => {
diagnosticsActions: { await fetchServicesInfo();
...diagnosticsActions, store.set({
start: { loading: false }, diagnosticsActions: {
}, ...diagnosticsActions,
}); start: { loading: false },
location.reload(); },
});
}, 5000);
} }
} }
@@ -131,13 +136,13 @@ async function handleEnable() {
} catch (e) { } catch (e) {
console.log('handleEnable - e', e); console.log('handleEnable - e', e);
} finally { } finally {
await fetchServicesInfo();
store.set({ store.set({
diagnosticsActions: { diagnosticsActions: {
...diagnosticsActions, ...diagnosticsActions,
enable: { loading: false }, enable: { loading: false },
}, },
}); });
//TODO actualize dashboard
} }
} }
@@ -155,20 +160,29 @@ async function handleDisable() {
} catch (e) { } catch (e) {
console.log('handleDisable - e', e); console.log('handleDisable - e', e);
} finally { } finally {
await fetchServicesInfo();
store.set({ store.set({
diagnosticsActions: { diagnosticsActions: {
...diagnosticsActions, ...diagnosticsActions,
disable: { loading: false }, disable: { loading: false },
}, },
}); });
//TODO actualize dashboard
} }
} }
function renderDiagnosticAvailableActionsWidget() { function renderDiagnosticAvailableActionsWidget() {
const diagnosticsActions = store.get().diagnosticsActions; const diagnosticsActions = store.get().diagnosticsActions;
const servicesInfoWidget = store.get().servicesInfoWidget;
console.log('renderDiagnosticActionsWidget'); console.log('renderDiagnosticActionsWidget');
const podkopEnabled = Boolean(servicesInfoWidget.data.podkop);
const singBoxRunning = Boolean(servicesInfoWidget.data.singbox);
const atLeastOneServiceCommandLoading =
servicesInfoWidget.loading ||
diagnosticsActions.restart.loading ||
diagnosticsActions.start.loading ||
diagnosticsActions.stop.loading;
const container = document.getElementById('pdk_diagnostic-page-actions'); const container = document.getElementById('pdk_diagnostic-page-actions');
const renderedActions = renderAvailableActions({ const renderedActions = renderAvailableActions({
@@ -176,41 +190,49 @@ function renderDiagnosticAvailableActionsWidget() {
loading: diagnosticsActions.restart.loading, loading: diagnosticsActions.restart.loading,
visible: true, visible: true,
onClick: handleRestart, onClick: handleRestart,
disabled: atLeastOneServiceCommandLoading,
}, },
start: { start: {
loading: diagnosticsActions.start.loading, loading: diagnosticsActions.start.loading,
visible: true, visible: !singBoxRunning,
onClick: handleStart, onClick: handleStart,
disabled: atLeastOneServiceCommandLoading,
}, },
stop: { stop: {
loading: diagnosticsActions.stop.loading, loading: diagnosticsActions.stop.loading,
visible: true, visible: singBoxRunning,
onClick: handleStop, onClick: handleStop,
disabled: atLeastOneServiceCommandLoading,
}, },
enable: { enable: {
loading: diagnosticsActions.enable.loading, loading: diagnosticsActions.enable.loading,
visible: true, visible: !podkopEnabled,
onClick: handleEnable, onClick: handleEnable,
disabled: atLeastOneServiceCommandLoading,
}, },
disable: { disable: {
loading: diagnosticsActions.disable.loading, loading: diagnosticsActions.disable.loading,
visible: true, visible: podkopEnabled,
onClick: handleDisable, onClick: handleDisable,
disabled: atLeastOneServiceCommandLoading,
}, },
globalCheck: { globalCheck: {
loading: diagnosticsActions.globalCheck.loading, loading: diagnosticsActions.globalCheck.loading,
visible: true, visible: true,
onClick: () => {}, onClick: () => {},
disabled: atLeastOneServiceCommandLoading,
}, },
viewLogs: { viewLogs: {
loading: diagnosticsActions.viewLogs.loading, loading: diagnosticsActions.viewLogs.loading,
visible: true, visible: true,
onClick: () => {}, onClick: () => {},
disabled: atLeastOneServiceCommandLoading,
}, },
showSingBoxConfig: { showSingBoxConfig: {
loading: diagnosticsActions.showSingBoxConfig.loading, loading: diagnosticsActions.showSingBoxConfig.loading,
visible: true, visible: true,
onClick: () => {}, onClick: () => {},
disabled: atLeastOneServiceCommandLoading,
}, },
}); });
@@ -267,7 +289,7 @@ async function onStoreUpdate(
renderDiagnosticRunActionWidget(); renderDiagnosticRunActionWidget();
} }
if (diff.diagnosticsActions) { if (diff.diagnosticsActions || diff.servicesInfoWidget) {
renderDiagnosticAvailableActionsWidget(); renderDiagnosticAvailableActionsWidget();
} }
} }
@@ -313,5 +335,8 @@ export async function initController(): Promise<void> {
// Initial system info render // Initial system info render
renderDiagnosticSystemInfoWidget(); renderDiagnosticSystemInfoWidget();
// Initial services info fetch
fetchServicesInfo();
}); });
} }

View File

@@ -14,6 +14,7 @@ import { insertIf } from '../../../../helpers';
interface ActionProps { interface ActionProps {
loading: boolean; loading: boolean;
visible: boolean; visible: boolean;
disabled: boolean;
onClick: () => void; onClick: () => void;
} }
@@ -47,6 +48,7 @@ export function renderAvailableActions({
icon: renderRotateCcwIcon24, icon: renderRotateCcwIcon24,
text: 'Restart podkop', text: 'Restart podkop',
loading: restart.loading, loading: restart.loading,
disabled: restart.disabled,
}), }),
]), ]),
...insertIf(stop.visible, [ ...insertIf(stop.visible, [
@@ -56,6 +58,7 @@ export function renderAvailableActions({
icon: renderCircleStopIcon24, icon: renderCircleStopIcon24,
text: 'Stop podkop', text: 'Stop podkop',
loading: stop.loading, loading: stop.loading,
disabled: stop.disabled,
}), }),
]), ]),
...insertIf(start.visible, [ ...insertIf(start.visible, [
@@ -65,6 +68,7 @@ export function renderAvailableActions({
icon: renderCirclePlayIcon24, icon: renderCirclePlayIcon24,
text: 'Start podkop', text: 'Start podkop',
loading: start.loading, loading: start.loading,
disabled: start.disabled,
}), }),
]), ]),
...insertIf(disable.visible, [ ...insertIf(disable.visible, [
@@ -72,8 +76,9 @@ export function renderAvailableActions({
classNames: ['cbi-button-remove'], classNames: ['cbi-button-remove'],
onClick: disable.onClick, onClick: disable.onClick,
icon: renderPauseIcon24, icon: renderPauseIcon24,
text: 'Disable podkop', text: 'Disable autostart',
loading: disable.loading, loading: disable.loading,
disabled: disable.disabled,
}), }),
]), ]),
...insertIf(enable.visible, [ ...insertIf(enable.visible, [
@@ -81,8 +86,9 @@ export function renderAvailableActions({
classNames: ['cbi-button-save'], classNames: ['cbi-button-save'],
onClick: enable.onClick, onClick: enable.onClick,
icon: renderPlayIcon24, icon: renderPlayIcon24,
text: 'Enable podkop', text: 'Enable autostart',
loading: enable.loading, loading: enable.loading,
disabled: enable.disabled,
}), }),
]), ]),
...insertIf(globalCheck.visible, [ ...insertIf(globalCheck.visible, [
@@ -91,6 +97,7 @@ export function renderAvailableActions({
icon: renderCircleCheckBigIcon24, icon: renderCircleCheckBigIcon24,
text: 'Get global check', text: 'Get global check',
loading: globalCheck.loading, loading: globalCheck.loading,
disabled: globalCheck.disabled,
}), }),
]), ]),
...insertIf(viewLogs.visible, [ ...insertIf(viewLogs.visible, [
@@ -99,6 +106,7 @@ export function renderAvailableActions({
icon: renderSquareChartGanttIcon24, icon: renderSquareChartGanttIcon24,
text: 'View logs', text: 'View logs',
loading: viewLogs.loading, loading: viewLogs.loading,
disabled: viewLogs.disabled,
}), }),
]), ]),
...insertIf(showSingBoxConfig.visible, [ ...insertIf(showSingBoxConfig.visible, [
@@ -107,6 +115,7 @@ export function renderAvailableActions({
icon: renderCogIcon24, icon: renderCogIcon24,
text: 'Show sing-box config', text: 'Show sing-box config',
loading: showSingBoxConfig.loading, loading: showSingBoxConfig.loading,
disabled: showSingBoxConfig.disabled,
}), }),
]), ]),
]); ]);

View File

@@ -1507,28 +1507,7 @@ function prettyBytes(n) {
return n + " " + unit; return n + " " + unit;
} }
// src/podkop/tabs/dashboard/initController.ts // src/podkop/fetchers/fetchServicesInfo.ts
async function fetchDashboardSections() {
const prev = store.get().sectionsWidget;
store.set({
sectionsWidget: {
...prev,
failed: false
}
});
const { data, success } = await CustomPodkopMethods.getDashboardSections();
if (!success) {
console.log("[fetchDashboardSections]: failed to fetch");
}
store.set({
sectionsWidget: {
latencyFetching: false,
loading: false,
failed: !success,
data
}
});
}
async function fetchServicesInfo() { async function fetchServicesInfo() {
const [podkop, singbox] = await Promise.all([ const [podkop, singbox] = await Promise.all([
PodkopShellMethods.getStatus(), PodkopShellMethods.getStatus(),
@@ -1553,6 +1532,29 @@ async function fetchServicesInfo() {
}); });
} }
} }
// src/podkop/tabs/dashboard/initController.ts
async function fetchDashboardSections() {
const prev = store.get().sectionsWidget;
store.set({
sectionsWidget: {
...prev,
failed: false
}
});
const { data, success } = await CustomPodkopMethods.getDashboardSections();
if (!success) {
console.log("[fetchDashboardSections]: failed to fetch");
}
store.set({
sectionsWidget: {
latencyFetching: false,
loading: false,
failed: !success,
data
}
});
}
async function connectToClashSockets() { async function connectToClashSockets() {
socket.subscribe( socket.subscribe(
`${getClashWsUrl()}/traffic?token=`, `${getClashWsUrl()}/traffic?token=`,
@@ -2085,7 +2087,7 @@ async function runDnsCheck() {
}, },
{ {
state: data.dhcp_has_dns_server ? "success" : "error", state: data.dhcp_has_dns_server ? "success" : "error",
key: _("Dhcp has dns server"), key: _("DHCP has DNS server"),
value: "" value: ""
} }
] ]
@@ -2935,7 +2937,8 @@ function renderAvailableActions({
onClick: restart.onClick, onClick: restart.onClick,
icon: renderRotateCcwIcon24, icon: renderRotateCcwIcon24,
text: "Restart podkop", text: "Restart podkop",
loading: restart.loading loading: restart.loading,
disabled: restart.disabled
}) })
]), ]),
...insertIf(stop.visible, [ ...insertIf(stop.visible, [
@@ -2944,7 +2947,8 @@ function renderAvailableActions({
onClick: stop.onClick, onClick: stop.onClick,
icon: renderCircleStopIcon24, icon: renderCircleStopIcon24,
text: "Stop podkop", text: "Stop podkop",
loading: stop.loading loading: stop.loading,
disabled: stop.disabled
}) })
]), ]),
...insertIf(start.visible, [ ...insertIf(start.visible, [
@@ -2953,7 +2957,8 @@ function renderAvailableActions({
onClick: start.onClick, onClick: start.onClick,
icon: renderCirclePlayIcon24, icon: renderCirclePlayIcon24,
text: "Start podkop", text: "Start podkop",
loading: start.loading loading: start.loading,
disabled: start.disabled
}) })
]), ]),
...insertIf(disable.visible, [ ...insertIf(disable.visible, [
@@ -2961,8 +2966,9 @@ function renderAvailableActions({
classNames: ["cbi-button-remove"], classNames: ["cbi-button-remove"],
onClick: disable.onClick, onClick: disable.onClick,
icon: renderPauseIcon24, icon: renderPauseIcon24,
text: "Disable podkop", text: "Disable autostart",
loading: disable.loading loading: disable.loading,
disabled: disable.disabled
}) })
]), ]),
...insertIf(enable.visible, [ ...insertIf(enable.visible, [
@@ -2970,8 +2976,9 @@ function renderAvailableActions({
classNames: ["cbi-button-save"], classNames: ["cbi-button-save"],
onClick: enable.onClick, onClick: enable.onClick,
icon: renderPlayIcon24, icon: renderPlayIcon24,
text: "Enable podkop", text: "Enable autostart",
loading: enable.loading loading: enable.loading,
disabled: enable.disabled
}) })
]), ]),
...insertIf(globalCheck.visible, [ ...insertIf(globalCheck.visible, [
@@ -2979,7 +2986,8 @@ function renderAvailableActions({
onClick: globalCheck.onClick, onClick: globalCheck.onClick,
icon: renderCircleCheckBigIcon24, icon: renderCircleCheckBigIcon24,
text: "Get global check", text: "Get global check",
loading: globalCheck.loading loading: globalCheck.loading,
disabled: globalCheck.disabled
}) })
]), ]),
...insertIf(viewLogs.visible, [ ...insertIf(viewLogs.visible, [
@@ -2987,7 +2995,8 @@ function renderAvailableActions({
onClick: viewLogs.onClick, onClick: viewLogs.onClick,
icon: renderSquareChartGanttIcon24, icon: renderSquareChartGanttIcon24,
text: "View logs", text: "View logs",
loading: viewLogs.loading loading: viewLogs.loading,
disabled: viewLogs.disabled
}) })
]), ]),
...insertIf(showSingBoxConfig.visible, [ ...insertIf(showSingBoxConfig.visible, [
@@ -2995,7 +3004,8 @@ function renderAvailableActions({
onClick: showSingBoxConfig.onClick, onClick: showSingBoxConfig.onClick,
icon: renderCogIcon24, icon: renderCogIcon24,
text: "Show sing-box config", text: "Show sing-box config",
loading: showSingBoxConfig.loading loading: showSingBoxConfig.loading,
disabled: showSingBoxConfig.disabled
}) })
]) ])
]); ]);
@@ -3226,13 +3236,15 @@ async function handleRestart() {
} catch (e) { } catch (e) {
console.log("handleRestart - e", e); console.log("handleRestart - e", e);
} finally { } finally {
store.set({ setTimeout(async () => {
diagnosticsActions: { await fetchServicesInfo();
...diagnosticsActions, store.set({
restart: { loading: false } diagnosticsActions: {
} ...diagnosticsActions,
}); restart: { loading: false }
location.reload(); }
});
}, 5e3);
} }
} }
async function handleStop() { async function handleStop() {
@@ -3248,6 +3260,7 @@ async function handleStop() {
} catch (e) { } catch (e) {
console.log("handleStop - e", e); console.log("handleStop - e", e);
} finally { } finally {
await fetchServicesInfo();
store.set({ store.set({
diagnosticsActions: { diagnosticsActions: {
...diagnosticsActions, ...diagnosticsActions,
@@ -3269,13 +3282,15 @@ async function handleStart() {
} catch (e) { } catch (e) {
console.log("handleStart - e", e); console.log("handleStart - e", e);
} finally { } finally {
store.set({ setTimeout(async () => {
diagnosticsActions: { await fetchServicesInfo();
...diagnosticsActions, store.set({
start: { loading: false } diagnosticsActions: {
} ...diagnosticsActions,
}); start: { loading: false }
location.reload(); }
});
}, 5e3);
} }
} }
async function handleEnable() { async function handleEnable() {
@@ -3291,6 +3306,7 @@ async function handleEnable() {
} catch (e) { } catch (e) {
console.log("handleEnable - e", e); console.log("handleEnable - e", e);
} finally { } finally {
await fetchServicesInfo();
store.set({ store.set({
diagnosticsActions: { diagnosticsActions: {
...diagnosticsActions, ...diagnosticsActions,
@@ -3312,6 +3328,7 @@ async function handleDisable() {
} catch (e) { } catch (e) {
console.log("handleDisable - e", e); console.log("handleDisable - e", e);
} finally { } finally {
await fetchServicesInfo();
store.set({ store.set({
diagnosticsActions: { diagnosticsActions: {
...diagnosticsActions, ...diagnosticsActions,
@@ -3322,51 +3339,63 @@ async function handleDisable() {
} }
function renderDiagnosticAvailableActionsWidget() { function renderDiagnosticAvailableActionsWidget() {
const diagnosticsActions = store.get().diagnosticsActions; const diagnosticsActions = store.get().diagnosticsActions;
const servicesInfoWidget = store.get().servicesInfoWidget;
console.log("renderDiagnosticActionsWidget"); console.log("renderDiagnosticActionsWidget");
const podkopEnabled = Boolean(servicesInfoWidget.data.podkop);
const singBoxRunning = Boolean(servicesInfoWidget.data.singbox);
const atLeastOneServiceCommandLoading = servicesInfoWidget.loading || diagnosticsActions.restart.loading || diagnosticsActions.start.loading || diagnosticsActions.stop.loading;
const container = document.getElementById("pdk_diagnostic-page-actions"); const container = document.getElementById("pdk_diagnostic-page-actions");
const renderedActions = renderAvailableActions({ const renderedActions = renderAvailableActions({
restart: { restart: {
loading: diagnosticsActions.restart.loading, loading: diagnosticsActions.restart.loading,
visible: true, visible: true,
onClick: handleRestart onClick: handleRestart,
disabled: atLeastOneServiceCommandLoading
}, },
start: { start: {
loading: diagnosticsActions.start.loading, loading: diagnosticsActions.start.loading,
visible: true, visible: !singBoxRunning,
onClick: handleStart onClick: handleStart,
disabled: atLeastOneServiceCommandLoading
}, },
stop: { stop: {
loading: diagnosticsActions.stop.loading, loading: diagnosticsActions.stop.loading,
visible: true, visible: singBoxRunning,
onClick: handleStop onClick: handleStop,
disabled: atLeastOneServiceCommandLoading
}, },
enable: { enable: {
loading: diagnosticsActions.enable.loading, loading: diagnosticsActions.enable.loading,
visible: true, visible: !podkopEnabled,
onClick: handleEnable onClick: handleEnable,
disabled: atLeastOneServiceCommandLoading
}, },
disable: { disable: {
loading: diagnosticsActions.disable.loading, loading: diagnosticsActions.disable.loading,
visible: true, visible: podkopEnabled,
onClick: handleDisable onClick: handleDisable,
disabled: atLeastOneServiceCommandLoading
}, },
globalCheck: { globalCheck: {
loading: diagnosticsActions.globalCheck.loading, loading: diagnosticsActions.globalCheck.loading,
visible: true, visible: true,
onClick: () => { onClick: () => {
} },
disabled: atLeastOneServiceCommandLoading
}, },
viewLogs: { viewLogs: {
loading: diagnosticsActions.viewLogs.loading, loading: diagnosticsActions.viewLogs.loading,
visible: true, visible: true,
onClick: () => { onClick: () => {
} },
disabled: atLeastOneServiceCommandLoading
}, },
showSingBoxConfig: { showSingBoxConfig: {
loading: diagnosticsActions.showSingBoxConfig.loading, loading: diagnosticsActions.showSingBoxConfig.loading,
visible: true, visible: true,
onClick: () => { onClick: () => {
} },
disabled: atLeastOneServiceCommandLoading
} }
}); });
return preserveScrollForPage(() => { return preserveScrollForPage(() => {
@@ -3411,7 +3440,7 @@ async function onStoreUpdate2(next, prev, diff) {
if (diff.diagnosticsRunAction) { if (diff.diagnosticsRunAction) {
renderDiagnosticRunActionWidget(); renderDiagnosticRunActionWidget();
} }
if (diff.diagnosticsActions) { if (diff.diagnosticsActions || diff.servicesInfoWidget) {
renderDiagnosticAvailableActionsWidget(); renderDiagnosticAvailableActionsWidget();
} }
} }
@@ -3440,6 +3469,7 @@ async function initController2() {
renderDiagnosticRunActionWidget(); renderDiagnosticRunActionWidget();
renderDiagnosticAvailableActionsWidget(); renderDiagnosticAvailableActionsWidget();
renderDiagnosticSystemInfoWidget(); renderDiagnosticSystemInfoWidget();
fetchServicesInfo();
}); });
} }