diff --git a/web/src/index.css b/web/src/index.css index 132f30d..fb04e3e 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -66,16 +66,17 @@ body { --nm-accent: #3b82f6; --nm-accent-deep: #2563eb; --nm-header: #060a12; - --nm-chrome: #070b14; - --nm-nav: #0c1220; - --nm-nav-border: #1e293b; - --nm-nav-hover: #152033; - --nm-nav-active: #1a2740; + --nm-chrome: #080d18; + --nm-main: #0a101c; + --nm-nav: #101826; + --nm-nav-border: rgba(148, 163, 184, 0.14); + --nm-nav-hover: rgba(59, 130, 246, 0.1); + --nm-nav-active: rgba(59, 130, 246, 0.16); --nm-nav-ink: #e2e8f0; --nm-nav-muted: #94a3b8; - --nm-panel: rgba(15, 23, 42, 0.72); - --nm-panel-solid: #0f172a; - --nm-panel-border: #1e293b; + --nm-panel: rgba(15, 23, 42, 0.78); + --nm-panel-solid: #111a2b; + --nm-panel-border: rgba(148, 163, 184, 0.16); --nm-brand: #f1f5f9; --nm-text: #e2e8f0; --nm-muted: #94a3b8; @@ -2145,10 +2146,12 @@ pre { .ume-page, .system-page { margin: -20px -28px -32px; - padding: 16px 18px 24px; + padding: 20px 22px 28px; min-height: calc(100vh - 48px); - background: var(--nm-chrome); - gap: 14px; + background: + radial-gradient(1200px 480px at 0% 0%, rgba(59, 130, 246, 0.07), transparent 55%), + var(--nm-main, var(--nm-chrome)); + gap: 16px; } /* Already inside network/audit shell — don't re-bleed or force full-viewport height @@ -2167,15 +2170,19 @@ pre { .ume-page > .cards > .panel, .ume-page > .cards > .card, .system-page > .panel { - padding: 16px 18px 18px; - border-color: var(--nm-panel-border); - box-shadow: 0 1px 2px rgba(15, 27, 45, 0.06); + padding: 18px 20px 20px; + border: 1px solid var(--nm-panel-border); + border-radius: 14px; + background: linear-gradient(180deg, rgba(22, 32, 50, 0.96), rgba(15, 23, 42, 0.92)); + box-shadow: + 0 1px 0 rgba(255, 255, 255, 0.03) inset, + 0 10px 28px rgba(0, 0, 0, 0.18); } .ume-page > .cards { display: flex; flex-direction: column; - gap: 14px; + gap: 16px; margin: 0; grid-template-columns: none; } @@ -2185,7 +2192,7 @@ pre { .system-page .panel__toolbar { margin-bottom: 14px; padding-bottom: 12px; - border-bottom: 1px solid var(--nm-panel-border, #c8d2de); + border-bottom: 1px solid rgba(148, 163, 184, 0.14); } .ne-page .panel__toolbar h2, @@ -2198,7 +2205,7 @@ pre { font-size: 17px; font-weight: 650; color: var(--nm-brand); - letter-spacing: -0.01em; + letter-spacing: -0.02em; margin: 0; } @@ -2219,12 +2226,111 @@ pre { .ume-page .card__section-title { margin: 16px 0 10px; padding-top: 12px; - border-top: 1px solid var(--nm-panel-border, #c8d2de); + border-top: 1px solid rgba(148, 163, 184, 0.14); font-size: 14px; font-weight: 650; color: var(--nm-brand); } +.ume-page .ume-status-row { + gap: 8px; + flex-wrap: wrap; + align-items: center; +} + +.ume-conn-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 16px 28px; + align-items: start; +} + +.ume-conn-col { + display: flex; + flex-direction: column; + gap: 10px; + min-width: 0; +} + +.ume-conn-col .panel__toolbar { + margin-bottom: 0; + padding-bottom: 10px; +} + +.ume-conn-col + .ume-conn-col { + padding-left: 28px; + border-left: 1px solid rgba(148, 163, 184, 0.14); +} + +.ume-conn-panel .ume-ws-log { + margin-top: 16px; + padding-top: 14px; + border-top: 1px solid rgba(148, 163, 184, 0.14); +} + +@media (max-width: 960px) { + .ume-conn-grid { + grid-template-columns: 1fr; + gap: 18px; + } + + .ume-conn-col + .ume-conn-col { + padding-left: 0; + padding-top: 14px; + border-left: 0; + border-top: 1px solid rgba(148, 163, 184, 0.14); + } +} + +.ume-page .pt-list-table-wrap { + border: 1px solid rgba(148, 163, 184, 0.14); + border-radius: 12px; + overflow: hidden; + background: rgba(8, 13, 24, 0.28); +} + +.ume-page .pt-list-table thead th { + font-size: 12px; + font-weight: 600; + letter-spacing: 0.02em; + text-transform: uppercase; +} + +.ume-page .ume-ws-log { + margin-top: 14px; + display: flex; + flex-direction: column; + gap: 8px; +} + +.ume-page .ume-ws-log__head { + display: flex; + flex-wrap: wrap; + align-items: baseline; + justify-content: space-between; + gap: 8px 12px; +} + +.ume-page .ume-ws-log__head strong { + font-size: 13px; + color: var(--nm-brand); +} + +.ume-page .ume-ws-log__head .muted { + font-size: 12px; +} + +.ume-page .ws-log-panel { + margin-top: 0; + max-height: 180px; + border-radius: 10px; + background: rgba(8, 13, 24, 0.55); +} + +.ume-page .error-text { + color: #fca5a5; +} + .ne-page .filter-inline, .ume-page .filter-inline, .system-page .filter-inline { @@ -9236,62 +9342,82 @@ html.login-page--paused .login-page__flare { } .network-nav { - width: 220px; + width: 248px; flex-shrink: 0; display: flex; flex-direction: column; - background: var(--nm-nav); + background: + linear-gradient(180deg, rgba(59, 130, 246, 0.06), transparent 120px), + var(--nm-nav); border-right: 1px solid var(--nm-nav-border); min-height: 0; color: var(--nm-text); - box-shadow: inset -1px 0 0 rgba(15, 27, 45, 0.04); + box-shadow: 4px 0 24px rgba(0, 0, 0, 0.18); } .network-nav__scroll { flex: 1; min-height: 0; overflow: auto; - padding: 10px 0 16px; + padding: 10px 10px 20px; +} + +.network-nav__accordion.accordion { + width: 100%; + background: transparent; + border: 0; + border-radius: 0; + contain: none; } .network-nav__group { - margin: 0 0 4px; + margin: 0 0 6px; + border-radius: 10px; +} + +.network-nav__group.is-active-group { + background: rgba(59, 130, 246, 0.05); } .app-main .network-nav__group-toggle, -.network-nav__group-toggle { +.network-nav__group-toggle, +.network-nav .accordion__trigger.network-nav__group-toggle { display: flex; align-items: center; - gap: 6px; + gap: 8px; width: 100%; - padding: 9px 14px; + padding: 10px 12px; border: 0; - border-radius: 0; + border-radius: 10px; background: transparent; - color: var(--nm-text); + color: var(--nm-muted); font-size: 12px; font-weight: 650; - letter-spacing: 0.02em; + letter-spacing: 0.04em; + text-transform: uppercase; text-align: left; cursor: pointer; } .app-main .network-nav__group-toggle:hover, -.network-nav__group-toggle:hover { +.network-nav__group-toggle:hover, +.network-nav .accordion__trigger.network-nav__group-toggle:hover { background: var(--nm-nav-hover); color: var(--nm-brand); } -.network-nav__group.is-active-group .network-nav__group-toggle { - color: var(--nm-accent); +.network-nav__group.is-active-group .network-nav__group-toggle, +.network-nav__group.is-active-group .accordion__trigger.network-nav__group-toggle { + color: #93c5fd; } -.network-nav__chevron { - display: inline-block; - width: 1em; - color: #7b8b9c; - font-size: 11px; - line-height: 1; +.network-nav__chevron, +.network-nav .accordion__indicator.network-nav__chevron { + display: inline-flex; + width: 14px; + height: 14px; + color: #64748b; + flex-shrink: 0; } .network-nav__group-label { @@ -9299,11 +9425,19 @@ html.login-page--paused .login-page__flare { min-width: 0; } +.network-nav .accordion__body-inner.network-nav__panel-body, +.network-nav .network-nav__panel-body { + padding: 0 4px 8px !important; + color: inherit !important; +} + .network-nav__list { list-style: none; margin: 0; - /* Indent under group label (toggle pad + chevron + gap), not under the chevron */ - padding: 0 8px 6px 34px; + padding: 0 4px; + display: flex; + flex-direction: column; + gap: 2px; } .network-nav__list > li { @@ -9314,13 +9448,17 @@ html.login-page--paused .login-page__flare { display: block; box-sizing: border-box; width: 100%; - padding: 7px 12px; - border-radius: 6px; + padding: 9px 12px; + border-radius: 8px; color: var(--nm-muted); text-decoration: none; font-size: 13px; line-height: 1.35; - border-left: 2px solid transparent; + border-left: 0; + transition: + background 140ms ease, + color 140ms ease, + box-shadow 140ms ease; } .network-nav__link:hover { @@ -9330,22 +9468,25 @@ html.login-page--paused .login-page__flare { .network-nav__link.is-active { background: var(--nm-nav-active); - color: var(--nm-accent); + color: #dbeafe; font-weight: 600; - border-left-color: var(--nm-accent); + box-shadow: inset 3px 0 0 var(--nm-accent); } .network-nav__brand { - padding: 14px 16px 10px; + padding: 16px 18px 14px; font-size: 13px; font-weight: 700; - letter-spacing: 0.02em; + letter-spacing: 0.06em; + text-transform: uppercase; color: var(--nm-brand); border-bottom: 1px solid var(--nm-nav-border); + background: rgba(8, 13, 24, 0.35); } .network-nav__list--flat { - padding: 8px 10px 12px; + padding: 4px; + gap: 2px; } .audit-shell .network-main { @@ -9357,40 +9498,52 @@ html.login-page--paused .login-page__flare { min-width: 0; min-height: 0; overflow: auto; - padding: 16px 18px 24px; - background: var(--nm-chrome); + padding: 20px 22px 28px; + background: + radial-gradient(1200px 480px at 0% 0%, rgba(59, 130, 246, 0.07), transparent 55%), + var(--nm-main, var(--nm-chrome)); } .network-main > .panel, -.network-main .page-stack > .panel { - padding: 16px 18px 18px; - border-color: var(--nm-panel-border); - box-shadow: 0 1px 2px rgba(15, 27, 45, 0.06); +.network-main .page-stack > .panel, +.network-main > .nm-page-panel { + padding: 18px 20px 20px; + border: 1px solid var(--nm-panel-border); + border-radius: 14px; + background: linear-gradient(180deg, rgba(22, 32, 50, 0.96), rgba(15, 23, 42, 0.92)); + box-shadow: + 0 1px 0 rgba(255, 255, 255, 0.03) inset, + 0 10px 28px rgba(0, 0, 0, 0.18); } .network-main .panel__toolbar { - margin-bottom: 14px; - padding-bottom: 12px; - border-bottom: 1px solid rgba(148, 163, 184, 0.18); + margin-bottom: 16px; + padding-bottom: 14px; + border-bottom: 1px solid rgba(148, 163, 184, 0.14); + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; } .network-main .panel__toolbar h2 { - font-size: 17px; + margin: 0; + font-size: 18px; font-weight: 650; color: var(--nm-brand); - letter-spacing: -0.01em; + letter-spacing: -0.02em; } .network-main .filter-inline { display: flex; flex-wrap: wrap; - gap: 8px; + gap: 10px; align-items: center; margin-bottom: 0; - padding: 10px 12px; - border: 1px solid rgba(148, 163, 184, 0.2); - border-radius: 8px; - background: rgba(15, 23, 42, 0.55); + padding: 12px 14px; + border: 1px solid rgba(148, 163, 184, 0.16); + border-radius: 12px; + background: rgba(8, 13, 24, 0.45); grid-template-columns: none; } @@ -9400,13 +9553,13 @@ html.login-page--paused .login-page__flare { min-width: 140px; flex: 1 1 160px; max-width: 280px; - height: 32px; + height: 34px; margin: 0; - border: 1px solid rgba(148, 163, 184, 0.28); - border-radius: 6px; + border: 1px solid rgba(148, 163, 184, 0.24); + border-radius: 8px; background: #0b1220; color: #e2e8f0; - padding: 0 10px; + padding: 0 12px; font-size: 13px; } @@ -9421,35 +9574,63 @@ html.login-page--paused .login-page__flare { .network-main .filter-inline > .ui-field > .ui-field__select { width: 100%; - height: 32px; - min-height: 32px; - max-height: 32px; + height: 34px; + min-height: 34px; + max-height: 34px; flex: none; margin: 0; - border: 1px solid rgba(148, 163, 184, 0.28); - border-radius: 6px; + border: 1px solid rgba(148, 163, 184, 0.24); + border-radius: 8px; background: #0b1220; color: #e2e8f0; - padding: 0 10px; + padding: 0 12px; font-size: 13px; } .network-main .filter-inline button { - height: 32px; + height: 34px; flex: 0 0 auto; } .network-main .pt-list { - gap: 12px; + gap: 14px; } .network-main .pt-list-table-wrap { - border-color: rgba(148, 163, 184, 0.2); + border: 1px solid rgba(148, 163, 184, 0.14); + border-radius: 12px; + overflow: hidden; + background: rgba(8, 13, 24, 0.28); +} + +.network-main .pt-list-table { + margin: 0; } .network-main .pt-list-table thead th { - background: rgba(15, 23, 42, 0.9); + background: rgba(15, 23, 42, 0.92); color: #94a3b8; + font-size: 12px; + font-weight: 600; + letter-spacing: 0.02em; + text-transform: uppercase; + padding-top: 12px; + padding-bottom: 12px; +} + +.network-main .pt-list-table tbody td { + padding-top: 11px; + padding-bottom: 11px; + border-bottom-color: rgba(148, 163, 184, 0.08); +} + +.network-main .pt-list-table tbody tr:last-child td { + border-bottom: 0; +} + +.network-main .pt-list-actions .button, +.network-main .table-actions .button { + min-height: 28px; } .network-main .pager.pt-list-pager, @@ -9459,7 +9640,8 @@ html.login-page--paused .login-page__flare { align-items: center; justify-content: space-between; gap: 10px; - margin-top: 2px; + margin-top: 4px; + padding-top: 4px; } .pt-port-updown { @@ -9618,13 +9800,17 @@ html.login-page--paused .login-page__flare { .ume-entry-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - gap: 14px; + gap: 16px; } .ume-page > .ume-entry-grid > .panel { padding: 16px 18px 18px; - border-color: var(--nm-panel-border); - box-shadow: 0 1px 2px rgba(15, 27, 45, 0.06); + border: 1px solid var(--nm-panel-border); + border-radius: 14px; + background: linear-gradient(180deg, rgba(22, 32, 50, 0.96), rgba(15, 23, 42, 0.92)); + box-shadow: + 0 1px 0 rgba(255, 255, 255, 0.03) inset, + 0 10px 28px rgba(0, 0, 0, 0.18); margin: 0; display: flex; flex-direction: column; @@ -9647,6 +9833,18 @@ html.login-page--paused .login-page__flare { .ume-entry__pills { margin: 0; flex-wrap: wrap; + gap: 6px; +} + +.ume-entry__link { + color: #93c5fd; + text-decoration: none; + font-weight: 600; +} + +.ume-entry__link:hover { + color: #bfdbfe; + text-decoration: underline; } .ume-modal-form { @@ -11037,8 +11235,8 @@ option { .ne-page .filter-inline, .ume-page .filter-inline, .system-page .filter-inline { - background: rgba(15, 23, 42, 0.55) !important; - border-color: rgba(148, 163, 184, 0.2) !important; + background: rgba(8, 13, 24, 0.45) !important; + border-color: rgba(148, 163, 184, 0.16) !important; } .app-main .filter-inline input, @@ -11052,7 +11250,7 @@ option { .system-page .filter-inline input, .system-page .filter-inline select { background: #0b1220 !important; - border-color: rgba(148, 163, 184, 0.28) !important; + border-color: rgba(148, 163, 184, 0.24) !important; color: #e2e8f0 !important; } @@ -11062,8 +11260,8 @@ option { .ume-page .pt-list-table-wrap, .system-page .pt-list-table-wrap, .pt-list-table-wrap { - border-color: rgba(148, 163, 184, 0.2) !important; - background: transparent; + border-color: rgba(148, 163, 184, 0.14) !important; + background: rgba(8, 13, 24, 0.28); } .app-main .pt-list-table thead th, @@ -11074,9 +11272,9 @@ option { .pt-list-table thead th, .app-main .data-table thead th, .data-table thead th { - background: rgba(15, 23, 42, 0.95) !important; + background: rgba(15, 23, 42, 0.92) !important; color: #94a3b8 !important; - border-bottom-color: rgba(148, 163, 184, 0.18); + border-bottom-color: rgba(148, 163, 184, 0.14); } .app-main .pt-list-table tbody tr:hover td, diff --git a/web/src/pages/CollectPage.tsx b/web/src/pages/CollectPage.tsx index a1d03a9..ebddf82 100644 --- a/web/src/pages/CollectPage.tsx +++ b/web/src/pages/CollectPage.tsx @@ -28,6 +28,7 @@ import { useToast } from "../hooks/useToast"; import type { CollectionJobItem, CollectionRunItem, CollectionTargetRef, EligibleNeItem } from "../types"; import { downloadCsv, fetchAllPages } from "../utils/csvExport"; import { pageCount } from "../utils/display"; +import { jobChipColor, NmStatusChip, sourceChipColor } from "./network/nmChips"; import { formatSystemTime } from "../utils/time"; const POLL_MS = 2000; @@ -458,7 +459,7 @@ export function CollectPage() { return (
-
+

{t("collect.jobs.title")}

@@ -542,7 +543,7 @@ export function CollectPage() {
-
+

{t("collect.policyTitle")}

{t("collect.policyHint")} @@ -703,7 +704,7 @@ export function CollectPage() { ) : null}

-
+

{t("collect.jobs.listTitle")}

@@ -1146,7 +1147,9 @@ function JobRow({ return ( {job.title} - {job.status} + + {job.status} + {job.success_count}/{job.ne_count} {t("collect.jobs.ok")}, {job.fail_count} {t("collect.jobs.fail")} @@ -1368,11 +1371,15 @@ function JobRunsPanel({ {runs.map((run) => ( - {run.ne_source || "managed"} + + {run.ne_source || "managed"} + {run.ne_name} {run.ne_ip} - {run.status} + + {run.status} + {run.message ? (
diff --git a/web/src/pages/ConfigSyncPage.tsx b/web/src/pages/ConfigSyncPage.tsx index 369efc6..2b013c5 100644 --- a/web/src/pages/ConfigSyncPage.tsx +++ b/web/src/pages/ConfigSyncPage.tsx @@ -25,6 +25,7 @@ import type { CliTargetItem, ConfigSyncCycle, ConfigSyncTargetRef, ConfigSyncTas import { downloadCsv, fetchAllPages } from "../utils/csvExport"; import { pageCount } from "../utils/display"; import { formatSystemTime } from "../utils/time"; +import { jobChipColor, NmStatusChip, sourceChipColor } from "./network/nmChips"; const POLL_MS = 2500; const TARGET_PAGE_SIZE = 10; @@ -353,7 +354,7 @@ export function ConfigSyncPage() { }; return ( -
+

{t("configSync.title")}

@@ -549,7 +550,9 @@ export function ConfigSyncPage() { onChange={() => toggleTarget(row)} /> - {source} + + {source} + {row.name} {row.ip_address} {row.vendor || "-"} @@ -664,21 +667,7 @@ export function ConfigSyncPage() { {c.id.slice(0, 8)} {c.trigger_mode} - - {c.status} - + {c.status} {c.success_count}/{c.planned_count} · fail {c.fail_count} @@ -690,7 +679,7 @@ export function ConfigSyncPage() { {c.status === "running" || c.status === "pending" ? ( - - -
- {(tokenOpError || tokenRefreshMutation.error || tokenDisconnectMutation.error) && ( -
- {t("common.opFailed")}: {tokenOpError || String(tokenRefreshMutation.error || tokenDisconnectMutation.error)} +
+
+
+
+

{t("ume.token.title")}

- )} -
- -
-
-

{t("ume.tasks.currentTitle")}

-
- 0 ? "unknown" : "up"}`}> - {t("ume.tasks.running")}: {runningTasks.length} - +
+ + + token:{" "} + {!hasToken + ? t("ume.token.disconnected") + : tokenNeedsRenewal + ? t("ume.token.connectedRenew") + : t("ume.token.connected")} + + + + {t("ume.token.expiresIn")}:{" "} + {typeof tokenStatusQuery.data?.expires_in_s === "number" + ? tokenNeedsRenewal + ? t("ume.token.needsRenew") + : `${tokenStatusQuery.data.expires_in_s}s` + : t("common.empty")} + + {tokenStatusQuery.data?.token_preview ? ( + + {t("ume.token.preview")}: {tokenStatusQuery.data.token_preview} + + ) : null} +
+
+ + +
+ {(tokenOpError || tokenRefreshMutation.error || tokenDisconnectMutation.error) && ( +
+ {t("common.opFailed")}: {tokenOpError || String(tokenRefreshMutation.error || tokenDisconnectMutation.error)} +
+ )} +
+ +
+
+

+ {t("ume.subscription.title")} + +

+
+
+ + {t("ume.subscription.sub")}:{" "} + {subscriptionActive ? t("ume.subscription.subActive") : t("ume.subscription.subInactive")} + + {subscriptionActive && alarmSub.subscription_id ? ( + + + id: {String(alarmSub.subscription_id).slice(0, 12)}… + + + ) : null} + {subscriptionActive || wsConsumer ? ( + + + WSS: {wsLabel} + + + ) : null} +
+ {scheduledSyncSkipped && !serverSubLost ? ( +
+ {t("ume.subscription.wssModeBanner", { mode: currentAlarmsMode })} +
+ ) : null} + {serverSubLost ? ( +
+ {t("ume.subscription.serverLostBanner")} + {serverSubLostReason ? ( +
+ {serverSubLostReason.slice(0, 280)} +
+ ) : null} +
+ ) : null} +
+ + {serverSubLost && subscriptionActive ? ( + + ) : null} + + +
+ {subscriptionOpError ? ( +
+ {t("ume.subscription.opFailed")}: {subscriptionOpError} +
+ ) : null} +
+
+ +
+
+ {t("ume.subscription.wsLogs")} + + {wsConsumer?.last_run_at + ? t("ume.subscription.wsActivity", { time: formatSystemTime(String(wsConsumer.last_run_at)) }) + : t("ume.subscription.wsAutoRefresh")} + +
+
+ {wsLogs.length === 0 ? ( +
{t("ume.subscription.wsLogsEmpty")}
+ ) : ( + wsLogs.map((line, idx) => { + const lvl = String(line.level || "info").toLowerCase(); + const cls = + lvl === "error" ? "ws-log-line--error" : lvl === "warning" ? "ws-log-line--warning" : "ws-log-line--info"; + return ( +
+ {formatSystemTime(line.ts)} + [{lvl}] + {line.message} + {line.subscription_id ? ( + · {String(line.subscription_id).slice(0, 8)}… + ) : null} +
+ ); + }) + )} +
+
+
+ +
+
+

{t("ume.tasks.currentTitle")}

+
+ 0 ? "accent" : "success"}> + {t("ume.tasks.running")}: {runningTasks.length} + +
) : null}
-
- - - - - - - - - - - - - {runningTasks.map((x) => ( - - - - - - - - - ))} - {!syncStatusQuery.isLoading && runningTasks.length === 0 && ( - - - - )} - -
IDdomaintrigger_modestatusstarted_aterror
{x.id}{x.domain}{x.trigger_mode}{x.status}{formatSystemTime(x.started_at)}{x.error_message || t("common.empty")}
{t("ume.tasks.noRunning")}
-
+
+ + + + + + + + + + + + + {runningTasks.map((x) => ( + + + + + + + + + ))} + {!syncStatusQuery.isLoading && runningTasks.length === 0 && ( + + + + )} + +
IDdomaintrigger_modestatusstarted_aterror
{x.id}{x.domain}{x.trigger_mode} + {x.status} + {formatSystemTime(x.started_at)} + {x.error_message || t("common.empty")} +
{t("ume.tasks.noRunning")}
+
-

{t("ume.tasks.runtimeTitle")}

- {runtimeTaskError ? ( -
- {t("ume.tasks.runtimeOpFailed")}: {runtimeTaskError} -
- ) : null} -
- - - - - - - - - - - - - {runtimeTasks.map((x) => ( - - - - - - - - - ))} - {!syncStatusQuery.isLoading && runtimeTasks.length === 0 && ( - - - - )} - -
taskintervalstatuslast_run_at{t("ume.tasks.lastErrorCol")}actions
{runtimeTaskLabel(x.task)} - {runtimeIntervalLabel(x.interval_label)} - {x.status}{x.last_run_at ? formatSystemTime(x.last_run_at) : t("common.empty")}{runtimeLastError(x.last_error, t) || t("common.empty")} - {Boolean(x.paused) ? ( - - ) : ( - - )} -
{t("ume.tasks.noRuntime")}
-
-
-
- -
-
-

- {t("ume.subscription.title")} - -

-
-
- - {t("ume.subscription.sub")}: {subscriptionActive ? t("ume.subscription.subActive") : t("ume.subscription.subInactive")} - - {subscriptionActive && alarmSub.subscription_id ? ( - - id: {String(alarmSub.subscription_id).slice(0, 12)}… - +

{t("ume.tasks.runtimeTitle")}

+ {runtimeTaskError ? ( +
+ {t("ume.tasks.runtimeOpFailed")}: {runtimeTaskError} +
) : null} - {subscriptionActive || wsConsumer ? ( - - WSS: {wsLabel} - - ) : null} -
- {scheduledSyncSkipped && !serverSubLost ? ( -
- {t("ume.subscription.wssModeBanner", { mode: currentAlarmsMode })} -
- ) : null} - {serverSubLost ? ( -
- {t("ume.subscription.serverLostBanner")} - {serverSubLostReason ? ( -
- {serverSubLostReason.slice(0, 280)} -
- ) : null} -
- ) : null} -
- - {serverSubLost && subscriptionActive ? ( - - ) : null} - - -
- {subscriptionOpError ? ( -
- {t("ume.subscription.opFailed")}: {subscriptionOpError} -
- ) : null} -
-
- {t("ume.subscription.wsLogs")} - - {wsConsumer?.last_run_at - ? t("ume.subscription.wsActivity", { time: formatSystemTime(String(wsConsumer.last_run_at)) }) - : t("ume.subscription.wsAutoRefresh")} - -
-
- {wsLogs.length === 0 ? ( -
{t("ume.subscription.wsLogsEmpty")}
- ) : ( - wsLogs.map((line, idx) => { - const lvl = String(line.level || "info").toLowerCase(); - const cls = - lvl === "error" ? "ws-log-line--error" : lvl === "warning" ? "ws-log-line--warning" : "ws-log-line--info"; - return ( -
- {formatSystemTime(line.ts)} - [{lvl}] - {line.message} - {line.subscription_id ? ( - · {String(line.subscription_id).slice(0, 8)}… - ) : null} -
- ); - }) - )} +
+ + + + + + + + + + + + + {runtimeTasks.map((x) => ( + + + + + + + + + ))} + {!syncStatusQuery.isLoading && runtimeTasks.length === 0 && ( + + + + )} + +
taskintervalstatuslast_run_at{t("ume.tasks.lastErrorCol")}actions
+ {runtimeTaskLabel(x.task)} + + {runtimeIntervalLabel(x.interval_label)} + + {x.status} + {x.last_run_at ? formatSystemTime(x.last_run_at) : t("common.empty")} + {runtimeLastError(x.last_error, t) || t("common.empty")} + + {Boolean(x.paused) ? ( + + ) : ( + + )} +
{t("ume.tasks.noRuntime")}
@@ -829,52 +863,52 @@ export function UmePage() {
-
+

{t("ume.cli.title")}

-

{t("ume.cli.hint")}

-
+

{t("ume.keyAlert.title")}

-
- + {t("ume.keyAlert.hub")}:{" "} {keyAlertHubSubscribers > 0 ? t("ume.keyAlert.hubConnected") : t("ume.keyAlert.hubEmpty")} - - + + {t("ume.keyAlert.hubSubscribers")}: {keyAlertHubSubscribers} - - + + {t("ume.keyAlert.hubPublished")}: {Number(keyAlertHub?.published || 0)} - - + + {t("ume.keyAlert.hubDeliverOk")}: {Number(keyAlertHub?.deliver_ok || 0)} - +
-
+

{t("ume.syncStatus.title")}

-
@@ -888,10 +922,10 @@ export function UmePage() {

-
+

{t("ume.ne.title")}

-
@@ -900,13 +934,14 @@ export function UmePage() {

-
+

{t("ume.alarms.title")}

{t("ume.alarms.movedHint")}{" "} { e.preventDefault(); @@ -1359,7 +1394,9 @@ export function UmePage() { {String(x.id).slice(0, 8)} {x.domain} - {x.status} + + {x.status} + {x.pulled_count} {x.inserted_count} {x.updated_count} diff --git a/web/src/pages/network/LldpLinksPage.tsx b/web/src/pages/network/LldpLinksPage.tsx index a739d4b..8221e54 100644 --- a/web/src/pages/network/LldpLinksPage.tsx +++ b/web/src/pages/network/LldpLinksPage.tsx @@ -33,6 +33,12 @@ import type { import { downloadCsv, fetchAllPages } from "../../utils/csvExport"; import { pageCount } from "../../utils/display"; import { formatSystemTime } from "../../utils/time"; +import { + edgeChipColor, + jobChipColor, + NmStatusChip, + sourceChipColor, +} from "./nmChips"; const POLL_MS = 2500; const TARGET_PAGE_SIZE = 10; @@ -553,7 +559,7 @@ export function LldpLinksPage() { }; return ( -

+

{t("lldpLinks.title")}

@@ -776,7 +782,9 @@ export function LldpLinksPage() { onChange={() => toggleTarget(row)} /> - {source} + + {source} + {row.name} {row.ip_address} {row.vendor || "-"} @@ -880,7 +888,9 @@ export function LldpLinksPage() { const st = e.status === "stale" ? "missing" : e.status; return ( - {lldpEdgeStatusLabel(t, st)} + + {lldpEdgeStatusLabel(t, st)} +
{aLabel}
{e.a_ip && e.a_name ?
{e.a_ip}
: null} @@ -891,7 +901,11 @@ export function LldpLinksPage() { {e.b_ip && e.b_name ?
{e.b_ip}
: null} {e.b_port || "—"} - {lldpEdgeSourceLabel(t, e.source)} + + + {lldpEdgeSourceLabel(t, e.source)} + + {missCount || (st === "missing" ? 1 : 0)} {replaced ? ( @@ -1003,17 +1017,9 @@ export function LldpLinksPage() { {lldpTriggerLabel(t, job.trigger_mode)} {lldpScopeLabel(t, job.scope)} - + {lldpJobStatusLabel(t, job.status)} - + {job.done}/{job.total} @@ -1034,7 +1040,7 @@ export function LldpLinksPage() { {job.status === "running" || job.status === "pending" ? ( - {open ? ( -
    - {group.items.map((item) => ( -
  • - - `network-nav__link${isActive ? " is-active" : ""}` - } - end={ - item.path === "/network/devices" || - item.path === "/network/tasks/port-traffic" - } - > - {t(item.labelKey)} - -
  • - ))} -
- ) : null} -
- ); - })} + + + {t(group.labelKey)} + + + + + +
    + {group.items.map((item) => ( +
  • + + `network-nav__link${isActive ? " is-active" : ""}` + } + end={ + item.path === "/network/devices" || + item.path === "/network/tasks/port-traffic" + } + > + {t(item.labelKey)} + +
  • + ))} +
+
+
+ + ); + })} +
diff --git a/web/src/pages/network/PortTrafficBoardListPage.tsx b/web/src/pages/network/PortTrafficBoardListPage.tsx index ccd3041..83fc144 100644 --- a/web/src/pages/network/PortTrafficBoardListPage.tsx +++ b/web/src/pages/network/PortTrafficBoardListPage.tsx @@ -49,7 +49,7 @@ export function PortTrafficBoardListPage() { const boards = boardsQuery.data?.items || []; return ( -
+

{t("portTraffic.wallTitle")}

@@ -113,7 +113,7 @@ export function PortTrafficBoardListPage() {
- {needsNeRebind(row) ? ( - ) : null} {row.status !== "running" ? (