mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-05 20:09:34 +00:00
Adds the ability to update node panels to the latest release from the Nodes page: select online, enabled nodes (checkboxes) and trigger their official self-updater, or use the per-row Update action. A node whose reported panel version trails the latest GitHub release is flagged with an 'update available' tag (compared via lib/panel-version, mirroring the Go isNewerVersion). Backend: Remote.UpdatePanel calls the node's existing POST /panel/api/server/updatePanel; NodeService.UpdatePanels fans out over the selected ids, skipping disabled/offline nodes with a per-node reason; exposed as POST /panel/api/nodes/updatePanel (documented in endpoints.ts + openapi.json). The bulk request sends a JSON body, so it sets Content-Type: application/json explicitly — axios defaults POST to form-urlencoded, which made ShouldBindJSON fail with 'invalid character i'. Also reuses the clients-page online cue on the Nodes page: a pulsing green dot plus green label for an online node. The .online-dot style moved to the shared styles/utils.css so both pages load it. Translations for all new node keys added across every language file.
30 lines
1.1 KiB
TypeScript
30 lines
1.1 KiB
TypeScript
// Mirror of web/service/panel.go isNewerVersion: parse a vMAJOR.MINOR.PATCH tag
|
|
// and report whether `latest` is ahead of `current`. When either side isn't a
|
|
// clean three-part numeric tag, fall back to a normalized string inequality —
|
|
// the same heuristic the Go side uses so the node "update available" badge
|
|
// agrees with what the server would decide.
|
|
function parseVersionParts(version: string): [number, number, number] | null {
|
|
const parts = version.trim().replace(/^v/, '').split('.');
|
|
if (parts.length !== 3) return null;
|
|
const out: number[] = [];
|
|
for (const part of parts) {
|
|
if (!/^\d+$/.test(part)) return null;
|
|
out.push(Number(part));
|
|
}
|
|
return [out[0], out[1], out[2]];
|
|
}
|
|
|
|
export function isPanelUpdateAvailable(latest: string, current: string): boolean {
|
|
if (!latest || !current) return false;
|
|
const a = parseVersionParts(latest);
|
|
const b = parseVersionParts(current);
|
|
if (!a || !b) {
|
|
return latest.trim().replace(/^v/, '') !== current.trim().replace(/^v/, '');
|
|
}
|
|
for (let i = 0; i < 3; i++) {
|
|
if (a[i] > b[i]) return true;
|
|
if (a[i] < b[i]) return false;
|
|
}
|
|
return false;
|
|
}
|