@camstack/addon-admin-ui 1.2.108 → 1.2.110
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{AddLocationWizard-C1QuDd5l.js → AddLocationWizard-B2pYT5l3.js} +1 -1
- package/dist/assets/{AddonCollectionPage-CAMY7BSp.js → AddonCollectionPage-BM--U5wi.js} +1 -1
- package/dist/assets/Addons-C1fP2vbH.js +1 -0
- package/dist/assets/{AdminTabs-DIHki8py.js → AdminTabs-CLeY5YpY.js} +1 -1
- package/dist/assets/{AiProfiles-DiQNZe9S.js → AiProfiles-B4OqaOyL.js} +2 -2
- package/dist/assets/{BrokerForm-mfcucCqe.js → BrokerForm-BBcYgkU0.js} +1 -1
- package/dist/assets/{Build-Bd3bm4rZ.js → Build-Clz-9wEa.js} +4 -4
- package/dist/assets/{Capabilities-CT-vp-yT.js → Capabilities-GMmZShHl.js} +1 -1
- package/dist/assets/{CapabilityBadges-5yUqlEI8.js → CapabilityBadges-ls5u4iSS.js} +1 -1
- package/dist/assets/Cluster-B0miuhVw.js +11 -0
- package/dist/assets/{Data-DLHWqZce.js → Data-BsJaaX8N.js} +1 -1
- package/dist/assets/DetectionIntelligence-DwAMtJfh.js +1 -0
- package/dist/assets/{DeviceAggregateSection-CJc0z5bD.js → DeviceAggregateSection-CfbUJ--n.js} +1 -1
- package/dist/assets/DeviceDetail-kxj_2AT4.js +2 -0
- package/dist/assets/Devices-CrvA2yT8.js +1 -0
- package/dist/assets/EmbedPlayerPage-5qdw9AQ5.js +1 -0
- package/dist/assets/Events-C0HDOEKf.js +1 -0
- package/dist/assets/{FormBuilder-DfwoGzWg.js → FormBuilder-Sl0aUAjm.js} +1 -1
- package/dist/assets/Identity-3wRL60eh.js +1 -0
- package/dist/assets/IntegrationDetail-DYdXG7zw.js +1 -0
- package/dist/assets/Integrations-DWirlHH2.js +1 -0
- package/dist/assets/Integrations-GhhEgWTs.js +1 -0
- package/dist/assets/{Logs-BI78-0VJ.js → Logs-OCVO9mBC.js} +1 -1
- package/dist/assets/{MotionZonesSettings-gEbDj9Pj.js → MotionZonesSettings-DztkSAzw.js} +1 -1
- package/dist/assets/{MyAccess-Dq5YfsIV.js → MyAccess-C1FnwEV1.js} +1 -1
- package/dist/assets/Network-C1tyUle7.js +1 -0
- package/dist/assets/NodeAddonsSettingsPanel-C51CLAUV.js +1 -0
- package/dist/assets/NodeInferenceDevices-BheDiA_Y.js +1 -0
- package/dist/assets/Notifications-2oJHn7yF.js +1 -0
- package/dist/assets/Pipeline-BWgUjIBu.js +1 -0
- package/dist/assets/{Plates-LVOTLRQ_.js → Plates-B1CFXuYH.js} +1 -1
- package/dist/assets/{PrivacyMaskSettings-ByMo4smL.js → PrivacyMaskSettings-BhcRGnjg.js} +1 -1
- package/dist/assets/{ProviderIcon-BuQT-C1f.js → ProviderIcon-CSGCWRat.js} +1 -1
- package/dist/assets/Recordings-CVBJ-fTE.js +1 -0
- package/dist/assets/{ScanNetworkModal-DO_NYOIO.js → ScanNetworkModal-DP3Q1lJf.js} +1 -1
- package/dist/assets/{SceneMonitorEditor-COTXt9Av.js → SceneMonitorEditor-CC_SRLkY.js} +1 -1
- package/dist/assets/Scenes-CMobnBno.js +1 -0
- package/dist/assets/{Settings-UaBYAyll.js → Settings-Boxw0bXQ.js} +1 -1
- package/dist/assets/{Showroom-BO0DQHWe.js → Showroom-BLra8xK_.js} +1 -1
- package/dist/assets/{Terminal-D6BI2-dB.js → Terminal-DJKkbuyK.js} +3 -3
- package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-6VfZqYHt.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-MSGGSFff.js} +1 -1
- package/dist/assets/{bell-ring-COnGH5xz.js → bell-ring-BrNXSpTM.js} +1 -1
- package/dist/assets/{boxes-BqAi_ZYu.js → boxes-BBQZcZmf.js} +1 -1
- package/dist/assets/circle-check-big-BA325w7j.js +1 -0
- package/dist/assets/{circle-x-CAQ2kQrS.js → circle-x-duYSDFk4.js} +1 -1
- package/dist/assets/clock-C2SeIGR3.js +1 -0
- package/dist/assets/{copy-D25tAWbr.js → copy-sWO8ojL1.js} +1 -1
- package/dist/assets/{debounced-invalidate-Dd9oPYKq.js → debounced-invalidate-CsEaF8m7.js} +1 -1
- package/dist/assets/{dist-Cz-CwPmU.js → dist-B2d_n790.js} +1 -1
- package/dist/assets/dist-CwHxBEa6.js +349 -0
- package/dist/assets/{download-DC6CvEwh.js → download-BG5cgMLB.js} +1 -1
- package/dist/assets/{face-bbox-HBoy_dVM.js → face-bbox-CuCo2m34.js} +1 -1
- package/dist/assets/{hostInit-BZyW6qkD.js → hostInit-BXhxZCos.js} +1 -1
- package/dist/assets/index-TIovJNJd.js +4 -0
- package/dist/assets/{key-round-CkImMp76.js → key-round-DFB6Ddil.js} +1 -1
- package/dist/assets/{layers-DR9qbaZc.js → layers-Dg2FntHR.js} +1 -1
- package/dist/assets/{mf-entry-bootstrap-0-ed3637b6.js → mf-entry-bootstrap-0-78ce8935.js} +2 -2
- package/dist/assets/{pencil-D-rxGNNf.js → pencil-DfqU4z4Q.js} +1 -1
- package/dist/assets/play-B850xDzN.js +1 -0
- package/dist/assets/{player-overlays-wniETo4u.js → player-overlays-BrCS3AFF.js} +1 -1
- package/dist/assets/plus-C1RBhRwm.js +1 -0
- package/dist/assets/power-DSSFcNbH.js +1 -0
- package/dist/assets/{radio-dB0UNm47.js → radio-PpN-ewHt.js} +1 -1
- package/dist/assets/{refresh-cw-srKCTv_-.js → refresh-cw-BP3l62v-.js} +1 -1
- package/dist/assets/remoteEntry-y4f0U6fp.js +1 -0
- package/dist/assets/rotate-ccw-BiOviRuW.js +1 -0
- package/dist/assets/rotate-cw-PvJE7LD3.js +1 -0
- package/dist/assets/{send-DouvNKBS.js → send-BhFSH1Dx.js} +1 -1
- package/dist/assets/{server-BQtqKhWd.js → server-DTziPc-j.js} +1 -1
- package/dist/assets/{shield-Df5MsuC2.js → shield-DloVBwF4.js} +1 -1
- package/dist/assets/square-BxxA8zwF.js +1 -0
- package/dist/assets/{square-check-big-DRcEphPQ.js → square-check-big-DCkSuowJ.js} +1 -1
- package/dist/assets/{src-IW6snE8b.js → src-CTpgEWRF.js} +17 -17
- package/dist/assets/src-Db_n2ue2.js +349 -0
- package/dist/assets/{star-DSf9DLF0.js → star-mh10UPuW.js} +1 -1
- package/dist/assets/{undo-2-D8E8Za4o.js → undo-2-BdzAmJva.js} +1 -1
- package/dist/assets/{use-scenes-feed-DZbJbkzy.js → use-scenes-feed-DuRQEHSx.js} +1 -1
- package/dist/assets/useEventInvalidation-DI7nUUUv.js +1 -0
- package/dist/assets/{video-DMGYxQJX.js → video-B8iXv4k7.js} +1 -1
- package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-ByOZvjdD.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-vbnrVEeZ.js} +2 -2
- package/dist/assets/{wifi-DPLmik5h.js → wifi-CA7EJ_s4.js} +1 -1
- package/dist/assets/{zap-D-TFU8vN.js → zap-Bm8mq3x-.js} +1 -1
- package/dist/index.html +5 -5
- package/dist/server/addon.js +270 -2
- package/package.json +1 -1
- package/dist/assets/Addons-bWB0ZmER.js +0 -1
- package/dist/assets/Cluster-BPFw3CEh.js +0 -11
- package/dist/assets/DetectionIntelligence-B4PBUQWJ.js +0 -1
- package/dist/assets/DeviceDetail-bORj-EYN.js +0 -2
- package/dist/assets/Devices-D88uoW-K.js +0 -1
- package/dist/assets/EmbedPlayerPage-BQ5bsryo.js +0 -1
- package/dist/assets/Events-D9XRueHk.js +0 -1
- package/dist/assets/Identity-43Eya081.js +0 -1
- package/dist/assets/IntegrationDetail-CwEQCSYB.js +0 -1
- package/dist/assets/Integrations-Bj0zg-09.js +0 -1
- package/dist/assets/Integrations-tWtIaZju.js +0 -1
- package/dist/assets/Network-0uDqECDb.js +0 -1
- package/dist/assets/NodeAddonsSettingsPanel-CAyKEQpD.js +0 -1
- package/dist/assets/NodeInferenceDevices-CnDRCNxR.js +0 -1
- package/dist/assets/Notifications-zU06XSrO.js +0 -1
- package/dist/assets/Pipeline-B5A-GVGG.js +0 -1
- package/dist/assets/Recordings-TSgV5nm4.js +0 -1
- package/dist/assets/Scenes-DgDtCzMz.js +0 -1
- package/dist/assets/circle-check-big-BQVyFP9A.js +0 -1
- package/dist/assets/clock-DGWYKseh.js +0 -1
- package/dist/assets/dist-B_SWpX_l.js +0 -349
- package/dist/assets/index-Cp84SBzW.js +0 -4
- package/dist/assets/play-s0iikQHY.js +0 -1
- package/dist/assets/plus-BVcSfMMt.js +0 -1
- package/dist/assets/power-CcdufSlh.js +0 -1
- package/dist/assets/remoteEntry-B2zHiyBK.js +0 -1
- package/dist/assets/rotate-ccw-CY-1yf9N.js +0 -1
- package/dist/assets/rotate-cw-DKLLB8dt.js +0 -1
- package/dist/assets/square-CFDIb2ZA.js +0 -1
- package/dist/assets/src-CsxD-27Y.js +0 -349
- package/dist/assets/useEventInvalidation-CsNvM4qI.js +0 -1
package/dist/server/addon.js
CHANGED
|
@@ -5917,6 +5917,40 @@ var BaseAddon = class {
|
|
|
5917
5917
|
deviceSettingsSchema() {
|
|
5918
5918
|
return null;
|
|
5919
5919
|
}
|
|
5920
|
+
/**
|
|
5921
|
+
* INTEGRATION-LEVEL SETTINGS — declare which of this addon's global sections
|
|
5922
|
+
* ARE the configuration of its integration.
|
|
5923
|
+
*
|
|
5924
|
+
* Return the `ConfigSection.id`s, from {@link globalSettingsSchema}, that an
|
|
5925
|
+
* operator should find on the addon's integration page (System →
|
|
5926
|
+
* Integrations → <name>) rather than only in the cluster-wide list of every
|
|
5927
|
+
* addon. Empty (the default) means the addon has no integration-level
|
|
5928
|
+
* settings and no such surface is offered — this is opt-in, because whether
|
|
5929
|
+
* an addon's configuration IS its integration's configuration depends on the
|
|
5930
|
+
* nature of the integration.
|
|
5931
|
+
*
|
|
5932
|
+
* WHAT THIS IS NOT. It is not a scope. The selected sections keep living in
|
|
5933
|
+
* the ONE global schema, in the ONE addon store, written by the ONE
|
|
5934
|
+
* `updateGlobalSettings` path. There is deliberately no
|
|
5935
|
+
* `updateIntegrationSettings`: a second write path is how a surface acquires
|
|
5936
|
+
* a second store key, and this repo has shipped that twice (`btmPath@hub`,
|
|
5937
|
+
* D266). Selecting sections cannot introduce a key that selecting cannot.
|
|
5938
|
+
*
|
|
5939
|
+
* WHY IT IS A LIST OF SECTION IDS AND NOT A MARKER ON THE SECTION.
|
|
5940
|
+
* `ConfigFieldBase` used to carry `scope?: 'device' | 'global'` and it was
|
|
5941
|
+
* removed with the reason recorded at
|
|
5942
|
+
* `packages/types/src/interfaces/config-ui.ts:249` — *"a field's scope is
|
|
5943
|
+
* determined by WHICH schema it lives in, not by a field-level marker."* A
|
|
5944
|
+
* marker sprinkled across sections also has to borrow a field that already
|
|
5945
|
+
* means something else; borrowing `section.tab` put the literal word
|
|
5946
|
+
* "integration" into an operator-facing tab bar, because `tab` means "how to
|
|
5947
|
+
* GROUP this visually" and cannot also mean "where this lives" (D269
|
|
5948
|
+
* supersedes D268). One declaration, in one place, next to the schema whose
|
|
5949
|
+
* ids it names.
|
|
5950
|
+
*/
|
|
5951
|
+
integrationSettingSections() {
|
|
5952
|
+
return [];
|
|
5953
|
+
}
|
|
5920
5954
|
async getGlobalSettings(overlay, cap, nodeId) {
|
|
5921
5955
|
const schema = this.globalSettingsSchema(cap);
|
|
5922
5956
|
if (!schema) return { sections: [] };
|
|
@@ -5927,6 +5961,55 @@ var BaseAddon = class {
|
|
|
5927
5961
|
} : projected);
|
|
5928
5962
|
}
|
|
5929
5963
|
/**
|
|
5964
|
+
* The integration-level view of this addon's settings: exactly the sections
|
|
5965
|
+
* named by {@link integrationSettingSections}, hydrated from the SAME store
|
|
5966
|
+
* `getGlobalSettings` reads, and narrowed to cluster-scoped fields.
|
|
5967
|
+
*
|
|
5968
|
+
* Returns `null` when the addon declared nothing — an addon that opts out has
|
|
5969
|
+
* no integration settings surface at all, rather than an empty one that reads
|
|
5970
|
+
* as a failed load.
|
|
5971
|
+
*
|
|
5972
|
+
* Three properties hold BY CONSTRUCTION, which is why they are here in core
|
|
5973
|
+
* and not in whichever UI happens to render this:
|
|
5974
|
+
*
|
|
5975
|
+
* 1. **One key.** The payload is a SUBSET of the global schema, so a field
|
|
5976
|
+
* shown here is the same field, with the same bare key, that the addon's
|
|
5977
|
+
* own page shows. There is no integration-specific writer — callers save
|
|
5978
|
+
* through `updateGlobalSettings` — so a second store key is unreachable,
|
|
5979
|
+
* not merely discouraged.
|
|
5980
|
+
* 2. **No node scope.** `perNode: true` fields are DROPPED. Their store key
|
|
5981
|
+
* is `<key>@<nodeId>` and an integration is not a node; whichever node
|
|
5982
|
+
* such a field silently picked would be a wrong answer for the operator
|
|
5983
|
+
* who opened the page (D266).
|
|
5984
|
+
* 3. **No silent typo.** A declared id that names no section throws. The
|
|
5985
|
+
* alternative — skip it — turns a rename into a surface that quietly
|
|
5986
|
+
* empties, which looks exactly like an addon with nothing to configure.
|
|
5987
|
+
*/
|
|
5988
|
+
async getIntegrationSettings(nodeId) {
|
|
5989
|
+
const declared = this.integrationSettingSections();
|
|
5990
|
+
if (declared.length === 0) return null;
|
|
5991
|
+
const schema = this.globalSettingsSchema();
|
|
5992
|
+
if (!schema) throw new Error(`${this.constructor.name}: integrationSettingSections() names [${declared.join(", ")}] but globalSettingsSchema() returns null.`);
|
|
5993
|
+
const byId = new Map(schema.sections.map((section) => [section.id, section]));
|
|
5994
|
+
const sections = [];
|
|
5995
|
+
for (const id of declared) {
|
|
5996
|
+
const section = byId.get(id);
|
|
5997
|
+
if (!section) throw new Error(`${this.constructor.name}: integrationSettingSections() names unknown section "${id}". Known sections: [${[...byId.keys()].join(", ")}].`);
|
|
5998
|
+
const fields = dropPerNodeFields(section.fields);
|
|
5999
|
+
if (fields.length === 0) continue;
|
|
6000
|
+
sections.push({
|
|
6001
|
+
...section,
|
|
6002
|
+
fields
|
|
6003
|
+
});
|
|
6004
|
+
}
|
|
6005
|
+
if (sections.length === 0) return null;
|
|
6006
|
+
const projected = await this.resolveGlobalStore(nodeId);
|
|
6007
|
+
return hydrateSchema({
|
|
6008
|
+
...schema,
|
|
6009
|
+
sections
|
|
6010
|
+
}, projected);
|
|
6011
|
+
}
|
|
6012
|
+
/**
|
|
5930
6013
|
* The raw addon store PROJECTED onto the target node's bare per-node keys:
|
|
5931
6014
|
* every `perNode: true` field carries THAT node's scoped value on its bare
|
|
5932
6015
|
* key (absent scoped key ⇒ key absent, so the schema `default` wins — no
|
|
@@ -6230,6 +6313,41 @@ var BaseAddon = class {
|
|
|
6230
6313
|
* `hydrateSchema` does. Valueless structural fields (separator/info/…)
|
|
6231
6314
|
* don't declare `perNode` and are excluded by the `in` narrowing.
|
|
6232
6315
|
*/
|
|
6316
|
+
/**
|
|
6317
|
+
* The same fields with every `perNode: true` one removed, recursing into layout
|
|
6318
|
+
* containers exactly as {@link collectPerNodeFieldKeys} does. A container left
|
|
6319
|
+
* with no child is dropped rather than rendered empty.
|
|
6320
|
+
*
|
|
6321
|
+
* Used by `getIntegrationSettings`: an integration is not a node, so a field
|
|
6322
|
+
* whose store key is `<key>@<nodeId>` has no node to belong to there.
|
|
6323
|
+
*/
|
|
6324
|
+
function dropPerNodeFields(fields) {
|
|
6325
|
+
const kept = [];
|
|
6326
|
+
for (const field of fields) {
|
|
6327
|
+
if (field.type === "group") {
|
|
6328
|
+
const inner = dropPerNodeFields(field.fields);
|
|
6329
|
+
if (inner.length > 0) kept.push({
|
|
6330
|
+
...field,
|
|
6331
|
+
fields: inner
|
|
6332
|
+
});
|
|
6333
|
+
continue;
|
|
6334
|
+
}
|
|
6335
|
+
if (field.type === "sub-tabs") {
|
|
6336
|
+
const tabs = field.tabs.map((tab) => ({
|
|
6337
|
+
...tab,
|
|
6338
|
+
fields: dropPerNodeFields(tab.fields)
|
|
6339
|
+
})).filter((tab) => tab.fields.length > 0);
|
|
6340
|
+
if (tabs.length > 0) kept.push({
|
|
6341
|
+
...field,
|
|
6342
|
+
tabs
|
|
6343
|
+
});
|
|
6344
|
+
continue;
|
|
6345
|
+
}
|
|
6346
|
+
if ("perNode" in field && field.perNode === true) continue;
|
|
6347
|
+
kept.push(field);
|
|
6348
|
+
}
|
|
6349
|
+
return kept;
|
|
6350
|
+
}
|
|
6233
6351
|
function collectPerNodeFieldKeys(fields) {
|
|
6234
6352
|
const collected = [];
|
|
6235
6353
|
for (const field of fields) {
|
|
@@ -9401,6 +9519,9 @@ method(object({
|
|
|
9401
9519
|
kind: "mutation",
|
|
9402
9520
|
auth: "admin"
|
|
9403
9521
|
}), method(object({
|
|
9522
|
+
addonId: string(),
|
|
9523
|
+
nodeId: string().optional()
|
|
9524
|
+
}), SettingsSchemaWithValuesSchema.nullable()), method(object({
|
|
9404
9525
|
addonId: string(),
|
|
9405
9526
|
deviceId: number(),
|
|
9406
9527
|
nodeId: string().optional()
|
|
@@ -13085,6 +13206,114 @@ method(LogEntrySchema, _void(), { kind: "mutation" }), method(object({
|
|
|
13085
13206
|
limit: number().optional(),
|
|
13086
13207
|
tags: record(string(), string()).optional()
|
|
13087
13208
|
}), array(LogEntrySchema).readonly());
|
|
13209
|
+
/**
|
|
13210
|
+
* `failure-contribution` — the capability an addon reports its OWN losses
|
|
13211
|
+
* through, per camera, with the denominator attached. It stores nothing.
|
|
13212
|
+
*
|
|
13213
|
+
* ## The twin of `load-contribution`, and why it is a twin and not a field
|
|
13214
|
+
*
|
|
13215
|
+
* `load-contribution` answers *what did this camera COST*. This answers *what
|
|
13216
|
+
* did this camera LOSE*. The reporting discipline is identical and deliberately
|
|
13217
|
+
* copied: the contributor reports what it already knows, hub-main adds only
|
|
13218
|
+
* `addonId`, nothing needs global knowledge, and there is no central list for
|
|
13219
|
+
* somebody to forget to edit.
|
|
13220
|
+
*
|
|
13221
|
+
* They are not merged, because their invariants are opposites:
|
|
13222
|
+
*
|
|
13223
|
+
* - a `load-contribution` measurement is **absent, never zero** — a zero would
|
|
13224
|
+
* claim a camera cost nothing, which is a measurement nobody made;
|
|
13225
|
+
* - a `failure-contribution` zero is the **most valuable value on the
|
|
13226
|
+
* surface** — `attempts: 400, succeeded: 400` is the proof a fix landed,
|
|
13227
|
+
* and it is exactly what an absent entry cannot say.
|
|
13228
|
+
*
|
|
13229
|
+
* Putting a loss counter on a cost entry would also break the reconciliation
|
|
13230
|
+
* that gives `load-contribution` its point: contributions are subtracted from
|
|
13231
|
+
* `metrics.node-processes-snapshot` to find processes nobody claims. A failure
|
|
13232
|
+
* has no process.
|
|
13233
|
+
*
|
|
13234
|
+
* ## Why not a log line, since the counters already exist
|
|
13235
|
+
*
|
|
13236
|
+
* Several of these paths already counted themselves — `CaptureScheduler`'s
|
|
13237
|
+
* per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
|
|
13238
|
+
* ends in a log line, and a log line is the thing the operator asked to stop
|
|
13239
|
+
* needing: *"possiamo armare questi errori intanto? Così al prossimo giro
|
|
13240
|
+
* ricontrolliamo tutti questi punti"*. Reading them meant grepping Loki and
|
|
13241
|
+
* hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
|
|
13242
|
+
* media blackout were both diagnosed. The counters stay; this is where they can
|
|
13243
|
+
* be READ.
|
|
13244
|
+
*
|
|
13245
|
+
* ## The rate is served with its denominator or not at all
|
|
13246
|
+
*
|
|
13247
|
+
* Every entry carries `attempts` and `succeeded`. A miss count alone is
|
|
13248
|
+
* unreadable: on 2026-08-28 the enrichment-crop miss count read as "35x worse
|
|
13249
|
+
* than yesterday" and was **flat across twelve hours** once divided by the
|
|
13250
|
+
* successes on the same path. A surface that publishes only the numerator
|
|
13251
|
+
* reproduces that mistake on every read.
|
|
13252
|
+
*
|
|
13253
|
+
* ## Shape
|
|
13254
|
+
*
|
|
13255
|
+
* Copied from `load-contribution.cap.ts` (`mode: 'collection'`,
|
|
13256
|
+
* `internal: true`, `mount: { kind: 'skip' }`): no tRPC route of its own and no
|
|
13257
|
+
* generated hooks, while `addons.listCapabilityProviders` still enumerates it
|
|
13258
|
+
* and the hub's `CapabilityRegistry` still holds an RPC proxy per provider — so
|
|
13259
|
+
* a forked runner's entries reach hub-main over transport that already exists.
|
|
13260
|
+
* No new UDS message, no second registry (D3). The operator reads the assembled
|
|
13261
|
+
* result through `system.getFailureContributions`.
|
|
13262
|
+
*/
|
|
13263
|
+
var FailureReasonCountSchema = object({
|
|
13264
|
+
/**
|
|
13265
|
+
* Why the attempt did not land, in the contributor's own vocabulary —
|
|
13266
|
+
* `worker-lease-gone`, `queue-overflow`, `timeout`, `empty-read`. The same
|
|
13267
|
+
* strings that already appear in this repo's logs and, where one exists, the
|
|
13268
|
+
* same string the per-track `previewMissReason` records (D276): a second
|
|
13269
|
+
* vocabulary for the same loss would make the row and the counter
|
|
13270
|
+
* un-joinable.
|
|
13271
|
+
*/
|
|
13272
|
+
reason: string(),
|
|
13273
|
+
count: number().int().nonnegative()
|
|
13274
|
+
});
|
|
13275
|
+
var FailureContributionSchema = object({
|
|
13276
|
+
/**
|
|
13277
|
+
* The failing path — `enrichment-crop`, `inference`, `plate-ocr`,
|
|
13278
|
+
* `person-over-vehicle`. Free text, for the reason `load-contribution` keeps
|
|
13279
|
+
* `unit` free: the families are owned by different addons and a shared enum
|
|
13280
|
+
* is a central list that rots invisibly.
|
|
13281
|
+
*/
|
|
13282
|
+
family: string(),
|
|
13283
|
+
/**
|
|
13284
|
+
* The NUMERIC device id — the same value every log line carries as
|
|
13285
|
+
* `tags.deviceId`. Never nullable and never absent: a contributor that
|
|
13286
|
+
* cannot name the camera must not emit the entry, because a fleet total
|
|
13287
|
+
* cannot answer the only question anybody asks of this surface.
|
|
13288
|
+
*/
|
|
13289
|
+
deviceId: number().int().positive(),
|
|
13290
|
+
/**
|
|
13291
|
+
* A second dimension inside the family: the model / step id for an inference
|
|
13292
|
+
* timeout, so "which camera AND which model" is one read. Absent when the
|
|
13293
|
+
* family has a single variant.
|
|
13294
|
+
*/
|
|
13295
|
+
variant: string().optional(),
|
|
13296
|
+
/**
|
|
13297
|
+
* Epoch ms this counter started — the INCARNATION MARKER. A consumer
|
|
13298
|
+
* differencing two reads must drop the interval when it changes, because the
|
|
13299
|
+
* counter restarted from zero in a respawned runner. Same discipline as
|
|
13300
|
+
* `LoadContribution.startedAtMs`.
|
|
13301
|
+
*/
|
|
13302
|
+
sinceMs: number(),
|
|
13303
|
+
/** Epoch ms it was read. `atMs - sinceMs` is the interval this covers. */
|
|
13304
|
+
atMs: number(),
|
|
13305
|
+
/**
|
|
13306
|
+
* THE DENOMINATOR — every attempt on this path for this camera in the
|
|
13307
|
+
* window. A failure count published without it is the mistake this schema
|
|
13308
|
+
* exists to make impossible.
|
|
13309
|
+
*/
|
|
13310
|
+
attempts: number().int().nonnegative(),
|
|
13311
|
+
/** Attempts that landed. `attempts - succeeded` is the loss. */
|
|
13312
|
+
succeeded: number().int().nonnegative(),
|
|
13313
|
+
/** The loss, partitioned. Sums to `attempts - succeeded`. */
|
|
13314
|
+
reasons: array(FailureReasonCountSchema).readonly()
|
|
13315
|
+
});
|
|
13316
|
+
method(_void(), array(FailureContributionSchema).readonly());
|
|
13088
13317
|
var LoadContributionSchema = object({
|
|
13089
13318
|
role: _enum([
|
|
13090
13319
|
"decode",
|
|
@@ -17597,6 +17826,20 @@ var TrackSchema = object({
|
|
|
17597
17826
|
* `=== true` and render nothing otherwise — never infer "no rider".
|
|
17598
17827
|
*/
|
|
17599
17828
|
hasRider: boolean().optional(),
|
|
17829
|
+
/**
|
|
17830
|
+
* WHY this track ended without a NATIVE best-shot tile
|
|
17831
|
+
* ([D276](../decisions/adr-0276-a-stand-in-tile-is-provisional-and-a-close-says-why.md)) —
|
|
17832
|
+
* a composed token line (`no-key-frame capture=keyframe:native-missx4`,
|
|
17833
|
+
* `derive-returned-null tile=standin`, …) written at close and CLEARED by
|
|
17834
|
+
* the late-keyFrame upgrade when a native tile lands after all. The
|
|
17835
|
+
* operator-facing answer to "perché manca l'immagine?" on a track whose
|
|
17836
|
+
* tile is a face/plate stand-in, a raster crop, or an icon.
|
|
17837
|
+
*
|
|
17838
|
+
* **Absent ≠ "missed silently"**: a row written before the column, a hub
|
|
17839
|
+
* that predates the field, and every track whose tile landed native all
|
|
17840
|
+
* omit it. Render nothing when absent.
|
|
17841
|
+
*/
|
|
17842
|
+
previewMissReason: string().optional(),
|
|
17600
17843
|
...TrackFlagFields,
|
|
17601
17844
|
...TrackRetrainFields
|
|
17602
17845
|
});
|
|
@@ -26823,6 +27066,13 @@ var LoggingSettingsPatchSchema = object({
|
|
|
26823
27066
|
* anyone but its owner.
|
|
26824
27067
|
*/
|
|
26825
27068
|
var ReportedLoadContributionSchema = LoadContributionSchema.extend({ addonId: string() });
|
|
27069
|
+
/**
|
|
27070
|
+
* One per-camera failure counter, plus WHO reported it.
|
|
27071
|
+
*
|
|
27072
|
+
* Same rule as {@link ReportedLoadContributionSchema}: `addonId` is stamped by
|
|
27073
|
+
* the hub as it enumerates providers, never by the contributor.
|
|
27074
|
+
*/
|
|
27075
|
+
var ReportedFailureContributionSchema = FailureContributionSchema.extend({ addonId: string() });
|
|
26826
27076
|
var GetLoggingSettingsInputSchema = object({
|
|
26827
27077
|
scopeNodeId: string().optional(),
|
|
26828
27078
|
/**
|
|
@@ -26881,7 +27131,7 @@ method(_void(), FeatureManifestSchema), method(_void(), HealthStatusSchema), met
|
|
|
26881
27131
|
}), method(_void(), SiteLocationStatusSchema, {
|
|
26882
27132
|
kind: "mutation",
|
|
26883
27133
|
auth: "admin"
|
|
26884
|
-
}), method(_void(), RequestCensusStatusSchema, { auth: "admin" }), method(_void(), array(ReportedLoadContributionSchema).readonly(), { auth: "admin" }), method(GetLoggingSettingsInputSchema, LoggingSettingsStateSchema, { auth: "admin" }), method(SetLoggingSettingsInputSchema, LoggingSettingsStateSchema, {
|
|
27134
|
+
}), method(_void(), RequestCensusStatusSchema, { auth: "admin" }), method(_void(), array(ReportedLoadContributionSchema).readonly(), { auth: "admin" }), method(_void(), array(ReportedFailureContributionSchema).readonly(), { auth: "admin" }), method(GetLoggingSettingsInputSchema, LoggingSettingsStateSchema, { auth: "admin" }), method(SetLoggingSettingsInputSchema, LoggingSettingsStateSchema, {
|
|
26885
27135
|
kind: "mutation",
|
|
26886
27136
|
auth: "admin"
|
|
26887
27137
|
});
|
|
@@ -27795,6 +28045,12 @@ Object.freeze({
|
|
|
27795
28045
|
addonId: null,
|
|
27796
28046
|
access: "view"
|
|
27797
28047
|
},
|
|
28048
|
+
"addonSettings.getIntegrationSettings": {
|
|
28049
|
+
capName: "addon-settings",
|
|
28050
|
+
capScope: "system",
|
|
28051
|
+
addonId: null,
|
|
28052
|
+
access: "view"
|
|
28053
|
+
},
|
|
27798
28054
|
"addonSettings.updateDeviceSettings": {
|
|
27799
28055
|
capName: "addon-settings",
|
|
27800
28056
|
capScope: "system",
|
|
@@ -29457,6 +29713,12 @@ Object.freeze({
|
|
|
29457
29713
|
addonId: null,
|
|
29458
29714
|
access: "create"
|
|
29459
29715
|
},
|
|
29716
|
+
"failureContribution.list": {
|
|
29717
|
+
capName: "failure-contribution",
|
|
29718
|
+
capScope: "system",
|
|
29719
|
+
addonId: null,
|
|
29720
|
+
access: "view"
|
|
29721
|
+
},
|
|
29460
29722
|
"fanControl.setDirection": {
|
|
29461
29723
|
capName: "fan-control",
|
|
29462
29724
|
capScope: "device",
|
|
@@ -32763,6 +33025,12 @@ Object.freeze({
|
|
|
32763
33025
|
addonId: null,
|
|
32764
33026
|
access: "create"
|
|
32765
33027
|
},
|
|
33028
|
+
"system.getFailureContributions": {
|
|
33029
|
+
capName: "system",
|
|
33030
|
+
capScope: "system",
|
|
33031
|
+
addonId: null,
|
|
33032
|
+
access: "view"
|
|
33033
|
+
},
|
|
32766
33034
|
"system.getLoadContributions": {
|
|
32767
33035
|
capName: "system",
|
|
32768
33036
|
capScope: "system",
|
|
@@ -35668,7 +35936,7 @@ var AdminUIAddon = class extends BaseAddon {
|
|
|
35668
35936
|
capability: adminUiCapability,
|
|
35669
35937
|
provider: {
|
|
35670
35938
|
getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
|
|
35671
|
-
getVersion: async () => ({ version: "1.2.
|
|
35939
|
+
getVersion: async () => ({ version: "1.2.110" })
|
|
35672
35940
|
}
|
|
35673
35941
|
}];
|
|
35674
35942
|
}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as e,K as t,Q as n,R as r,S as i,W as a,b as o,o as s,q as c,x as l,z as u}from"./_virtual_mf___mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DhP-Lgiq.js";import{Z as d}from"./player-overlays-wniETo4u.js";import{An as f,Bn as p,C as m,Cn as h,En as g,Fn as _,Fs as v,In as y,J as ee,Nn as b,On as x,Pn as S,Rn as te,Sn as ne,Tn as re,Zi as C,bn as w,g as ie,jn as ae,kn as oe,ln as se,na as T,q as ce,wn as E,xn as D,yn as le,zn as ue}from"./src-IW6snE8b.js";import{Vt as O}from"./src-CsxD-27Y.js";import{t as k}from"./clock-DGWYKseh.js";import{t as A}from"./download-DC6CvEwh.js";import{t as de}from"./plus-BVcSfMMt.js";import{t as j}from"./refresh-cw-srKCTv_-.js";import{C as M,J as N,K as P,P as fe,R as F,X as pe,_ as I,f as me,m as he,o as L,p as R,r as z,z as B}from"./index-Cp84SBzW.js";import{t as V}from"./AdminPage-CCD07UMs.js";import{t as H}from"./NodeAddonsSettingsPanel-CAyKEQpD.js";var ge=P(`chevron-up`,[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]]),U=P(`octagon-alert`,[[`path`,{d:`M12 16h.01`,key:`1drbdi`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z`,key:`1fd625`}]]),_e=P(`package`,[[`path`,{d:`M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z`,key:`1a0edw`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}],[`polyline`,{points:`3.29 7 12 12 20.71 7`,key:`ousv84`}],[`path`,{d:`m7.5 4.27 9 5.15`,key:`1c824w`}]]),W=P(`skip-forward`,[[`polygon`,{points:`5 4 15 12 5 20 5 4`,key:`16p6eg`}],[`line`,{x1:`19`,x2:`19`,y1:`5`,y2:`19`,key:`futhcm`}]]),G=P(`upload`,[[`path`,{d:`M12 3v12`,key:`1x0j5s`}],[`path`,{d:`m17 8-5-5-5 5`,key:`7q97r8`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}]]);n();var K=new Set([`completed`,`failed`,`partially-failed`,`cancelled`]),q=new Set([`done`,`failed`,`skipped`]);function ve(e){return!q.has(e.phase)&&!K.has(e.jobState)}function J(e,t){let n=new Map,r=[...e].sort((e,t)=>e.createdAtMs-t.createdAtMs);for(let e of r){let r=K.has(e.state);for(let i of e.tasks)r&&i.finishedAtMs!==null&&t-i.finishedAtMs>6e4||n.set(i.packageName,{jobId:e.jobId,packageName:i.packageName,phase:i.phase,fromVersion:i.fromVersion,toVersion:i.toVersion,error:i.error,jobState:e.state,finishedAtMs:i.finishedAtMs})}return n}function ye(){let{data:e}=x({activeOnly:!0},{refetchOnWindowFocus:!1,refetchInterval:e=>(e.state.data?.length??0)>0?3e3:!1}),{map:t}=v(O.AddonsJobProgress,e=>e.job.jobId);return a(()=>{let n=new Map;for(let t of e??[])n.set(t.jobId,t);for(let[e,r]of t)n.set(e,r.job);return J([...n.values()],Date.now())},[e,t])}var be={queued:{icon:k,cls:`bg-muted text-foreground-subtle`,label:`queued`},fetching:{icon:M,cls:`bg-primary/10 text-primary`,label:`fetching`,spin:!0},staged:{icon:M,cls:`bg-primary/10 text-primary`,label:`staged`,spin:!0},validating:{icon:M,cls:`bg-primary/10 text-primary`,label:`validating`,spin:!0},applying:{icon:M,cls:`bg-primary/10 text-primary`,label:`applying`,spin:!0},restarting:{icon:M,cls:`bg-amber-500/10 text-amber-600 dark:text-amber-400`,label:`restarting`,spin:!0},applied:{icon:M,cls:`bg-primary/10 text-primary`,label:`finalizing`,spin:!0},done:{icon:B,cls:`bg-success/10 text-success`,label:`updated`},failed:{icon:U,cls:`bg-danger/10 text-danger`,label:`failed`},skipped:{icon:W,cls:`bg-muted text-foreground-subtle`,label:`skipped`}};function xe({progress:e}){let t=be[e.phase],n=t.icon,r=e.error??`${e.packageName}: ${e.fromVersion??`?`} → ${e.toVersion}`;return i(`span`,{"data-testid":`addon-job-progress`,className:`inline-flex items-center gap-1 px-1.5 py-0.5 text-[10px] rounded shrink-0 ${t.cls}`,title:r,children:[l(n,{className:`w-2.5 h-2.5 ${t.spin?`animate-spin`:``}`}),t.label,i(`span`,{className:`font-mono`,children:[`→ `,e.toVersion]})]})}function Se({packageName:e,currentVersion:t,installSource:n,onInstall:r,onClose:a,onSelect:s,selectedVersion:c}){let u=n===`upload`||n===`local`,{data:d,isLoading:f}=E({name:e});return i(`div`,{className:`fixed z-50 w-72 rounded-lg border border-border bg-surface shadow-xl overflow-hidden`,style:{top:`auto`,bottom:`auto`},ref:e=>{if(!e)return;let t=e.parentElement?.getBoundingClientRect();if(!t)return;let n=window.innerHeight-t.bottom,r=t.top;n<280&&r>n?(e.style.bottom=`${window.innerHeight-t.top+4}px`,e.style.top=`auto`):(e.style.top=`${t.bottom+4}px`,e.style.bottom=`auto`),e.style.right=`${window.innerWidth-t.right}px`},onClick:e=>e.stopPropagation(),children:[i(`div`,{className:`flex items-center justify-between px-3 py-2 border-b border-border`,children:[l(`span`,{className:`text-[10px] uppercase tracking-wide text-foreground-subtle font-medium`,children:`Versions`}),l(`button`,{type:`button`,onClick:a,className:`text-foreground-subtle hover:text-foreground`,children:l(z,{className:`h-3 w-3`})})]}),u&&i(`div`,{className:`flex items-start gap-2 px-3 py-2 border-b border-border bg-cyan-500/10 text-[10px]`,children:[l(G,{className:`h-3 w-3 mt-0.5 text-cyan-500 shrink-0`}),i(`div`,{className:`text-cyan-700 dark:text-cyan-200`,children:[i(`span`,{className:`font-semibold`,children:[n===`upload`?`Uploaded copy`:`Local copy`,` in place.`]}),` `,`Re-install `,l(`span`,{className:`font-mono`,children:t}),` from npm to track upstream releases again.`]})]}),f&&i(`div`,{className:`flex items-center justify-center gap-2 py-6 text-[10px] text-foreground-subtle`,children:[l(M,{className:`h-3.5 w-3.5 animate-spin`}),`Loading versions...`]}),d&&l(`div`,{className:`max-h-64 overflow-auto divide-y divide-border`,children:d.map(e=>{let n=e.version===t,a=s!==void 0&&e.version===c,d=/-(alpha|beta|rc|dev|canary|next)/i.test(e.version),f=i(o,{children:[l(`span`,{className:`font-mono flex-1 text-left ${n?`text-primary font-semibold`:d?`text-amber-400`:`text-foreground`}`,children:e.version}),n&&l(`span`,{className:`text-[9px] rounded-full px-1.5 py-0.5 font-medium bg-primary/10 text-primary`,children:`current`}),e.distTags.map(e=>l(`span`,{className:`text-[9px] rounded-full px-1.5 py-0.5 font-medium ${e===`latest`?`bg-emerald-500/15 text-emerald-400`:e===`beta`?`bg-amber-500/15 text-amber-400`:`bg-gray-500/15 text-gray-400`}`,children:e},e)),e.deprecated&&l(`span`,{className:`text-[9px] text-red-400 line-through`,children:`deprecated`}),l(`span`,{className:`text-[9px] text-foreground-subtle shrink-0`,children:new Date(e.publishedAt).toLocaleDateString()})]});return s?i(`button`,{type:`button`,"aria-label":`Select ${e.version}`,onClick:()=>s(e.version),className:`w-full flex items-center gap-2 px-3 py-2 text-[11px] ${a?`bg-primary/5`:`hover:bg-surface-hover`} transition-colors`,children:[f,a?l(B,{className:`h-3 w-3 text-primary shrink-0`}):l(`span`,{className:`w-3 shrink-0`})]},e.version):i(`div`,{className:`flex items-center gap-2 px-3 py-2 text-[11px] ${n?`bg-primary/5`:`hover:bg-surface-hover`} transition-colors`,children:[f,n&&!u?l(B,{className:`h-3 w-3 text-primary shrink-0`}):l(`button`,{type:`button`,onClick:()=>r(e.version),className:`shrink-0 rounded p-0.5 hover:bg-primary/20 text-foreground-subtle hover:text-primary transition-colors`,title:n?`Re-install ${e.version} from npm`:`Install ${e.version}`,children:l(A,{className:`h-3 w-3`})})]},e.version)})}),d&&d.length===0&&l(`div`,{className:`py-4 text-center text-[10px] text-foreground-subtle`,children:`No versions found`})]})}var Y={queued:{icon:k,bg:`bg-muted text-foreground-subtle`,label:`queued`},updating:{icon:M,bg:`bg-primary/10 text-primary`,label:`updating`,spin:!0},"done-pending-restart":{icon:j,bg:`bg-amber-500/10 text-amber-700`,label:`pending restart`},done:{icon:B,bg:`bg-success/10 text-success`,label:`done`},failed:{icon:U,bg:`bg-danger/10 text-danger`,label:`failed`}};function Ce({item:e}){let t=Y[e.status],n=t.icon;return i(`span`,{className:`inline-flex items-center gap-1 px-1.5 py-0.5 text-[10px] rounded ${t.bg}`,title:e.error,children:[l(n,{className:`w-2.5 h-2.5 ${t.spin?`animate-spin`:``}`}),t.label]})}n();var X=`device-export`;function Z(e){return e.capabilities.some(e=>(typeof e==`string`?e:e.name)===X)}function we({isBundle:e,installSource:t,addonId:n,iconPath:r,color:a}){let[o,s]=c(!1),u=a?{backgroundColor:`${a.startsWith(`#`)?a:`#${a}`}26`}:void 0,d=e?`bg-indigo-500/20 text-indigo-700 dark:text-indigo-300`:`bg-purple-500/20 text-purple-700 dark:text-purple-300`,f=n&&r?`/api/addon-assets/${n}/${r}`:null,p=!!f&&!o;return i(`div`,{className:`relative flex-shrink-0`,children:[l(`div`,{className:`h-9 w-9 rounded-lg flex items-center justify-center ${u?``:d}`,style:u,children:p?l(`img`,{src:f,alt:n,className:`h-5 w-5`,onError:()=>s(!0)}):l(e?_e:I,{className:`h-4 w-4`})}),t===`local`&&l(`span`,{className:`absolute -top-1.5 -left-1.5 text-[7px] font-bold leading-none bg-orange-500 text-white px-1 py-0.5 rounded -rotate-12 shadow-sm`,children:`DEV`}),t===`npm`&&l(`span`,{className:`absolute -top-1 -left-1 w-4 h-4 rounded bg-[#cb3837] flex items-center justify-center -rotate-12 shadow-sm`,children:l(`svg`,{viewBox:`0 0 780 250`,className:`w-[11px] h-[11px]`,children:l(`path`,{fill:`#fff`,d:`M240 250h100V50h100v200h340V0H0v250z`})})}),t===`upload`&&l(`span`,{className:`absolute -top-1.5 -left-1.5 flex items-center justify-center h-4 w-4 rounded bg-cyan-500 -rotate-12 shadow-sm`,children:l(G,{className:`h-2.5 w-2.5 text-white`})})]})}function Te({version:e,availableUpdate:t,selectedVersion:n,isUpdating:r,installSource:a,disabled:o,onUpdate:s,onOpenPicker:c,children:u}){if(r)return i(`span`,{className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border border-blue-500/30 bg-blue-500/10 text-blue-400 shrink-0`,children:[l(M,{className:`h-3 w-3 animate-spin`}),`Updating…`]});if(t){let r=n??t;return i(`div`,{className:`relative inline-flex items-center gap-1 shrink-0`,children:[s&&i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),s()},disabled:o,className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-semibold border border-blue-500/30 bg-blue-500/10 text-blue-400 hover:bg-blue-500/20 disabled:opacity-50 disabled:cursor-not-allowed transition-colors`,title:`Update to ${r}`,children:[l(A,{className:`h-3 w-3`}),`Update`]}),i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),c()},disabled:o,"aria-label":`Select version to install`,title:`Installed ${e} — update available. Selected ${r}; tap to choose another version.`,className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-bold font-mono border border-amber-500/40 bg-amber-500/15 text-amber-500 hover:bg-amber-500/25 animate-pulse disabled:opacity-50 disabled:cursor-not-allowed transition-colors`,children:[l(`span`,{className:`font-normal opacity-70`,children:e}),l(`span`,{className:`font-normal opacity-70`,children:`→`}),r,l(F,{className:`h-3 w-3`})]}),u]})}return i(`div`,{className:`relative inline-flex items-center gap-1 shrink-0`,children:[i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),c()},disabled:o,className:[`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-bold font-mono border transition-colors disabled:opacity-50 disabled:cursor-not-allowed`,a===`local`?`border-orange-500/30 bg-orange-500/10 text-orange-400 hover:bg-orange-500/20`:`border-emerald-500/30 bg-emerald-500/10 text-emerald-400 hover:bg-emerald-500/20`].join(` `),title:`Version ${e} — tap to view all versions`,children:[e,l(F,{className:`h-3 w-3 opacity-50`})]}),u]})}function Ee({addonId:e}){let t=s(),{data:n=`inherit`}=D({addonId:e}),r=_({onSuccess:()=>{t.invalidateQueries({queryKey:[[`addons`,`getAddonAutoUpdate`]]})}});return l(`div`,{className:`flex rounded-lg border border-border overflow-hidden text-[10px] font-medium`,children:[`inherit`,`off`,`latest`,`beta`].map(t=>l(`button`,{type:`button`,onClick:n=>{n.stopPropagation(),r.mutate({addonId:e,channel:t})},disabled:r.isPending,className:`px-2.5 py-1 transition-colors capitalize ${n===t?t===`inherit`?`bg-gray-700/50 text-gray-700 dark:text-gray-300`:t===`off`?`bg-gray-700 text-gray-700 dark:text-gray-300`:t===`latest`?`bg-blue-500/20 text-blue-400`:`bg-amber-500/20 text-amber-400`:`bg-transparent text-foreground-subtle hover:bg-surface-hover`} ${t===`inherit`?``:`border-l border-border`}`,children:t},t))})}function De({addon:e,agents:t=[],clusterStatus:n,hideVersion:r,availableUpdate:a,onUpdate:f,isUpdating:p,jobProgress:h,bundle:g,bulkItem:_,disabledByBulk:v,isSystem:y}){let[x,S]=c(!1),[te,ne]=c(!1),[C,w]=c(!1),[ie,oe]=c(null);u(()=>{oe(null)},[a]);let T=ie??a,[E,D]=c(!1),[le,O]=c(!1),[k,A]=c(`logs`),M=s(),P=d(),fe=N(),pe=se(),{manifest:I}=e,R=e.installedOn??[],B=!g&&!I.protected&&I.removable!==!1,V=!!g,W=g?.displayName??I.name,G=g?.packageName??I.packageName,K=g?.version??I.packageVersion??I.version,q=g?.installSource??e.installSource,ve=g?g.bundle?.description??g.addons[0]?.manifest.description:I.description,J=ue({onSuccess:()=>{M.invalidateQueries({queryKey:[[`addons`]]}),M.invalidateQueries({queryKey:[[`addonPages`]]}),M.invalidateQueries({queryKey:[[`capabilities`]]})}}),ye=ae({onSuccess:()=>{M.invalidateQueries({queryKey:[[`addons`]]})}}),be=re({onSuccess:()=>{M.invalidateQueries({queryKey:[[`addons`]]}),M.invalidateQueries({queryKey:[[`addonPages`]]}),M.invalidateQueries({queryKey:[[`capabilities`]]}),M.invalidateQueries({queryKey:[[`integrations`]]})}}),Y=b({onSuccess:()=>{M.invalidateQueries({queryKey:[[`addons`]]}),M.invalidateQueries({queryKey:[[`alerts`]]})}}),X=e.health,Q=X?.phase===`failed`&&!X.inGracePeriod,Oe=Q&&X?.nextRetryAt&&!X.retrying;return i(`div`,{className:`rounded-lg border bg-surface overflow-hidden ${Q?`border-red-500/50`:`border-border`}`,children:[Q&&X&&i(`div`,{className:`bg-danger/10 border-b border-danger/30 px-4 py-2.5 flex items-start gap-2.5`,children:[l(U,{className:`h-4 w-4 text-danger shrink-0 mt-0.5`}),i(`div`,{className:`flex-1 min-w-0`,children:[i(`div`,{className:`text-xs font-semibold text-danger`,children:[`Failed to load (attempt #`,X.retryCount,`)`]}),l(`div`,{className:`text-[11px] text-foreground mt-0.5 break-words font-mono`,children:X.lastError?.message??`Unknown error`}),Oe&&X.nextRetryAt&&i(`div`,{className:`text-[10px] text-foreground-subtle mt-1`,children:[`Auto-retry at `,new Date(X.nextRetryAt).toLocaleTimeString()]})]}),i(`button`,{type:`button`,disabled:Y.isPending||X.retrying,onClick:e=>{e.stopPropagation(),Y.mutate({packageName:G})},className:`inline-flex items-center gap-1.5 rounded-md px-2.5 py-1 text-[11px] font-semibold border border-red-400/40 bg-red-400/10 text-red-700 dark:text-red-300 hover:bg-red-400/20 disabled:opacity-50 disabled:cursor-not-allowed transition-colors shrink-0`,title:`Reset retry counter and force immediate reload`,children:[l(j,{className:`h-3 w-3 ${Y.isPending||X.retrying?`animate-spin`:``}`}),`Retry now`]})]}),i(`div`,{className:`flex items-start gap-3 px-4 py-3`,children:[l(we,{isBundle:V||!!I.components&&I.components.length>1,installSource:q,addonId:V?g.addons[0]?.manifest.id:I.id,iconPath:V?g.bundle?.icon??g.addons[0]?.manifest.icon:I.icon,color:V?g.addons[0]?.manifest.color:I.color}),i(`div`,{className:`flex-1 min-w-0`,children:[i(`div`,{className:`flex items-start justify-between gap-2`,children:[l(`span`,{className:`text-sm font-semibold text-foreground truncate min-w-0`,children:W}),!r&&l(Te,{version:K,availableUpdate:a,...T===void 0?{}:{selectedVersion:T},isUpdating:p,installSource:q,disabled:v,...f&&T!==void 0?{onUpdate:()=>f(T)}:{},onOpenPicker:()=>w(e=>!e),children:C&&l(Se,{packageName:G,currentVersion:K,...q?{installSource:q}:{},...a!==void 0&&T!==void 0?{selectedVersion:T,onSelect:e=>{oe(e),w(!1)}}:{},onInstall:e=>{w(!1),be.mutate({packageName:G,version:e})},onClose:()=>w(!1)})})]}),i(`div`,{className:`flex flex-wrap items-center gap-x-1.5 gap-y-1 mt-0.5`,children:[G!==W&&l(`span`,{className:`text-[10px] text-foreground-subtle font-mono truncate max-w-full`,children:G}),V&&i(`span`,{className:`text-[10px] rounded-full bg-primary/10 text-primary px-2 py-0.5 font-medium shrink-0 inline-flex items-center gap-1`,children:[l(_e,{className:`h-3 w-3`}),g.addons.length]}),y&&i(`span`,{className:`text-[10px] rounded-full bg-amber-500/15 text-amber-700 dark:text-amber-300 px-2 py-0.5 font-medium shrink-0 inline-flex items-center gap-1`,title:`System package — updating restarts the hub`,children:[l(j,{className:`h-3 w-3`}),`System`]}),_!=null&&l(Ce,{item:_}),h!=null&&l(xe,{progress:h})]}),ve&&l(`p`,{className:`text-[10px] text-foreground-subtle mt-1 line-clamp-1`,children:ve}),!V&&e.process&&i(`div`,{className:`flex flex-wrap items-center gap-1.5 mt-1`,children:[l(`span`,{className:`text-[9px] rounded-full px-1.5 py-0.5 font-medium ${e.process.mode===`forked`?`bg-blue-500/15 text-blue-400`:`bg-gray-500/15 text-gray-400`}`,children:e.process.mode===`forked`?`forked`:`in-process`}),e.process.pid!=null&&i(`span`,{className:`text-[9px] font-mono text-foreground-subtle`,children:[`PID `,e.process.pid]}),l(`span`,{className:`text-[9px] rounded-full px-1.5 py-0.5 font-medium ${e.process.state===`running`?`bg-emerald-500/15 text-emerald-400`:e.process.state===`crashed`||e.process.state===`failed`?`bg-red-500/15 text-red-400`:`bg-gray-500/15 text-gray-400`}`,children:e.process.state})]})]})]}),!V&&i(`div`,{className:`flex items-center gap-1 px-4 py-1.5 border-t border-border/50 bg-surface-hover/20`,children:[i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),ye.mutate({addonId:I.id})},disabled:ye.isPending||v,className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border border-border text-foreground-subtle hover:text-blue-400 hover:border-blue-500/30 hover:bg-blue-500/10 disabled:opacity-50 transition-colors`,children:[l(j,{className:`h-3 w-3 ${ye.isPending?`animate-spin`:``}`}),`Restart`]}),i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),D(e=>!e)},className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border transition-colors ${E?`border-primary/30 bg-primary/10 text-primary`:`border-border text-foreground-subtle hover:text-foreground hover:border-primary/30 hover:bg-primary/10`}`,children:[l(he,{className:`h-3 w-3`}),`Logs`]}),!V&&i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),O(!0)},className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border transition-colors ${le?`border-primary/30 bg-primary/10 text-primary`:`border-border text-foreground-subtle hover:text-foreground hover:border-primary/30 hover:bg-primary/10`}`,children:[l(me,{className:`h-3 w-3`}),`Settings`]}),l(`div`,{className:`flex-1`}),B&&i(`button`,{type:`button`,onClick:async e=>{e.stopPropagation(),await pe({title:`Uninstall ${I.name}?`,message:`This will remove the addon package and all its data. This action cannot be undone.`,confirmLabel:`Uninstall`,variant:`danger`})&&J.mutate({packageName:I.packageName})},disabled:J.isPending||v,className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border border-border text-foreground-subtle hover:text-red-400 hover:border-red-500/30 hover:bg-red-500/10 disabled:opacity-50 transition-colors`,children:[l(L,{className:`h-3 w-3`}),J.isPending?`Removing...`:`Uninstall`]})]}),n&&n.nodes.length>1&&!V&&i(`div`,{className:`border-t border-border px-4 py-2 bg-muted/10`,children:[l(`div`,{className:`text-[10px] font-medium text-foreground-subtle mb-1.5`,children:`Cluster Deployment`}),l(`div`,{className:`space-y-1`,children:n.nodes.map(e=>i(`div`,{className:`flex items-center gap-2 text-[10px]`,children:[l(`div`,{className:`h-1.5 w-1.5 rounded-full shrink-0 ${e.status===`offline`?`bg-muted-foreground/30`:e.synced?`bg-success`:`bg-amber-500`}`}),l(`span`,{className:`font-medium text-foreground min-w-[60px]`,children:e.name}),l(`span`,{className:`font-mono text-foreground-subtle`,children:e.version}),!e.synced&&e.status!==`offline`&&l(`span`,{className:`text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-400 border border-amber-500/20`,children:`outdated`}),e.status===`offline`&&l(`span`,{className:`text-[9px] px-1 py-0.5 rounded bg-muted text-muted-foreground`,children:`offline`}),e.synced&&e.status!==`offline`&&l(`span`,{className:`text-[9px] text-success`,children:`synced`})]},e.nodeId))})]}),E&&!V&&i(`div`,{className:`border-t border-border`,children:[i(`div`,{className:`flex items-center px-4 py-1 bg-surface-hover/20 border-b border-border/50`,children:[i(`div`,{className:`flex rounded border border-border overflow-hidden text-[9px]`,children:[l(`button`,{type:`button`,onClick:()=>A(`logs`),className:`px-2 py-0.5 transition-colors ${k===`logs`?`bg-primary/10 text-primary`:`text-foreground-subtle hover:bg-surface-hover`}`,children:`Logs`}),l(`button`,{type:`button`,onClick:()=>A(`events`),className:`px-2 py-0.5 border-l border-border transition-colors ${k===`events`?`bg-primary/10 text-primary`:`text-foreground-subtle hover:bg-surface-hover`}`,children:`Events`})]}),l(`div`,{className:`flex-1`}),l(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),D(!1)},className:`text-foreground-subtle hover:text-foreground`,children:l(z,{className:`h-3.5 w-3.5`})})]}),k===`logs`&&l(ee,{addonId:I.id,maxHeight:`max-h-64`,showFilters:!1}),k===`events`&&l(ce,{addonId:I.id,category:`addon.*`,maxHeight:`max-h-64`})]}),V&&i(o,{children:[l(`button`,{type:`button`,onClick:()=>S(e=>!e),className:`w-full flex items-center justify-center border-t border-border py-1 hover:bg-surface-hover/50 transition-colors`,children:l(x?ge:F,{className:`h-3.5 w-3.5 text-foreground-subtle`})}),x&&l(`div`,{className:`border-t border-border px-3 py-2 space-y-2`,children:g.addons.map(e=>l(De,{addon:e,agents:t,hideVersion:!0},e.manifest.id))})]}),le&&!V&&l(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4`,onClick:()=>O(!1),children:i(`div`,{className:`w-full max-w-lg max-h-[80vh] rounded-xl border border-border bg-surface shadow-2xl flex flex-col overflow-hidden`,onClick:e=>e.stopPropagation(),children:[i(`div`,{className:`flex items-center justify-between px-5 py-3 border-b border-border flex-shrink-0`,children:[i(`div`,{className:`flex items-center gap-2`,children:[l(me,{className:`h-4 w-4 text-primary`}),i(`h2`,{className:`text-sm font-semibold text-foreground`,children:[W,` Settings`]})]}),l(`button`,{onClick:()=>O(!1),className:`text-foreground-subtle hover:text-foreground transition-colors p-1 rounded`,children:l(z,{className:`h-4 w-4`})})]}),i(`div`,{className:`flex-1 overflow-y-auto px-5 py-4 space-y-4`,children:[l(`div`,{className:`text-[10px] text-foreground-subtle mb-2`,children:`Cluster-wide settings — one value for every node. Per-node settings live under Cluster → the node → Settings.`}),l(H,{nodeId:null,addonIds:[I.id],level:`global`,fieldScope:`cluster`,emptyMessage:`This addon exposes no cluster-wide settings. Anything it can configure is per-node — open it from Cluster → the node → Settings.`}),Z(I)&&i(`div`,{children:[l(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:`Device export`}),l(m,{addonId:I.id,trpc:P.trpcClient,onOpenDevice:e=>fe(`/devices/${e}`)})]}),q===`npm`&&i(`div`,{children:[l(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:`Auto-Update`}),l(Ee,{addonId:I.id})]}),I.components&&I.components.length>0&&i(`div`,{children:[i(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:[`Components (`,I.components.length,`)`]}),l(`div`,{className:`flex flex-wrap gap-1`,children:I.components.map(e=>l(`span`,{className:`text-[10px] rounded bg-background border border-border px-1.5 py-0.5 text-foreground-subtle font-mono`,children:e},e))})]}),t.length>=2&&i(`div`,{children:[l(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:`Installed on`}),i(`div`,{className:`flex items-center gap-1.5 flex-wrap`,children:[R.length===0&&l(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Hub (local)`}),R.map(e=>l(`span`,{className:`rounded-full bg-surface-hover border border-border px-2 py-0.5 text-[10px] text-foreground-subtle`,children:e},e)),i(`div`,{className:`relative`,children:[i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),ne(e=>!e)},className:`inline-flex items-center gap-1 rounded-full border border-dashed border-border px-2 py-0.5 text-[10px] text-foreground-subtle hover:text-foreground hover:border-primary transition-colors`,title:`Install on more agents`,children:[l(de,{className:`h-3 w-3`}),`Add agent`]}),te&&i(`div`,{className:`absolute left-0 top-full mt-1 z-10 min-w-[160px] rounded-md border border-border bg-surface shadow-lg overflow-hidden`,children:[t.filter(e=>!e.isHub&&!R.includes(e.name)).map(e=>l(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),ne(!1)},className:`w-full text-left px-3 py-1.5 text-[10px] text-foreground hover:bg-surface-hover transition-colors`,children:e.name},e.id)),t.filter(e=>!e.isHub&&!R.includes(e.name)).length===0&&l(`div`,{className:`px-3 py-1.5 text-[10px] text-foreground-subtle`,children:`No available agents`})]})]})]})]})]}),l(`div`,{className:`flex items-center justify-end px-5 py-3 border-t border-border flex-shrink-0`,children:l(`button`,{type:`button`,onClick:()=>O(!1),className:`rounded-lg border border-border px-3 py-1.5 text-xs font-medium text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors`,children:`Close`})})]})})]})}n();var Q=`.tgz,.tar.gz,.zip`;function Oe({onUploadSuccess:n}){let[r,a]=c(!1),s=t(null),u=e(async e=>{a(!0);let t=new FormData;t.append(`file`,e);let r=localStorage.getItem(`camstack_admin_token`)??``;try{(await(await fetch(`/api/addons/upload`,{method:`POST`,headers:{Authorization:`Bearer ${r}`},body:t})).json()).success&&n()}finally{a(!1)}},[n]);return i(o,{children:[l(`input`,{ref:s,type:`file`,accept:Q,onChange:e(e=>{let t=e.target.files?.[0];t&&u(t),e.target.value=``},[u]),className:`hidden`}),i(`button`,{type:`button`,onClick:()=>s.current?.click(),disabled:r,className:`flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md bg-surface hover:bg-surface-hover border border-border disabled:opacity-50 transition-colors`,children:[r?l(M,{className:`w-3.5 h-3.5 animate-spin`}):l(G,{className:`w-3.5 h-3.5`}),r?`Uploading...`:`Upload`]})]})}n();var ke=[{seconds:900,label:`15m`},{seconds:3600,label:`1h`},{seconds:21600,label:`6h`},{seconds:43200,label:`12h`},{seconds:86400,label:`24h`}],Ae=new Set([`@camstack/system`,`@camstack/types`,`@camstack/sdk`,`@camstack/shm-ring`,`@camstack/ui-library`]);function je(e){return e!==void 0&&Ae.has(e)}function Me(e,t){let n=e??`hub-only`;return n===`any-node`?!0:n===`hub-only`?t:!t}function Ne(e){let t=e;if(!t?.manifest)return null;let n={...t.manifest,name:t.manifest.name??t.manifest.id,version:t.manifest.version??`0.0.0`,capabilities:t.manifest.capabilities??[]},r=t.process,i=r?{pid:r.pid,mode:r.mode===`forked`?`forked`:`in-process`,state:r.state??`unknown`}:void 0,a=t.health,o=t.declaration?.execution,s=t.manifest.execution,c=o?.placement??s?.placement;return{manifest:n,enabled:!0,source:t.source,installSource:t.installSource,installedOn:[],...i?{process:i}:{},hasBackup:t.hasBackup,...a?{health:a}:{},...c?{placement:c}:{}}}function Pe(e){let t=new Map,n=[];for(let r of e){let e=r.manifest.packageName;if(!e){n.push(r);continue}let i=t.get(e);if(i)i.addons.push(r);else{let n=r.manifest.bundle,i={packageName:e,displayName:n?.displayName??r.manifest.packageDisplayName??r.manifest.name,version:r.manifest.packageVersion,addons:[r],...r.installSource===void 0?{}:{installSource:r.installSource},...n===void 0?{}:{bundle:n}};t.set(e,i)}}let r=[];for(let e of t.values())e.bundle!==void 0||e.addons.length>=2?r.push({bundle:e,representative:e.addons[0]}):r.push(e.addons[0]);return r.push(...n),r}function $(e){return`bundle`in e}function Fe({addons:n,clusterStatus:o,selectedNode:d,onRefresh:f,isRefreshing:m}){let g=s(),[_,v]=c(``),ee=r(_),[b,x]=c(!1),C=t(null);u(()=>{if(!b)return;let e=e=>{C.current&&!C.current.contains(e.target)&&x(!1)};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[b]);let{data:w}=oe({nodeId:d.id}),ie=a(()=>{let e=new Map;for(let t of w??[])e.set(t.name,t.latestVersion);return e},[w]),ae=a(()=>(w??[]).filter(e=>!e.isSystem).length,[w]),[T,ce]=c(()=>new Set),[E,D]=c(()=>new Map),ue=e(e=>{ce(t=>new Set(t).add(e))},[]),O=e(e=>{ce(t=>{if(!t.has(e))return t;let n=new Set(t);return n.delete(e),n})},[]),k=e((e,t)=>{D(n=>new Map(n).set(e,t))},[]),de=e(e=>{D(t=>{if(!t.has(e))return t;let n=new Map(t);return n.delete(e),n})},[]),N=p({onMutate:e=>{ue(e.name),de(e.name)},onSuccess:(e,t)=>{O(t.name);let n=e;if(n&&n.success===!1){k(t.name,n.error??`Update failed (no error message returned by server)`);return}g.invalidateQueries({queryKey:[[`addons`]]}),g.invalidateQueries({queryKey:[[`addons`,`listUpdates`]]})},onError:(e,t)=>{O(t.name),k(t.name,e instanceof Error?e.message:String(e))}}),P=ye(),F=t(new Set);u(()=>{let e=new Set;for(let[t,n]of P)ve(n)&&e.add(t);let t=[...F.current].some(t=>!e.has(t));F.current=e,t&&(g.invalidateQueries({queryKey:[[`addons`]]}),g.invalidateQueries({queryKey:[[`addons`,`listUpdates`]]}))},[P,g]);let{data:I}=ne(void 0),me=le({onSuccess:()=>{g.invalidateQueries({queryKey:[[`addons`,`getAutoUpdateSettings`]]})}}),he=y({onSuccess:()=>{g.invalidateQueries({queryKey:[[`addons`,`getAutoUpdateSettings`]]})}}),{data:L,isFetching:z}=S({query:ee||void 0},{enabled:b}),V=te(),{data:H}=h(void 0),ge=H?.requestedAt,[U,_e]=c(null),[W,G]=c(!1);u(()=>{if(H?.kind===`framework-bulk-update`&&H.requestedAt!==U){_e(H.requestedAt),G(!0);let e=window.setTimeout(()=>G(!1),6e3);return()=>window.clearTimeout(e)}},[ge,U,H]),se();let K=e(async()=>{let e=(w??[]).filter(e=>!e.isSystem);if(e.length!==0){if(!d.isHub){for(let t of e)await N.mutateAsync({name:t.name,version:t.latestVersion,nodeId:d.id});return}await V.mutateAsync({kind:`update`,targets:e.map(e=>({name:e.name,version:e.latestVersion})),nodeIds:[d.id]})}},[w,d.id,d.isHub,V,N]),q=re({onSuccess:()=>{g.invalidateQueries({queryKey:[[`addons`]]}),g.invalidateQueries({queryKey:[[`addonPages`]]}),g.invalidateQueries({queryKey:[[`capabilities`]]}),g.invalidateQueries({queryKey:[[`integrations`]]})}}),[J,be]=c(`type`),[xe,Se]=c(()=>typeof window>`u`?`grouped`:window.localStorage.getItem(`camstack.addons.viewMode`)===`flat`?`flat`:`grouped`),Y=e=>{Se(e),typeof window<`u`&&window.localStorage.setItem(`camstack.addons.viewMode`,e)},[Ce,X]=pe(),Z=Ce.get(`capability`),we=a(()=>{let e=n.filter(e=>!je(e.manifest.packageName));return d.isHub||(e=e.filter(e=>Me(e.placement,d.isHub))),Z&&(e=e.filter(e=>(e.manifest.capabilities??[]).some(e=>(typeof e==`string`?e:e.name)===Z))),e},[n,d.isHub,Z]),Te=()=>{let e=new URLSearchParams(Ce);e.delete(`capability`),X(e,{replace:!0})},Ee=xe===`flat`?we:Pe(we),Q=a(()=>{let e=[...Ee];switch(J){case`type`:e.sort((e,t)=>{let n=+!$(e),r=+!$(t);if(n!==r)return n-r;let i=$(e)?e.bundle.displayName:e.manifest.name,a=$(t)?t.bundle.displayName:t.manifest.name;return i.localeCompare(a)});break;case`name`:e.sort((e,t)=>{let n=$(e)?e.bundle.displayName:e.manifest.name,r=$(t)?t.bundle.displayName:t.manifest.name;return n.localeCompare(r)});break;case`source`:e.sort((e,t)=>{let n=$(e)?e.bundle.installSource??``:e.installSource??``,r=$(t)?t.bundle.installSource??``:t.installSource??``;return n.localeCompare(r)});break}return e},[Ee,J]);return i(`div`,{className:`space-y-4`,children:[[...E.entries()].map(([e,t])=>l(`div`,{className:`rounded-md border border-danger/30 bg-danger/5 px-3 py-2 text-[11px]`,children:i(`div`,{className:`flex items-start justify-between gap-3`,children:[i(`div`,{className:`space-y-0.5`,children:[i(`div`,{className:`font-medium text-danger`,children:[`Failed to update `,e]}),l(`div`,{className:`text-foreground-subtle font-mono`,children:t})]}),l(`button`,{type:`button`,onClick:()=>de(e),className:`text-foreground-subtle hover:text-foreground text-[10px]`,children:`dismiss`})]})},e)),i(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[i(`div`,{className:`flex items-center gap-1.5`,children:[l(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Sort:`}),i(`select`,{value:J,onChange:e=>be(e.target.value),className:`rounded-md border border-border bg-surface px-2 py-1.5 text-[11px] text-foreground focus:outline-none focus:border-primary/50`,children:[l(`option`,{value:`type`,children:`Bundles first`}),l(`option`,{value:`name`,children:`Name`}),l(`option`,{value:`source`,children:`Install source`})]})]}),i(`div`,{className:`flex items-center gap-1.5`,children:[l(`span`,{className:`text-[10px] text-foreground-subtle`,children:`View:`}),l(`div`,{className:`flex rounded-md border border-border overflow-hidden text-[10px] font-medium`,children:[`grouped`,`flat`].map(e=>l(`button`,{type:`button`,onClick:()=>Y(e),className:`px-2.5 py-1.5 transition-colors capitalize ${xe===e?`bg-primary/10 text-primary`:`bg-transparent text-foreground-subtle hover:bg-surface-hover`}`,title:e===`grouped`?`Group multi-addon packages into a bundle card`:`Show every addon as its own card`,children:e},e))})]}),d.isHub&&i(`div`,{className:`flex items-center gap-1.5`,children:[l(j,{className:`h-3 w-3 text-foreground-subtle`}),l(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Auto-Update:`}),l(`div`,{className:`flex rounded-md border border-border overflow-hidden text-[10px] font-medium`,children:[`off`,`latest`,`beta`].map(e=>l(`button`,{type:`button`,onClick:()=>me.mutate({channel:e}),disabled:me.isPending,className:`px-2.5 py-1.5 transition-colors capitalize ${I?.channel===e?e===`off`?`bg-gray-700 text-gray-200`:e===`latest`?`bg-blue-500/20 text-blue-400`:`bg-amber-500/20 text-amber-400`:`bg-transparent text-foreground-subtle hover:bg-surface-hover`} ${e===`off`?``:`border-l border-border`}`,children:e},e))})]}),d.isHub&&i(`div`,{className:`flex items-center gap-1.5`,children:[l(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Check every:`}),l(`select`,{className:`rounded-md border border-border bg-transparent px-1.5 py-1 text-[10px] font-medium text-foreground-subtle`,value:I?.updateCheckIntervalSeconds??21600,disabled:he.isPending||I===void 0,onChange:e=>{I!==void 0&&he.mutate({channel:I.channel,updateCheckIntervalSeconds:Number(e.target.value)})},children:ke.map(e=>l(`option`,{value:e.seconds,children:e.label},e.seconds))})]}),ae>0&&i(`button`,{type:`button`,onClick:()=>void K(),disabled:V.isPending,className:`flex items-center gap-1.5 px-2.5 py-1.5 text-[11px] rounded-md bg-blue-500/10 text-blue-400 hover:bg-blue-500/20 border border-blue-500/30 disabled:opacity-50 transition-colors font-medium`,children:[V.isPending?l(M,{className:`w-3 h-3 animate-spin`}):l(A,{className:`w-3 h-3`}),V.isPending?`Updating…`:`Update All (${ae})`]}),i(`button`,{type:`button`,onClick:f,disabled:m||V.isPending,className:`flex items-center gap-1.5 px-2.5 py-1.5 text-[11px] rounded-md bg-surface hover:bg-surface-hover border border-border disabled:opacity-50 transition-colors`,children:[l(j,{className:`w-3 h-3 ${m?`animate-spin`:``}`}),`Refresh`]})]}),i(`div`,{className:`flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3`,children:[i(`div`,{className:`relative flex-1 min-w-0 sm:min-w-[200px]`,ref:C,children:[l(R,{className:`absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-foreground-subtle`}),l(`input`,{type:`text`,value:_,onChange:e=>{v(e.target.value),x(!0)},onFocus:()=>x(!0),placeholder:`Search addons on npm...`,disabled:V.isPending,className:`w-full rounded-lg border border-border bg-background pl-9 pr-3 py-2 text-xs text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-1 focus:ring-primary disabled:opacity-50 disabled:cursor-not-allowed`}),z&&l(M,{className:`absolute right-2.5 top-1/2 -translate-y-1/2 h-3 w-3 text-foreground-subtle animate-spin`}),b&&L&&L.length>0&&i(`div`,{className:`absolute left-0 right-0 top-full mt-1 z-40 rounded-lg border border-border bg-surface shadow-xl overflow-hidden`,children:[L.length>0&&i(`div`,{className:`px-3 py-1.5 text-[10px] uppercase tracking-wide text-foreground-subtle border-b border-border`,children:[`npm results (`,L.length,`)`]}),L&&L.length>0&&l(`div`,{className:`max-h-72 overflow-auto divide-y divide-border`,children:L.map(e=>i(`div`,{className:`flex items-center gap-3 px-3 py-2 hover:bg-surface-hover transition-colors`,children:[l(`div`,{className:`w-6 h-6 rounded-md bg-primary/10 flex items-center justify-center text-primary text-[9px] font-bold shrink-0`,children:e.name.replace(`@camstack/addon-`,``).charAt(0).toUpperCase()}),i(`div`,{className:`flex-1 min-w-0`,children:[i(`div`,{className:`flex items-baseline gap-2 min-w-0`,children:[l(`span`,{className:`text-[11px] font-semibold break-words`,children:e.name.replace(/^@camstack\/(addon-)?/,``)}),i(`span`,{className:`text-[10px] text-foreground-subtle shrink-0`,children:[`v`,e.version]})]}),l(`div`,{className:`font-mono text-[9px] text-foreground-subtle/80 truncate`,children:e.name}),e.description&&l(`div`,{className:`text-[10px] text-foreground-subtle truncate`,children:e.description})]}),e.installed?i(`span`,{className:`inline-flex items-center gap-1 px-2 py-1 text-[10px] font-medium rounded-md border border-emerald-500/30 bg-emerald-500/10 text-emerald-400 shrink-0`,children:[l(B,{className:`h-3 w-3`}),e.installedVersion??`Installed`]}):i(`button`,{type:`button`,onClick:()=>q.mutate({packageName:e.name}),disabled:q.isPending,className:`inline-flex items-center gap-1 px-2 py-1 text-[10px] font-medium rounded-md bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50 transition-colors shrink-0`,children:[q.isPending?l(M,{className:`h-3 w-3 animate-spin`}):l(A,{className:`h-3 w-3`}),`Install`]})]},e.name))})]})]}),l(Oe,{onUploadSuccess:()=>{g.invalidateQueries({queryKey:[[`addons`]]}),f()}})]}),Z&&i(`div`,{className:`flex items-center gap-2 px-3 py-2 rounded-lg bg-primary/10 border border-primary/30 text-sm`,children:[l(`span`,{className:`text-foreground-subtle`,children:`Filtering by capability:`}),l(`span`,{className:`font-mono text-primary font-semibold`,children:Z}),l(`button`,{type:`button`,onClick:Te,className:`ml-auto text-xs text-foreground-subtle hover:text-foreground underline`,children:`Clear`})]}),W&&i(`div`,{className:`fixed top-[calc(env(safe-area-inset-top)+1rem)] right-[calc(env(safe-area-inset-right)+1rem)] z-50 flex items-start gap-2 px-3 py-2.5 rounded-md border border-green-500/30 bg-green-500/10 shadow-lg backdrop-blur-sm max-w-sm pointer-events-auto`,children:[l(fe,{className:`w-4 h-4 shrink-0 mt-0.5 text-green-400`}),i(`div`,{children:[l(`div`,{className:`text-[11px] font-semibold text-foreground`,children:`Bulk update completed`}),l(`div`,{className:`text-[10px] text-foreground-subtle mt-0.5`,children:`System packages updated — hub restarted successfully.`})]})]}),we.length===0&&l(`div`,{className:`text-xs text-foreground-subtle`,children:n.length===0?`No addons installed`:Z?`No installed addons declare the "${Z}" capability. Browse the npm catalog above to find a compatible addon.`:`No addons compatible with ${d.name} (placement filter active)`}),l(`div`,{className:`space-y-2`,children:Q.map(e=>{let t=$(e)?e.bundle.packageName:e.manifest.packageName,n=ie.get(t),r=$(e)?e.representative:e,i=n?e=>N.mutate({name:t,version:e,nodeId:d.id}):void 0,a=P.get(t)??null,s=a!==null&&ve(a);return l(De,{addon:r,clusterStatus:o?.[r.manifest.id],bundle:$(e)?e.bundle:void 0,availableUpdate:n,isUpdating:T.has(t)||s,jobProgress:a,onUpdate:i,disabledByBulk:V.isPending},$(e)?t:e.manifest.id)})})]})}function Ie(){let e=s(),{data:n,isLoading:r,isError:o}=g(),{data:d}=C(void 0),{data:p}=T(void 0,{refetchInterval:1e4}),m=a(()=>{let e=new Map;e.set(`hub`,{id:`hub`,name:`Hub`,isHub:!0});for(let t of p??[]){let n=String(t.id??``);n&&e.set(n,{id:n,name:String(t.name??n),isHub:!!t.isHub})}return[...e.values()]},[p]),[h,_]=c(`hub`),v=m.find(e=>e.id===h)??m[0],y=w(),ee=f(),b=y.isPending||ee.isPending,x=async()=>{await y.mutateAsync({nodeId:h}),await ee.mutateAsync(),e.invalidateQueries({queryKey:[[`addons`]]})},S=t(y);S.current=y,u(()=>{S.current.mutate({nodeId:`hub`})},[]);let te=(n??[]).map(Ne).filter(e=>e!==null);return i(V,{children:[i(`div`,{className:`flex items-center justify-between gap-3 flex-wrap`,children:[l(ie,{selectedNodeId:h,onSelect:_}),i(`div`,{className:`flex items-center gap-3 flex-wrap`,children:[!r&&!o&&i(`span`,{className:`text-[10px] rounded-full bg-primary/10 text-primary px-2 py-0.5 font-medium`,children:[te.length,` installed`]}),i(`button`,{type:`button`,onClick:()=>void x(),disabled:b,className:`inline-flex items-center gap-1.5 px-2.5 py-1.5 text-[11px] rounded-md bg-surface hover:bg-surface-hover border border-border disabled:opacity-50 transition-colors`,title:`Re-fetch addons + check npm for new versions`,children:[l(j,{className:`w-3 h-3 ${b?`animate-spin`:``}`}),`Check for updates`]})]})]}),!v.isHub&&i(`div`,{className:`rounded-md border border-warning/30 bg-warning/5 px-3 py-2 text-[11px] text-foreground-subtle`,children:[`Showing only addons compatible with`,` `,l(`span`,{className:`font-medium text-foreground`,children:v.name}),` — agents only run`,` `,l(`code`,{className:`font-mono`,children:`agent-only`}),` and`,` `,l(`code`,{className:`font-mono`,children:`any-node`}),` addons. Install / uninstall is hub-driven; agents auto-sync from the hub.`]}),r&&l(`div`,{className:`text-xs text-foreground-subtle animate-pulse`,children:`Loading…`}),o&&l(`div`,{className:`text-xs text-danger`,children:`Failed to load addons`}),!r&&!o&&l(Fe,{addons:te,clusterStatus:d,selectedNode:v,onRefresh:()=>void x(),isRefreshing:b})]})}export{Ie as AddonsPage};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import{I as e,K as t,Q as n,S as r,V as i,W as a,b as o,o as s,q as c,x as l,z as u}from"./_virtual_mf___mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DhP-Lgiq.js";import{Z as d}from"./player-overlays-wniETo4u.js";import{$i as f,Ct as p,Fo as m,Gi as h,Io as g,Is as _,J as v,Ki as y,Lo as b,Po as x,Ps as S,Qi as C,Ra as w,St as ee,Xo as T,bt as te,ea as ne,et as E,ln as D,na as re,q as ie,ro as ae,ta as oe,tt as O,xt as se}from"./src-IW6snE8b.js";import{Et as ce}from"./src-CsxD-27Y.js";import{t as le}from"./pencil-D-rxGNNf.js";import{t as ue}from"./radio-dB0UNm47.js";import{t as de}from"./refresh-cw-srKCTv_-.js";import{t as k}from"./rotate-cw-DKLLB8dt.js";import{t as fe}from"./server-BQtqKhWd.js";import{C as A,H as pe,I as me,K as j,N as he,R as ge,a as M,m as _e,o as ve,p as ye,r as N,t as P,z as be}from"./index-Cp84SBzW.js";import{t as xe}from"./NodeAddonsSettingsPanel-CAyKEQpD.js";import{t as F}from"./format-size-DIxKXxtj.js";var I=j(`arrow-down-to-line`,[[`path`,{d:`M12 17V3`,key:`1cwfxf`}],[`path`,{d:`m6 11 6 6 6-6`,key:`12ii2o`}],[`path`,{d:`M19 21H5`,key:`150jfl`}]]),Se=j(`hard-drive-download`,[[`path`,{d:`M12 2v8`,key:`1q4o3n`}],[`path`,{d:`m16 6-4 4-4-4`,key:`6wukr`}],[`rect`,{width:`20`,height:`8`,x:`2`,y:`14`,rx:`2`,key:`w68u3i`}],[`path`,{d:`M6 18h.01`,key:`uhywen`}],[`path`,{d:`M10 18h.01`,key:`h775k`}]]),Ce=j(`memory-stick`,[[`path`,{d:`M6 19v-3`,key:`1nvgqn`}],[`path`,{d:`M10 19v-3`,key:`iu8nkm`}],[`path`,{d:`M14 19v-3`,key:`kcehxu`}],[`path`,{d:`M18 19v-3`,key:`1vh91z`}],[`path`,{d:`M8 11V9`,key:`63erz4`}],[`path`,{d:`M16 11V9`,key:`fru6f3`}],[`path`,{d:`M12 11V9`,key:`ha00sb`}],[`path`,{d:`M2 15h20`,key:`16ne18`}],[`path`,{d:`M2 7a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v1.1a2 2 0 0 0 0 3.837V17a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-5.1a2 2 0 0 0 0-3.837Z`,key:`lhddv3`}]]);n();function we(e){if(e<60)return`${e}s`;let t=Math.floor(e/60);if(t<60)return`${t}m`;let n=Math.floor(t/60);return n<24?`${n}h ${t%60}m`:`${Math.floor(n/24)}d ${n%24}h`}function Te({state:e}){return l(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded-full ${e===`running`?`bg-success/10 text-success`:e===`crashed`||e===`failed`?`bg-destructive/10 text-destructive`:`bg-muted text-muted-foreground`}`,children:e})}var Ee=[`trace`,`debug`,`info`,`warn`,`error`];function De({proc:e,nodeId:t,defaultExpanded:n,activePanel:i,onTogglePanel:a}){let o=e.services??[],s=o.length===1,[u,d]=c(s||n),[m,h]=c(null),[g,_]=c(`info`),y=e.name.includes(`(core)`),b=f(),x=ne(),S=oe(),C=async e=>{h(e);try{await b.mutateAsync({nodeId:t,addonId:e})}catch(e){console.error(`Failed to restart addon:`,e)}finally{h(null)}},w=async()=>{h(e.name);try{await x.mutateAsync({nodeId:t,processName:e.name})}catch(e){console.error(`Failed to restart process:`,e)}finally{h(null)}},T=async n=>{let r=`${t}/${e.name}`;try{await S.mutateAsync({nodeId:r,level:n}),_(n)}catch(e){console.error(`Failed to set log level:`,e)}};return r(`div`,{className:`border border-border/50 rounded-lg overflow-hidden`,children:[r(`div`,{role:s?void 0:`button`,tabIndex:s?void 0:0,onClick:s?void 0:()=>d(!u),onKeyDown:s?void 0:e=>{(e.key===`Enter`||e.key===` `)&&d(!u)},className:`flex items-center gap-2 w-full px-3 py-2 bg-muted/20 transition-colors text-left select-none ${s?``:`hover:bg-muted/40 cursor-pointer`}`,children:[s?l(`span`,{className:`h-3 w-3 shrink-0`}):l(u?ge:me,{className:`h-3 w-3 text-muted-foreground shrink-0`}),y?l(fe,{className:`h-3.5 w-3.5 text-primary shrink-0`}):l(pe,{className:`h-3.5 w-3.5 text-amber-500 shrink-0`}),l(`span`,{className:`text-xs font-semibold flex-1`,children:e.name}),r(`span`,{className:`text-[10px] text-muted-foreground tabular-nums`,children:[`PID `,e.pid]}),l(Te,{state:e.state}),r(`span`,{className:`text-[10px] text-muted-foreground tabular-nums`,children:[e.cpuPercent,`% CPU`]}),l(`span`,{className:`text-[10px] text-muted-foreground tabular-nums`,children:F(e.memoryRss)}),l(`span`,{className:`text-[10px] text-muted-foreground tabular-nums`,children:we(e.uptimeSeconds)}),!y&&r(`div`,{className:`flex items-center gap-1`,onClick:e=>e.stopPropagation(),children:[r(te,{children:[l(p,{className:`text-[9px] px-1.5 py-0.5 rounded border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors font-mono`,title:`Set log level`,children:g}),l(se,{align:`end`,className:`min-w-[70px] py-0.5`,children:Ee.map(e=>l(ee,{onClick:()=>T(e),className:`h-auto px-2 py-1 text-[10px] font-mono ${e===g?`text-primary font-semibold`:``}`,children:e},e))})]}),l(`button`,{onClick:w,disabled:m===e.name,className:`p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50`,title:`Restart process`,children:l(k,{className:`h-3 w-3 ${m===e.name?`animate-spin`:``}`})})]})]}),u&&o.length>0&&l(`div`,{className:`divide-y divide-border/30`,children:o.map(e=>r(`div`,{children:[r(`div`,{className:`flex items-center gap-2 px-3 py-1.5 pl-9 hover:bg-muted/10 transition-colors`,children:[l(`div`,{className:`h-1.5 w-1.5 rounded-full shrink-0 ${e.status===`running`?`bg-success`:`bg-muted-foreground/30`}`}),l(`span`,{className:`text-xs font-medium flex-1 min-w-0 truncate`,children:e.addonId}),e.capabilities.length>0&&r(`div`,{className:`flex gap-1 flex-shrink-0`,children:[e.capabilities.slice(0,3).map(e=>l(`span`,{className:`text-[9px] px-1 py-0.5 rounded bg-blue-500/10 text-blue-400 truncate max-w-[80px]`,children:e},e)),e.capabilities.length>3&&r(`span`,{className:`text-[9px] text-muted-foreground`,children:[`+`,e.capabilities.length-3]})]}),r(`div`,{className:`flex items-center gap-1 shrink-0`,children:[l(`button`,{onClick:()=>a(e.addonId,`logs`),className:`p-0.5 rounded transition-colors ${i?.addonId===e.addonId&&i.type===`logs`?`bg-primary/10 text-primary`:`hover:bg-muted text-muted-foreground hover:text-foreground`}`,title:`Show logs for ${e.addonId}`,children:l(_e,{className:`h-3 w-3`})}),l(`button`,{onClick:()=>a(e.addonId,`events`),className:`p-0.5 rounded transition-colors ${i?.addonId===e.addonId&&i.type===`events`?`bg-primary/10 text-primary`:`hover:bg-muted text-muted-foreground hover:text-foreground`}`,title:`Show events for ${e.addonId}`,children:l(ue,{className:`h-3 w-3`})}),l(`button`,{onClick:()=>C(e.addonId),disabled:m===e.addonId,className:`p-0.5 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50`,title:`Restart ${e.addonId}`,children:l(k,{className:`h-3 w-3 ${m===e.addonId?`animate-spin`:``}`})})]})]}),i?.addonId===e.addonId&&i.type===`logs`&&l(`div`,{className:`border-t border-border/40 bg-muted/5`,children:l(v,{addonId:e.addonId,agentId:t,maxHeight:`max-h-48`,showFilters:!1,onClose:()=>a(e.addonId,`logs`)})}),i?.addonId===e.addonId&&i.type===`events`&&l(`div`,{className:`border-t border-border/40 bg-muted/5`,children:l(ie,{addonId:e.addonId,category:`addon.*`,maxHeight:`max-h-48`,onClose:()=>a(e.addonId,`events`)})})]},e.addonId))}),u&&o.length===0&&l(`div`,{className:`px-3 py-2 pl-9 text-[10px] text-muted-foreground`,children:`No services`})]})}function Oe({nodeId:e,processes:t}){let[n,r]=c(null),i=(e,t)=>{r(n=>n?.addonId===e&&n.type===t?null:{addonId:e,type:t})};return t.length===0?l(`div`,{className:`py-4 text-xs text-muted-foreground text-center`,children:`No processes on this node`}):l(`div`,{className:`space-y-2 py-1`,children:t.map((t,r)=>l(De,{proc:t,nodeId:e,defaultExpanded:r===0,activePanel:n,onTogglePanel:i},t.name))})}var ke={system:0,managed:1,root:2};n();function Ae(e){return e<60?`${e}s`:e<3600?`${Math.floor(e/60)}m ${e%60}s`:e<86400?`${Math.floor(e/3600)}h ${Math.floor(e%3600/60)}m`:`${Math.floor(e/86400)}d ${Math.floor(e%86400/3600)}h`}function je(e,t=80){return e.length<=t?e:`…${e.slice(e.length-t+1)}`}function Me({nodeId:e}){let t=s(),n=S(`metrics.node-processes-snapshot`,t=>t.nodeId===e),{data:i}=y({nodeId:e}),o=n?.processes??i,c=a(()=>o?[...o]:[],[o]),u=a(()=>[{key:`classification`,header:`Class`,sortValue:e=>ke[e.classification],render:e=>l(`span`,{className:`inline-block rounded-full px-1.5 py-0.5 text-[10px] font-medium ${e.classification===`root`?`bg-sky-500/20 text-sky-400`:e.classification===`system`?`bg-foreground-subtle/20 text-foreground-subtle`:`bg-success/20 text-success`}`,children:e.classification})},{key:`pid`,header:`PID`,align:`right`,sortValue:e=>e.pid,render:e=>l(`span`,{className:`font-mono`,children:e.pid})},{key:`ppid`,header:`PPID`,align:`right`,sortValue:e=>e.ppid,render:e=>l(`span`,{className:`font-mono text-foreground-subtle`,children:e.ppid})},{key:`addonId`,header:`Addon`,sortValue:e=>e.addonId,render:e=>l(`span`,{className:`text-foreground-subtle text-[11px]`,children:e.addonId??`—`})},{key:`command`,header:`Command`,nowrap:!1,render:e=>l(`span`,{className:`font-mono text-[10px] text-foreground-subtle break-all`,children:je(e.command)})},{key:`cpuPercent`,header:`CPU%`,align:`right`,sortValue:e=>e.cpuPercent,render:e=>e.cpuPercent.toFixed(1)},{key:`memoryRssBytes`,header:`RSS`,align:`right`,sortValue:e=>e.memoryRssBytes,render:e=>F(e.memoryRssBytes)},{key:`uptimeSec`,header:`Uptime`,align:`right`,sortValue:e=>e.uptimeSec,render:e=>l(`span`,{className:`text-foreground-subtle`,children:Ae(e.uptimeSec)})}],[]);return r(`div`,{className:`space-y-4`,children:[l(`div`,{className:`flex items-start justify-end gap-4`,children:r(`button`,{type:`button`,onClick:()=>t.invalidateQueries({queryKey:[[`metricsProvider`,`listNodeProcesses`]]}),className:`inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[11px] text-foreground hover:bg-surface-hover`,children:[l(de,{className:`h-3 w-3`}),` Refresh`]})}),l(E,{columns:u,rows:c,rowKey:e=>e.pid,minWidthPx:880,mobileMode:`scroll`,maxBodyHeight:O,emptyMessage:`Scanning…`})]})}var L={width:320,height:64},R=5,z=L.width+34,B=L.height+R+1,Ne=[1,2,5,10],Pe=[1,2,4,8,16,32,64,128,256,512,1024],V=[1,1.5,2,2.5,3,4,5],H=[4,3,5,2],U=1e-9;function Fe(e,t){if(!Number.isFinite(e)||e<=0)return!1;if(t===`bytes`){if(!Number.isInteger(e))return!1;let t=e/1024**Math.floor(Math.log(e)/Math.log(1024));return V.some(e=>Math.abs(t-e)<U)}let n=e/10**Math.floor(Math.log10(e));return V.some(e=>Math.abs(n-e)<U)}function W(e,t,n){let r=0;for(let t of e)t!==null&&t>r&&(r=t);if(r<=t)return t;if(n===`bytes`){let e=1024**Math.floor(Math.log(r)/Math.log(1024));for(let t of Pe){let n=t*e;if(n>=r)return n}return 1024*e}let i=10**Math.floor(Math.log10(r));for(let e of Ne){let t=e*i;if(t>=r)return t}return 10*i}function Ie(e,t){if(!Number.isFinite(e)||e<=0)return[];let n=H.find(n=>Fe(e/n,t))??H[H.length-1],r=e/n,i=[];for(let e=1;e<=n;e++)i.push(r*e);return i}var Le=2.5;function Re(e){return e*Le}function G(e,t,n,r){if(e.length===0)return[];let i=e[0].atMs,a=e.at(-1).atMs-i,o=n<=0?1:n,s=r!==void 0&&r>0?r:null;return e.map((r,c)=>{let l=a>0?(r.atMs-i)/a*t.width:c/Math.max(1,e.length-1)*t.width,u=c>0?e[c-1]:void 0;return{x:l,y:r.value===null?null:t.height-Math.min(r.value,n)/o*t.height,gapBefore:s!==null&&u!==void 0&&r.atMs-u.atMs>s}})}function ze(e){let t=[],n=!1;for(let r of e){if(r.y===null){n=!1;continue}r.gapBefore&&(n=!1),t.push(`${n?`L`:`M`}${r.x.toFixed(1)},${r.y.toFixed(1)}`),n=!0}return t.join(` `)}function Be(e,t){let n=[],r=[],i=()=>{if(r.length<2){r=[];return}let e=r.map((e,t)=>`${t===0?`M`:`L`}${e.x.toFixed(1)},${e.top.toFixed(1)}`),t=[...r].reverse().map(e=>`L${e.x.toFixed(1)},${e.bottom.toFixed(1)}`);n.push(`${e.join(` `)} ${t.join(` `)} Z`),r=[]};for(let n=0;n<e.length;n++){let a=e[n],o=t[n];if(!a||!o||a.y===null||o.y===null){i();continue}(a.gapBefore||o.gapBefore)&&i(),r.push({x:a.x,top:a.y,bottom:o.y})}return i(),n.join(` `)}function Ve(e){let t=[];for(let n=1;n<e.length;n++){let r=e[n];r.gapBefore&&t.push({fromX:e[n-1].x,toX:r.x})}return t}function K(e,t){if(e.length===0)return null;let n=0,r=1/0;for(let i=0;i<e.length;i++){let a=Math.abs(e[i].x-t);a<r&&(r=a,n=i)}return n}n();var q={main:`var(--load-series-main)`,gc:`var(--load-series-gc)`},He=`
|
|
2
|
-
.load-chart-scope { --load-series-main: #2a78d6; --load-series-gc: #e87ba4; }
|
|
3
|
-
@media (prefers-color-scheme: dark) {
|
|
4
|
-
:root:not([data-theme="light"]) .load-chart-scope {
|
|
5
|
-
--load-series-main: #3987e5; --load-series-gc: #d55181;
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
:root[data-theme="dark"] .load-chart-scope {
|
|
9
|
-
--load-series-main: #3987e5; --load-series-gc: #d55181;
|
|
10
|
-
}
|
|
11
|
-
`,J=L,Ue={height:B};function We({title:e,points:n,mainLabel:s,gcLabel:u,formatValue:d,emptyMessage:f,gapMs:p}){let m=i(),h=t(null),[g,_]=c(null),v=a(()=>{let e=n.map(e=>({atMs:e.atMs,value:e.main===null||e.gc===null?null:e.main+e.gc})),t=n.map(e=>({atMs:e.atMs,value:e.main})),r=W(e.map(e=>e.value),25,`linear`),i=G(e,J,r,p),a=G(t,J,r,p),o=a.map(e=>({x:e.x,y:e.y===null?null:J.height,gapBefore:e.gapBefore}));return{max:r,ticks:Ie(r,`linear`),upper:i,middle:a,base:o,gaps:Ve(i)}},[n,p]),y=n.at(-1),b=(g===null?void 0:n[g.index])??y;return n.length===0||v.upper.every(e=>e.y===null)?l(X,{title:e,children:l(Je,{message:f})}):l(X,{title:e,legend:r(o,{children:[l(qe,{color:q.main,label:s}),l(qe,{color:q.gc,label:u})]}),readout:b&&b.main!==null&&b.gc!==null?r(o,{children:[l(Z,{color:q.main,text:d(b.main)}),l(Z,{color:q.gc,text:d(b.gc)})]}):null,children:r(`svg`,{ref:h,viewBox:`0 0 ${z} ${B}`,preserveAspectRatio:`none`,className:`w-full`,style:Ue,role:`img`,"aria-label":`${e}: ${s} and ${u} over time`,onMouseLeave:()=>_(null),onMouseMove:e=>{let t=e.currentTarget.getBoundingClientRect();if(t.width===0)return;let n=(e.clientX-t.left)/t.width*z-34,r=K(v.upper,n);r!==null&&_({index:r,xPx:v.upper[r].x})},children:[l(Ge,{ticks:v.ticks,max:v.max,formatValue:d}),r(`g`,{transform:`translate(34,${R})`,clipPath:`url(#${m})`,children:[l(`clipPath`,{id:m,children:l(`rect`,{x:0,y:0,width:J.width,height:J.height})}),l(Ke,{spans:v.gaps}),l(`path`,{d:Be(v.middle,v.base),fill:q.main,fillOpacity:.85}),l(`path`,{d:Be(v.upper,v.middle),fill:q.gc,fillOpacity:.85,stroke:`var(--color-surface, transparent)`,strokeWidth:2}),l(`path`,{d:ze(v.upper),fill:`none`,stroke:q.gc,strokeWidth:2}),g!==null&&l(`line`,{x1:g.xPx,x2:g.xPx,y1:0,y2:J.height,stroke:`currentColor`,strokeWidth:1,className:`text-foreground-subtle`})]})]})})}function Y({title:e,points:n,formatValue:i,emptyMessage:o,axisFloor:s,axisScale:u=`linear`,gapMs:d}){let f=t(null),[p,m]=c(null),h=a(()=>{let e=W(n.map(e=>e.value),s,u),t=G(n,J,e,d);return{max:e,ticks:Ie(e,u),projected:t,gaps:Ve(t)}},[n,s,u,d]),g=(p===null?n.at(-1):n[p.index])??void 0;return n.length===0||h.projected.every(e=>e.y===null)?l(X,{title:e,children:l(Je,{message:o})}):l(X,{title:e,readout:g&&g.value!==null?l(Z,{color:q.main,text:i(g.value)}):null,children:r(`svg`,{ref:f,viewBox:`0 0 ${z} ${B}`,preserveAspectRatio:`none`,className:`w-full`,style:Ue,role:`img`,"aria-label":e,onMouseLeave:()=>m(null),onMouseMove:e=>{let t=e.currentTarget.getBoundingClientRect();if(t.width===0)return;let n=(e.clientX-t.left)/t.width*z-34,r=K(h.projected,n);r!==null&&m({index:r,xPx:h.projected[r].x})},children:[l(Ge,{ticks:h.ticks,max:h.max,formatValue:i}),r(`g`,{transform:`translate(34,${R})`,children:[l(Ke,{spans:h.gaps}),l(`path`,{d:ze(h.projected),fill:`none`,stroke:q.main,strokeWidth:2}),p!==null&&l(`line`,{x1:p.xPx,x2:p.xPx,y1:0,y2:J.height,stroke:`currentColor`,strokeWidth:1,className:`text-foreground-subtle`})]})]})})}function Ge({ticks:e,max:t,formatValue:n}){let i=t<=0?1:t;return l(`g`,{className:`text-foreground-subtle`,children:e.map(e=>{let t=R+J.height-e/i*J.height;return r(`g`,{children:[l(`line`,{x1:34,x2:34+J.width,y1:t,y2:t,stroke:`currentColor`,strokeWidth:.5,strokeOpacity:.3}),l(`text`,{x:0,y:t+3,fontSize:8,fill:`currentColor`,children:n(e)})]},e)})})}function Ke({spans:e}){return e.length===0?null:l(`g`,{className:`text-foreground-subtle`,children:e.map(e=>l(`rect`,{x:e.fromX,y:0,width:Math.max(1,e.toX-e.fromX),height:J.height,fill:`currentColor`,fillOpacity:.12,children:l(`title`,{children:`No samples in this interval — nothing was measured, nothing is drawn.`})},`${e.fromX}-${e.toX}`))})}function X({title:e,legend:t,readout:n,children:i}){return r(`div`,{className:`load-chart-scope min-w-0`,children:[r(`div`,{className:`flex items-baseline justify-between gap-2 mb-1`,children:[l(`span`,{className:`text-[10px] uppercase tracking-wider text-foreground-subtle`,children:e}),l(`div`,{className:`flex items-center gap-2`,children:n})]}),i,t&&l(`div`,{className:`flex items-center gap-3 mt-1`,children:t})]})}function qe({color:e,label:t}){return r(`span`,{className:`inline-flex items-center gap-1 text-[9px] text-foreground-subtle`,children:[l(`span`,{className:`inline-block h-2 w-2 rounded-[2px]`,style:{backgroundColor:e}}),t]})}function Z({color:e,text:t}){return r(`span`,{className:`inline-flex items-center gap-1 text-[11px] tabular-nums text-foreground`,children:[l(`span`,{className:`inline-block h-2 w-2 rounded-[2px]`,style:{backgroundColor:e}}),t]})}function Je({message:e}){return l(`div`,{className:`h-16 flex items-center justify-center rounded border border-dashed border-border text-[10px] text-foreground-subtle text-center px-2`,children:e})}function Ye(e,t){let n=e.at(-1);return n===void 0?[t]:t.atMs>n.atMs?[...e,t]:e.some(e=>e.atMs===t.atMs)?e:[...e,t].toSorted((e,t)=>e.atMs-t.atMs)}function Xe(e,t,n,r){let i=e.get(t),a=Ye(i?.points??[],r);if(i!==void 0&&a===i.points)return e;let o=new Map(e);return o.set(t,{key:t,kind:n,points:a.slice(Math.max(0,a.length-720))}),o}function Ze(e,t,n){let r=e;for(let e of ce(t,n))r=Xe(r,e.key,e.kind,e.point);return r}function Qe(e,t){let n=e;for(let e of t)for(let t of e.points)n=Xe(n,e.key,e.kind,t);return n}function $e(e){let t=null;for(let n of e.values()){let e=n.points.at(-1);e!==void 0&&(t===null||e.atMs>t)&&(t=e.atMs)}return t}var et=12e4;function tt(e,t){return e===null?!1:t-e>et}function nt(e){let t=e=>{let t=e.points.at(-1);return t===void 0?-1:t.cpuMainPercent!==null&&t.cpuGcPercent!==null?t.cpuMainPercent+t.cpuGcPercent:t.cpuLifetimePercent};return[...e.values()].toSorted((e,n)=>{let r=t(n)-t(e);return r===0?e.key.localeCompare(n.key):r})}function rt(e){for(let t of e.values()){let e=t.points.at(-1);if(e&&e.cpuMainPercent!==null)return!0}return!1}var it={key:`cpu`,dir:`desc`};function at(e){let t=e.points.at(-1);return t===void 0?null:t.cpuMainPercent!==null&&t.cpuGcPercent!==null?t.cpuMainPercent+t.cpuGcPercent:t.cpuLifetimePercent}function ot(e){return e.points.at(-1)?.memoryRssBytes??null}function st(e,t,n){let r=n.trim().toLowerCase();return r===``?!0:e.toLowerCase().includes(r)||t.toLowerCase().includes(r)}function ct(e,t){return t===`memory`?ot(e):at(e)}function lt(e,t,n){let r=e.filter(e=>t.selectedKeys.size>0&&!t.selectedKeys.has(e.key)?!1:st(n(e),e.key,t.search)),i=(e,t)=>e.key.localeCompare(t.key);return[...r].toSorted((e,r)=>{if(t.sort.key===`name`){let a=n(e).localeCompare(n(r)),o=t.sort.dir===`asc`?a:-a;return o===0?i(e,r):o}let a=ct(e,t.sort.key),o=ct(r,t.sort.key);if(a===null&&o===null)return i(e,r);if(a===null)return 1;if(o===null)return-1;let s=t.sort.dir===`desc`?o-a:a-o;return s===0?i(e,r):s})}n();function ut(e,n=720){let r=S(`metrics.node-processes-snapshot`,t=>t.nodeId===e),[i,a]=c(new Map),[o,s]=c(void 0),l=t(null),{data:d,isPending:f}=h({forNodeId:e,sinceMs:o,maxPoints:n});u(()=>{d!==void 0&&a(e=>{let t=Qe(e,d.series);return l.current=$e(t),t})},[d]);let p=r?.timestamp;u(()=>{r==null||p===void 0||(tt(l.current,p)&&s(l.current??0),a(e=>{let t=Ze(e,r.processes,p);return l.current=$e(t),t}))},[p]),u(()=>{a(new Map),s(void 0),l.current=null},[e]);let m=0,g=null;for(let e of i.values()){m=Math.max(m,e.points.length);let t=e.points.at(0);t!==void 0&&(g===null||t.atMs<g)&&(g=t.atMs)}return{series:nt(i),sampleCount:m,threadSplitAvailable:rt(i),oldestAtMs:g,loadingRetained:f,durable:d?.durable??null,bucketMs:d?.bucketMs??null,cadenceMs:d?.cadenceMs??null,retainedSamples:d?.retainedSamples??null}}function dt(e){let t=e.indexOf(`@`);return t===-1?{addonId:e,nodeId:null}:{addonId:e.slice(0,t),nodeId:e.slice(t+1)}}function ft(e,t){let n=dt(e);return n.nodeId===null?t.isHub:n.nodeId===t.nodeId}function pt(e,t){return e.filter(e=>ft(e.addonId,t))}function mt(e){return dt(e).addonId}var ht=`__unclaimed__`;function gt(e,t){return{kind:e,deviceId:t,cpu:0,cpuKnown:!0,rss:0,rssKnown:!0,count:0,roles:new Set}}function _t(e,t){return{key:e,kind:t.kind,deviceId:t.deviceId,cpuSeconds:t.cpuKnown?Math.round(t.cpu*100)/100:null,rssBytes:t.rssKnown?t.rss:null,unitCount:t.count,roles:[...t.roles].sort()}}function vt(e,t){let n=new Map,r=new Set;for(let t of e){t.pid!==void 0&&r.add(t.pid);let e=t.deviceId!==null&&t.attribution!==`unattributable`,i=e?`device:${t.deviceId}`:`shared:${t.role}`,a=n.get(i)??gt(e?`camera`:`shared`,e?t.deviceId:null);a.count+=1,a.roles.add(t.role),t.cpuSeconds===void 0?a.cpuKnown=!1:a.cpu+=t.cpuSeconds,t.rssBytes===void 0?a.rssKnown=!1:a.rss+=t.rssBytes,n.set(i,a)}let i=[...n.entries()].map(([e,t])=>_t(e,t));if(t===void 0)return i;let a=t.filter(e=>!r.has(e.pid));if(a.length===0)return i;let o=gt(`unclaimed`,null);for(let e of a)o.count+=1,o.rss+=e.memoryRssBytes;return o.cpuKnown=!1,[...i,_t(ht,o)]}function yt(e,t){let n=new Set;for(let t of e)t.pid!==void 0&&n.add(t.pid);return{claimed:t.filter(e=>n.has(e.pid)).length,observed:t.length}}var bt=[{family:`decode`,attribution:`measured`,unit:`one forked decode-worker child per decode SESSION`,perCamera:!0,wiredToday:!0,missingLink:``,evidence:[`packages/addon-pipeline/src/session-decode/fork-decode-worker.ts:118`,`packages/addon-pipeline/src/session-decode/fork-decode-worker.ts:131`,`packages/addon-pipeline/src/pipeline-runner/index.ts:2765`,`packages/types/src/process/child-cost-registry.ts:188`]},{family:`transcode`,attribution:`measured`,unit:`one ffmpeg child per (camera, encode plan)`,perCamera:!0,wiredToday:!0,missingLink:``,evidence:[`packages/addon-pipeline/src/stream-broker/stream-broker/egress-transcode-manager.ts:960`,`packages/addon-pipeline/src/stream-broker/stream-broker/transcode-egress.ts:282`,`packages/addon-pipeline/src/stream-broker/stream-broker/transcode-egress.ts:324`,`packages/types/src/ffmpeg/sharing-key.ts:139`]},{family:`recording`,attribution:`measured`,unit:`one passthrough ffmpeg per (camera, profile)`,perCamera:!0,wiredToday:!0,missingLink:``,evidence:[`packages/addon-pipeline/src/recorder/addon/segment-writer.ts:33`,`packages/addon-pipeline/src/recorder/addon/segment-writer.ts:217`,`packages/addon-pipeline/src/recorder/addon/segment-writer.ts:279`,`packages/addon-pipeline/src/recorder/addon/recording-controller.ts:1710`]},{family:`detection`,attribution:`accounted`,unit:`a SHARED inference pool per (node, runtime, device) — no per-camera process`,perCamera:!1,wiredToday:!0,missingLink:"Nothing is missing for COUNTING — per-camera inference milliseconds, processed/shed frames and bytes-to-pool are already accumulated. What is missing is any basis for CPU seconds: `deviceId` reaches the pool as a diagnostic label and selects nothing, so cost can only ever be apportioned, never measured. Since 2026-08-27 the pool DECLARES this itself, contributing `deviceId: null` + `attribution: unattributable` rather than leaving an observer to infer it — the renunciation is data, and it is still refused by the chart gate.",evidence:[`packages/addon-pipeline/src/detection-pipeline/provider.ts:540`,`packages/addon-pipeline/src/detection-pipeline/engine/shared-inference-pool.ts:413`,`packages/types/src/interfaces/inference-engine.ts:24`,`packages/addon-pipeline/src/pipeline-runner/timing-sampler.ts:63`,`packages/addon-pipeline/src/pipeline-runner/runner.ts:353`,`packages/addon-pipeline/src/pipeline-runner/runner.ts:849`,`packages/addon-pipeline/src/pipeline-runner/frame-lazy-metrics.ts:100`]},{family:`streaming`,attribution:`measured`,unit:"one StreamBroker per `${deviceId}/${camStreamId}`, with an exact RTP ring byte counter",perCamera:!0,wiredToday:!1,missingLink:"The ffmpeg-backed ingest is now reported per camera, but that is the minority path. `rtpRingBytes` — the exact figure for the in-process case — is maintained on every push and drop and is still private and absent from `getStats()`. The three `EncodedRingBuffer`s track packets and duration and have no byte accumulator at all; the only byte figure they offer is `preRollBudgetBytes`, which is a BUDGET, not an occupancy.",evidence:[`packages/addon-pipeline/src/stream-broker/stream-broker/stream-broker.ts:2895`,`packages/addon-pipeline/src/stream-broker/rtsp/ffmpeg-push-reader.ts:189`,`packages/addon-pipeline/src/stream-broker/stream-broker/stream-broker.ts:494`,`packages/addon-pipeline/src/stream-broker/stream-broker/stream-broker.ts:498`,`packages/addon-pipeline/src/stream-broker/stream-broker/stream-broker.ts:2505`,`packages/addon-pipeline/src/stream-broker/stream-broker/pre-roll.ts:269`]}];function xt(e){return e.attribution===`measured`&&e.wiredToday}function St(){let e=new Set;for(let t of bt)xt(t)&&e.add(t.family);return e}var Ct=St();function Q(e){return!Ct.has(e.role)||e.deviceId===null?!1:e.attribution===`measured`}function wt(e){return`${e.addonId}${e.role}${e.unit}${e.pid??`-`}`}function Tt(){return{cpuSeconds:0,cpuKnown:!0,rssBytes:0,rssKnown:!0,unitCount:0,roles:new Set}}function Et(e,t,n){if(t.cpuSeconds===void 0)return null;if(e===void 0)return t.startedAtMs===void 0||t.startedAtMs<n?null:t.cpuSeconds;if(e.cpuSeconds===void 0||e.startedAtMs===void 0||t.startedAtMs===void 0||e.startedAtMs!==t.startedAtMs)return null;let r=t.cpuSeconds-e.cpuSeconds;return r<0?null:r}function Dt(e){return Math.round(e*10)/10}function Ot(e,t){let n=t.atMs-e.atMs;if(n<=0)return[];let r=n/1e3,i=new Map;for(let t of e.entries)Q(t)&&i.set(wt(t),t);let a=new Map,o=new Set;for(let n of t.entries){if(!Q(n)||n.deviceId===null)continue;let t=wt(n);o.add(t);let r=a.get(n.deviceId)??Tt();r.unitCount+=1,r.roles.add(n.role);let s=Et(i.get(t),n,e.atMs);s===null?r.cpuKnown=!1:r.cpuSeconds+=s,n.rssBytes===void 0?r.rssKnown=!1:r.rssBytes+=n.rssBytes,a.set(n.deviceId,r)}for(let[e,t]of i){if(o.has(e)||t.deviceId===null)continue;let n=a.get(t.deviceId);n!==void 0&&(n.cpuKnown=!1)}return[...a.entries()].map(([e,n])=>({deviceId:e,point:{atMs:t.atMs,cpuPercent:n.cpuKnown?Dt(n.cpuSeconds/r*100):null,rssBytes:n.rssKnown?n.rssBytes:null,unitCount:n.unitCount,roles:[...n.roles].toSorted()}}))}function kt(e,t){if(t.length===0)return e;let n=new Map(e);for(let e of t){let t=n.get(e.deviceId),r=t?.points.at(-1);if(r!==void 0&&e.point.atMs<=r.atMs)continue;let i=[...t?.points??[],e.point];n.set(e.deviceId,{deviceId:e.deviceId,points:i.slice(Math.max(0,i.length-720))})}return n}function At(e){let t=e=>{for(let t=e.points.length-1;t>=0;t--){let n=e.points[t]?.cpuPercent;if(n!=null)return n}return-1};return[...e.values()].toSorted((e,n)=>{let r=t(n)-t(e);return r===0?e.deviceId-n.deviceId:r})}n();function jt(e){let n=S(`metrics.node-processes-snapshot`,t=>t.nodeId===e.nodeId),r=T(void 0,{staleTime:1/0,refetchOnWindowFocus:!1}),[i,a]=c(new Map),[o,s]=c(null),[l,d]=c(0),f=t(null),p=t(r.refetch);p.current=r.refetch;let m=n?.timestamp;u(()=>{m!==void 0&&p.current()},[m]),u(()=>{a(new Map),s(null),d(0),f.current=null},[e.nodeId,e.isHub]);let h=r.data,g=r.dataUpdatedAt;u(()=>{if(h===void 0||g===0)return;let t={atMs:g,entries:pt(h,e)},n=f.current;if(f.current=t,n===null){s(g);return}let r=Ot(n,t);r.length!==0&&(d(e=>e+1),a(e=>kt(e,r)))},[h,g,e.nodeId,e.isHub]);let _=h===void 0?[]:pt(h,e),v=n?.processes,y=vt(_,v),b=v===void 0?null:yt(_,v),x=_.filter(e=>e.deviceId!==null&&!Q(e));return{series:At(i),sharedBuckets:y.filter(e=>e.kind===`shared`),unclaimed:y.find(e=>e.kind===`unclaimed`)??null,coverage:b,refusedEntries:x,windowStartedAtMs:o,windowCount:l,loading:r.isPending,error:r.error===null?null:r.error.message}}var Mt=25,Nt=64*1024*1024;function Pt({scope:e}){let{t}=P(),n=jt(e),i=[...St()].toSorted().join(`, `);return r(`section`,{className:`space-y-3`,children:[r(`div`,{className:`space-y-1`,children:[l(`h3`,{className:`text-xs font-medium text-foreground`,children:t(`cameraLoad.title`,`Per-camera load — measured, on this node`)}),l(`p`,{className:`text-[11px] text-foreground-subtle`,children:t(`cameraLoad.intro`,"Each addon reports its OWN cost through the `load-contribution` capability — the recorder does not have to be told which camera its ffmpeg serves, it spawned it. Nothing here joins a pid to a camera. Only families that are measured AND readable today are drawn ({{roles}}); every other family is named at the bottom of this panel, with the reason, rather than estimated.",{roles:i})}),r(`p`,{className:`text-[11px] text-foreground-subtle`,children:[t(`cameraLoad.windowNote`,`CPU is a DELTA of the cumulative counters, over the same fixed cadence the node already emits its process snapshot on — this panel adds no sampling and reads nothing while it is closed. Contributions are not stored anywhere, so unlike the per-addon charts above this window starts when you open this panel.`),n.windowStartedAtMs!==null&&r(o,{children:[` `,t(`cameraLoad.windowSince`,`Differencing since {{since}} ({{count}} windows).`,{since:new Date(n.windowStartedAtMs).toLocaleTimeString(),count:n.windowCount})]})]})]}),n.error!==null&&r(`div`,{className:`flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-[11px] text-destructive`,children:[l(M,{className:`h-3 w-3 mt-0.5 shrink-0`}),l(`span`,{children:t(`cameraLoad.readFailed`,`Could not read the load contributions: {{error}}. This is a failed read, NOT an idle cluster.`,{error:n.error})})]}),l(Ft,{state:n}),n.series.length===0&&n.error===null&&l(`div`,{className:`rounded-md border border-dashed border-border px-3 py-6 text-center text-[11px] text-foreground-subtle`,children:n.loading?t(`cameraLoad.loading`,`Reading what the addons report…`):t(`cameraLoad.waitingWindow`,`No per-camera window yet. A rate needs two readings, and the second arrives with the next process snapshot. A node running no decode, transcode or recording child stays empty — which is the truth, not a failure.`)}),l(`div`,{className:`space-y-3`,children:n.series.map(e=>r(`div`,{className:`rounded-lg border border-border p-3`,children:[r(`div`,{className:`flex items-baseline justify-between gap-2 mb-2`,children:[l(`span`,{className:`text-xs font-medium text-foreground`,children:t(`cameraLoad.deviceLabel`,`Camera {{deviceId}}`,{deviceId:e.deviceId})}),l(`span`,{className:`text-[10px] text-foreground-subtle`,children:t(`cameraLoad.unitCount`,`{{count}} unit(s): {{roles}}`,{count:e.points.at(-1)?.unitCount??0,roles:(e.points.at(-1)?.roles??[]).join(`, `)})})]}),r(`div`,{className:`grid grid-cols-1 md:grid-cols-2 gap-4`,children:[l(Y,{title:t(`cameraLoad.cpuTitle`,`CPU % of one core (delta)`),points:e.points.map(e=>({atMs:e.atMs,value:e.cpuPercent})),formatValue:e=>`${e.toFixed(1)}%`,axisFloor:Mt,emptyMessage:t(`cameraLoad.cpuUnavailable`,`No measurable window yet — every window so far contained a unit that started, stopped or reported no counter.`)}),l(Y,{title:t(`cameraLoad.memoryTitle`,`Memory RSS`),points:e.points.map(e=>({atMs:e.atMs,value:e.rssBytes})),formatValue:F,axisFloor:Nt,emptyMessage:t(`cameraLoad.memoryUnavailable`,`No memory reported for this camera.`)})]})]},e.deviceId))}),l(It,{buckets:n.sharedBuckets}),l(Rt,{entries:n.refusedEntries})]})}function Ft({state:e}){let{t}=P(),n=e.coverage;if(n===null)return l(`p`,{className:`text-[11px] text-foreground-subtle`,children:t(`cameraLoad.coverageUnknown`,`No process snapshot from this node yet, so nothing can be said about what is unclaimed. That is different from "everything is claimed".`)});let i=e.unclaimed;return r(`div`,{className:`rounded-md border border-border px-3 py-2 space-y-1`,children:[l(`p`,{className:`text-[11px] text-foreground`,children:t(`cameraLoad.coverage`,`Addons claim {{claimed}} of the {{observed}} camstack processes this node reports.`,{claimed:n.claimed,observed:n.observed})}),i===null?l(`p`,{className:`text-[10px] text-foreground-subtle`,children:t(`cameraLoad.noUnclaimed`,`Nothing is unclaimed on this node.`)}):l(`p`,{className:`text-[10px] text-amber-400`,children:t(`cameraLoad.unclaimed`,`{{count}} process(es) nobody claims, holding {{rss}}. Either a leak or a cost family nobody has taught to report — they stay in their own bucket and are never folded into a camera. CPU is unknown for them: the observer measures RSS and reports no cumulative CPU seconds.`,{count:i.unitCount,rss:i.rssBytes===null?`—`:F(i.rssBytes)})})]})}function It({buckets:e}){let{t}=P();return e.length===0?null:r(`div`,{className:`rounded-md border border-border px-3 py-2 space-y-1`,children:[l(`p`,{className:`text-[11px] font-medium text-foreground`,children:t(`cameraLoad.sharedTitle`,`Shared — declared as belonging to no camera`)}),l(`p`,{className:`text-[10px] text-foreground-subtle`,children:t(`cameraLoad.sharedNote`,`Reported so the shared cost is visible as shared instead of invisible. It is NOT divided across the cameras present: the inference pool is one process serving all of them, and an apportioned share is an estimate, not a measurement. These totals are cumulative since each unit started — not a rate.`)}),l(`ul`,{className:`space-y-0.5`,children:e.map(e=>l(`li`,{className:`text-[10px] text-foreground-subtle`,children:t(`cameraLoad.sharedRow`,`{{roles}} — {{units}} unit(s), {{cpu}} CPU-seconds, {{rss}}`,{roles:e.roles.join(`, `),units:e.unitCount,cpu:e.cpuSeconds===null?`—`:e.cpuSeconds.toFixed(0),rss:e.rssBytes===null?`—`:F(e.rssBytes)})},e.key))})]})}function Lt(e){let t=new Map;for(let n of e){let e=t.get(n.role)??{count:0,addons:new Set};e.count+=1,e.addons.add(mt(n.addonId)),t.set(n.role,e)}return t}function Rt({entries:e}){let{t}=P(),n=Lt(e),i=bt.filter(e=>!xt(e));return i.length===0?null:r(`div`,{className:`rounded-md border border-dashed border-border px-3 py-2 space-y-1`,children:[l(`p`,{className:`text-[11px] font-medium text-foreground`,children:t(`cameraLoad.notChartedTitle`,`Not charted per camera — and why`)}),l(`ul`,{className:`space-y-1`,children:i.map(e=>{let i=n.get(e.family);return r(`li`,{className:`text-[10px] text-foreground-subtle`,children:[l(`span`,{className:`font-medium capitalize text-foreground`,children:e.family}),` `,e.missingLink,i!==void 0&&r(o,{children:[` `,t(`cameraLoad.notChartedReported`,`Reported anyway this window: {{count}} entr(ies) from {{addons}}, all declined.`,{count:i.count,addons:[...i.addons].toSorted().join(`, `)})]})]},e.family)})})]})}n();var zt=256*1024*1024,Bt=1e4;function Vt({nodeId:e,isHub:t}){let{t:n}=P(),{series:i,sampleCount:o,threadSplitAvailable:s,oldestAtMs:u,loadingRetained:d,bucketMs:f,cadenceMs:p}=ut(e),[m,h]=c(``),[g,_]=c(new Set),[v,y]=c(it),b=e=>e.key===`__root__`?n(`clusterLoad.bucketRoot`,`Node supervisor`):e.key===`__unattributed__`?n(`clusterLoad.bucketUnattributed`,`Unattributed processes`):e.key,x=Re(f??p??Bt),S=a(()=>lt(i,{search:m,selectedKeys:g,sort:v},b),[i,m,g,v]),C=e=>{_(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})};return r(`div`,{className:`space-y-4`,children:[l(`style`,{children:He}),l(Ht,{oldestAtMs:u,bucketMs:f,cadenceMs:p}),!s&&o>0&&r(`div`,{className:`flex items-start gap-2 rounded-md border border-amber-500/40 bg-amber-500/5 px-3 py-2 text-[11px] text-amber-400`,children:[l(M,{className:`h-3 w-3 mt-0.5 shrink-0`}),l(`span`,{children:n(`clusterLoad.noThreadSplit`,`No thread-level CPU split on this node — /proc/<pid>/task is Linux-only, and the first sample after a restart has no window to measure. CPU below falls back to the ps lifetime AVERAGE, which is not a rate.`)})]}),o===0&&l(`div`,{className:`rounded-md border border-dashed border-border px-3 py-6 text-center text-[11px] text-foreground-subtle`,children:d?n(`clusterLoad.loadingRetained`,`Reading the retained series from this node…`):n(`clusterLoad.waitingFirstSample`,`No retained samples for this node — waiting for the next snapshot (up to 20s). The chart needs two to draw a rate.`)}),i.length>0&&r(`div`,{className:`space-y-2`,children:[r(`div`,{className:`flex flex-wrap items-center gap-2`,children:[r(`label`,{className:`relative flex-1 min-w-[160px]`,children:[l(ye,{className:`pointer-events-none absolute left-2 top-1/2 h-3 w-3 -translate-y-1/2 text-foreground-subtle`}),l(`input`,{type:`search`,value:m,onChange:e=>h(e.target.value),placeholder:n(`clusterLoad.searchPlaceholder`,`Find a runner…`),"aria-label":n(`clusterLoad.searchLabel`,`Find a runner`),className:`w-full rounded border border-border bg-background py-1 pl-7 pr-2 text-[11px] text-foreground placeholder:text-foreground-subtle`})]}),l(Ut,{sort:v,onChange:y})]}),r(`div`,{className:`flex flex-wrap items-center gap-1`,children:[i.map(e=>{let t=g.has(e.key);return l(`button`,{type:`button`,"aria-pressed":t,onClick:()=>C(e.key),className:`rounded-full border px-2 py-0.5 text-[10px] transition-colors ${t?`border-primary bg-primary/10 text-primary`:`border-border text-foreground-subtle hover:text-foreground`}`,children:b(e)},e.key)}),g.size>0&&r(`button`,{type:`button`,onClick:()=>_(new Set),className:`inline-flex items-center gap-1 rounded-full border border-border px-2 py-0.5 text-[10px] text-foreground-subtle hover:text-foreground`,children:[l(N,{className:`h-2.5 w-2.5`}),n(`clusterLoad.clearFilter`,`All runners`)]})]})]}),i.length>0&&S.length===0&&l(`div`,{className:`rounded-md border border-dashed border-border px-3 py-6 text-center text-[11px] text-foreground-subtle`,children:n(`clusterLoad.noMatches`,`No runner matches this search on {{count}} present. The node is reporting — the filter is hiding them.`,{count:i.length})}),l(`div`,{className:`space-y-3`,children:S.map(e=>r(`div`,{className:`rounded-lg border border-border p-3`,children:[r(`div`,{className:`flex items-baseline justify-between gap-2 mb-2`,children:[l(`span`,{className:`text-xs font-medium text-foreground`,children:b(e)}),l(`span`,{className:`text-[10px] text-foreground-subtle`,children:n(`clusterLoad.processCount`,`{{count}} process(es)`,{count:e.points.at(-1)?.processCount??0})})]}),r(`div`,{className:`grid grid-cols-1 md:grid-cols-2 gap-4`,children:[l(We,{title:s?n(`clusterLoad.cpuTitle`,`CPU % of one core`):n(`clusterLoad.cpuTitleLifetime`,`CPU % (ps lifetime average)`),mainLabel:n(`clusterLoad.seriesMain`,`Main threads`),gcLabel:n(`clusterLoad.seriesGc`,`GC / V8 helpers`),points:e.points.map(e=>({atMs:e.atMs,main:e.cpuMainPercent,gc:e.cpuGcPercent})),formatValue:e=>`${e.toFixed(0)}%`,gapMs:x,emptyMessage:n(`clusterLoad.cpuUnavailable`,`No thread split on this node. Lifetime average: {{avg}}%`,{avg:(e.points.at(-1)?.cpuLifetimePercent??0).toFixed(1)})}),l(Y,{title:n(`clusterLoad.memoryTitle`,`Memory RSS`),points:e.points.map(e=>({atMs:e.atMs,value:e.memoryRssBytes})),formatValue:F,axisFloor:zt,axisScale:`bytes`,gapMs:x,emptyMessage:n(`clusterLoad.memoryUnavailable`,`No memory samples yet.`)})]})]},e.key))}),l(Pt,{scope:{nodeId:e,isHub:t}})]})}function Ht({oldestAtMs:e,bucketMs:t,cadenceMs:n}){let{t:i}=P();if(e===null&&t===null)return null;let a=t!==null&&n!==null&&t>n;return r(`p`,{className:`text-[10px] text-foreground-subtle`,children:[e!==null&&i(`clusterLoad.captionSince`,`Since {{since}}`,{since:new Date(e).toLocaleTimeString()}),e!==null&&t!==null&&` · `,t!==null&&(a?i(`clusterLoad.captionBucket`,`1 point = {{bucket}}s (bucket MAXIMUM, not a mean)`,{bucket:Math.round(t/1e3)}):i(`clusterLoad.captionRaw`,`1 point = 1 snapshot`))]})}function Ut({sort:e,onChange:t}){let{t:n}=P(),i=[{key:`cpu`,label:n(`clusterLoad.sortCpu`,`CPU`)},{key:`memory`,label:n(`clusterLoad.sortMemory`,`Memory`)},{key:`name`,label:n(`clusterLoad.sortName`,`Name`)}];return r(`div`,{className:`flex items-center gap-1`,children:[l(`span`,{className:`text-[10px] text-foreground-subtle`,children:n(`clusterLoad.sortBy`,`Sort by`)}),i.map(n=>{let i=e.key===n.key;return r(`button`,{type:`button`,"aria-pressed":i,onClick:()=>t(i?{key:n.key,dir:e.dir===`desc`?`asc`:`desc`}:{key:n.key,dir:n.key===`name`?`asc`:`desc`}),className:`rounded border px-1.5 py-0.5 text-[10px] transition-colors ${i?`border-primary bg-primary/10 text-primary`:`border-border text-foreground-subtle hover:text-foreground`}`,children:[n.label,i&&(e.dir===`desc`?` ↓`:` ↑`)]},n.key)})]})}var Wt=`No per-node settings on this node. Every other setting these addons expose is one value for the whole cluster — edit those in System → Settings, not here.`;function Gt({nodeId:e,addonIds:t}){return t.length===0?l(`div`,{className:`py-4 text-xs text-muted-foreground text-center`,children:`No addons on this node`}):l(`div`,{className:`w-full py-2`,children:l(xe,{nodeId:e,addonIds:t,level:`global`,fieldScope:`perNode`,emptyMessage:Wt,selfTabbed:!0})})}n();function Kt({nodeId:e,addons:t}){let n=s(),{data:r,isLoading:i}=w({nodeId:e}),o=a(()=>{let e=new Map;for(let n of t)for(let t of n.capabilities){let r=e.get(t)??[];r.push(n.id),e.set(t,r)}return[...e.entries()].toSorted(([e],[t])=>e.localeCompare(t)).map(([e,t])=>({capName:e,providers:t}))},[t]),c=ae({onSuccess:()=>{n.invalidateQueries({queryKey:[[`pipelineOrchestrator`,`getCapabilityBindings`]]})}});return o.length===0?l(`div`,{className:`py-4 text-xs text-muted-foreground text-center`,children:`No capabilities on this node`}):l(E,{columns:[{key:`capName`,header:`Capability`,width:`w-1/2`,sortValue:e=>e.capName,render:e=>l(`span`,{className:`font-medium`,children:e.capName})},{key:`provider`,header:`Bound provider`,render:t=>{let n=r?.[t.capName]??t.providers[0]??``,a=t.providers.length===1;return l(`select`,{value:n,onChange:n=>c.mutate({nodeId:e,capName:t.capName,addonId:n.target.value}),disabled:a||c.isPending||i,className:`w-full rounded-md border border-border bg-surface px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-primary disabled:opacity-60`,title:a?`Only one provider installed — choice becomes available once a second addon registers this capability`:void 0,children:t.providers.map(e=>l(`option`,{value:e,children:e},e))})}}],rows:o,rowKey:e=>e.capName,minWidthPx:520,mobileMode:`scroll`,maxBodyHeight:O})}n();function qt(e){if(e==null)return`—`;let t=Math.floor(e/1e3),n=Math.floor(t/86400),r=Math.floor(t%86400/3600),i=Math.floor(t%3600/60);return n>0?`${n}d ${r}h ${i}m`:r>0?`${r}h ${i}m`:`${i}m`}function Jt(e){let[t,n]=c(!1),[i,a]=c(e.name),o=s(),u=C({onSuccess:()=>{o.invalidateQueries({queryKey:[[`nodes`,`topology`]]})}}),d=(e.localIps??[]).filter(e=>!e.includes(`:`)),f=(e.localIps??[]).filter(e=>e.includes(`:`)),p=async()=>{if(!i.trim()||i===e.name){n(!1);return}try{await u.mutateAsync({nodeId:e.nodeId,name:i.trim()}),n(!1)}catch(e){console.error(`Rename failed:`,e)}},m=[[`Node ID`,l(`span`,{className:`font-mono text-xs`,children:e.nodeId})],[`Display Name`,t?r(`div`,{className:`flex items-center gap-1.5`,children:[l(`input`,{type:`text`,className:`flex-1 px-2 py-0.5 text-xs border border-border rounded bg-background focus:outline-none focus:ring-1 focus:ring-primary`,value:i,onChange:e=>a(e.target.value),onKeyDown:e=>{e.key===`Enter`&&p(),e.key===`Escape`&&n(!1)},disabled:u.isPending,autoFocus:!0}),l(`button`,{onClick:()=>void p(),disabled:u.isPending,className:`p-0.5 text-success hover:bg-success/10 rounded`,title:`Save`,children:l(be,{className:`h-3.5 w-3.5`})}),l(`button`,{onClick:()=>n(!1),className:`p-0.5 text-muted-foreground hover:bg-muted rounded`,title:`Cancel`,children:l(N,{className:`h-3.5 w-3.5`})})]}):r(`div`,{className:`flex items-center gap-1.5`,children:[l(`span`,{className:`text-xs`,children:e.name}),!e.isHub&&l(`button`,{onClick:()=>{a(e.name),n(!0)},className:`p-0.5 text-muted-foreground hover:text-primary rounded`,title:`Rename`,children:l(le,{className:`h-3 w-3`})})]})],[`Hostname`,l(`span`,{className:`text-xs`,children:e.hostname})],[`Role`,e.isHub?l(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded bg-primary/10 text-primary font-medium`,children:`Hub`}):l(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded bg-muted text-muted-foreground font-medium`,children:`Agent`})],[`Root Package`,e.rootPackage?r(`span`,{className:`font-mono text-xs`,children:[e.rootPackage.name,`@`,e.rootPackage.version]}):l(`span`,{className:`text-xs text-muted-foreground`,children:`—`})],[`Platform`,r(`span`,{className:`text-xs`,children:[e.platform,` / `,e.arch]})],[`CPU`,r(`span`,{className:`text-xs`,children:[e.cpuModel??`—`,` (`,e.cpuCores,` cores)`]})],[`Memory`,l(`span`,{className:`text-xs`,children:e.memoryMB>0?`${(e.memoryMB/1024).toFixed(1)} GB`:`—`})],[`Uptime`,l(`span`,{className:`text-xs`,children:qt(e.uptime)})],[`Engines`,e.engines.length>0?l(`div`,{className:`flex flex-wrap gap-1`,children:e.engines.map(e=>l(`span`,{className:`text-[9px] px-1.5 py-0.5 rounded-full bg-purple-500/10 text-purple-400 font-medium`,children:e},e))}):l(`span`,{className:`text-xs text-muted-foreground`,children:`—`})]];return d.length>0&&m.push([`IPv4`,l(`div`,{className:`flex flex-wrap gap-1.5`,children:d.map((e,t)=>l(`span`,{className:`font-mono text-xs px-1.5 py-0.5 rounded bg-muted`,children:e},`${e}-${t}`))})]),f.length>0&&m.push([`IPv6`,l(`div`,{className:`flex flex-wrap gap-1.5`,children:f.map((e,t)=>l(`span`,{className:`font-mono text-[10px] px-1.5 py-0.5 rounded bg-muted truncate max-w-[280px]`,title:e,children:e},`${e}-${t}`))})]),l(`div`,{className:`py-2`,children:l(`table`,{className:`w-full text-sm`,children:l(`tbody`,{children:m.map(([e,t],n)=>r(`tr`,{className:n%2==0?`bg-muted/20`:``,children:[l(`td`,{className:`py-1.5 px-2 text-xs font-medium text-muted-foreground w-28 align-top whitespace-nowrap`,children:e}),l(`td`,{className:`py-1.5 px-2`,children:t})]},e))})})})}n();var Yt=[[`serverManagement`,`getServerPackageStatus`]];function Xt({label:e,tone:t}){return l(`span`,{className:`inline-flex items-center rounded px-2 py-0.5 text-[11px] font-medium ${{neutral:`bg-surface-muted text-foreground-subtle`,ok:`bg-emerald-500/15 text-emerald-500`,info:`bg-sky-500/15 text-sky-500`,warn:`bg-amber-500/15 text-amber-500`,error:`bg-red-500/15 text-red-500`}[t]}`,children:e})}function $({label:e,value:t}){return r(`div`,{className:`flex items-center justify-between gap-4 text-sm`,children:[l(`span`,{className:`text-foreground-subtle`,children:e}),l(`span`,{className:`font-mono text-foreground`,children:t??`—`})]})}function Zt({node:t}){let{t:n}=P(),i=s(),a=D(),[o,u]=c(!1),d=t.isHub?void 0:{nodeId:t.id},f=g(d,{refetchInterval:1e4,enabled:t.isOnline,retry:1}),p=f.data??null,h=e(()=>{i.invalidateQueries({queryKey:Yt})},[i]),_=m({onSettled:h}),v=x({onSettled:h}),y=b({onSettled:h}),S=e(async()=>{p?.latestVersion!=null&&await a({title:n(`serverManagement.confirmUpdateTitle`,`Update node root package`),message:n(`serverManagement.confirmUpdateBody`,`Install {{pkg}}@{{version}} on "{{node}}" and restart to apply.`,{pkg:p.packageName,version:p.latestVersion,node:t.name}),confirmLabel:n(`serverManagement.confirmUpdateAction`,`Update & restart`)})&&(await v.mutateAsync({version:p.latestVersion,...d})).restarting&&u(!0)},[v,a,t.name,d,p,n]),C=e(async()=>{await a({title:n(`serverManagement.confirmRestartTitle`,`Restart node`),message:n(`serverManagement.confirmRestartBody`,`Restart "{{node}}"? In-flight requests to this node are dropped.`,{node:t.name}),confirmLabel:n(`serverManagement.confirmRestartAction`,`Restart`),variant:`warning`})&&(await y.mutateAsync(d)).restarting&&u(!0)},[a,t.name,y,d,n]),w=()=>{switch(p?.bootMode){case`data-root`:return{label:n(`serverManagement.bootDataRoot`,`runtime-updatable`),tone:`ok`};case`workspace`:return{label:n(`serverManagement.bootWorkspace`,`dev workspace`),tone:`info`};default:return{label:n(`serverManagement.bootBaked`,`baked image seed`),tone:`neutral`}}},ee=()=>{if(p==null)return null;switch(p.updateState){case`checking`:return{label:n(`serverManagement.stateChecking`,`checking…`),tone:`info`};case`staging`:return{label:n(`serverManagement.stateStaging`,`updating…`),tone:`info`};case`pending-restart`:return{label:n(`serverManagement.statePending`,`restart pending`),tone:`warn`};default:return p.updateAvailable?{label:n(`serverManagement.stateUpdateAvailable`,`update available`),tone:`warn`}:{label:n(`serverManagement.stateUpToDate`,`up to date`),tone:`ok`}}},T=p?.bootMode===`workspace`,te=t.isOnline&&p!=null&&!T&&p.updateAvailable&&p.updateState===`idle`&&!v.isPending,ne=t.isOnline&&p!=null&&p.updateState===`idle`&&!y.isPending,E=t.isOnline?ee():null;return r(`div`,{className:`space-y-4 py-2`,children:[r(`div`,{className:`flex items-center justify-between gap-3`,children:[r(`div`,{className:`flex items-center gap-2 min-w-0`,children:[l(`span`,{className:`font-mono text-xs text-foreground-subtle truncate`,children:p?.packageName??t.rootPackage?.name??`@camstack/server`}),t.isOnline&&p!=null&&l(Xt,{...w()})]}),E!=null&&l(Xt,{...E})]}),!t.isOnline&&l($,{label:n(`serverManagement.lastReportedVersion`,`Last reported version`),value:t.rootPackage?.version??null}),t.isOnline&&f.isLoading&&r(`div`,{className:`flex items-center gap-2 text-sm text-foreground-subtle`,children:[l(A,{className:`h-4 w-4 animate-spin`}),n(`common.loading`,`Loading…`)]}),t.isOnline&&f.isError&&r(`div`,{className:`space-y-1.5`,children:[l(`p`,{className:`text-sm text-red-500`,children:n(`serverManagement.loadError`,`Could not load the node root-package status.`)}),t.rootPackage!=null&&l($,{label:n(`serverManagement.lastReportedVersion`,`Last reported version`),value:t.rootPackage.version})]}),t.isOnline&&p!=null&&r(`div`,{className:`space-y-1.5`,children:[l($,{label:n(`serverManagement.runningVersion`,`Running version`),value:p.runningVersion}),l($,{label:n(`serverManagement.latestVersion`,`Latest on registry`),value:p.latestVersion}),l($,{label:n(`serverManagement.imageSeedVersion`,`Image seed (baked)`),value:p.seedVersion}),l($,{label:n(`serverManagement.nodeRuntimeVersion`,`Node.js runtime`),value:p.nodeRuntimeVersion}),p.pendingVersion!=null&&l($,{label:n(`serverManagement.pendingVersion`,`Staged (applies on restart)`),value:p.pendingVersion})]}),t.isOnline&&p?.imageContract?.state===`behind-series`&&r(`div`,{className:`rounded-md border border-red-500/40 bg-red-500/10 px-3 py-2 text-xs leading-relaxed text-red-500`,children:[l(`p`,{className:`mb-0.5 font-semibold`,children:n(`serverManagement.imageContractDiverged`,`Container image diverges from the deployment contract`)}),l(`p`,{children:p.imageContract.message})]}),t.isOnline&&T&&l(`p`,{className:`text-xs text-foreground-subtle`,children:n(`serverManagement.workspaceNote`,`Development workspace detected — runtime updates are disabled (the dev loop resolves code from the workspace).`)}),o&&r(`div`,{className:`flex items-center gap-2 text-sm text-amber-500`,children:[l(A,{className:`h-4 w-4 animate-spin`}),n(`serverManagement.nodeRestarting`,`The node is restarting to apply the change…`)]}),t.isOnline&&r(`div`,{className:`flex flex-wrap items-center gap-2 pt-1`,children:[r(`button`,{type:`button`,className:`inline-flex items-center gap-1.5 rounded border border-border px-2.5 py-1.5 text-xs font-medium text-foreground hover:bg-surface-muted disabled:opacity-50`,disabled:_.isPending||p?.updateState===`staging`,onClick:()=>_.mutate(d),children:[_.isPending?l(A,{className:`h-3.5 w-3.5 animate-spin`}):l(de,{className:`h-3.5 w-3.5`}),n(`serverManagement.checkForUpdate`,`Check for update`)]}),te&&r(`button`,{type:`button`,className:`inline-flex items-center gap-1.5 rounded bg-primary px-2.5 py-1.5 text-xs font-medium text-primary-foreground hover:opacity-90 disabled:opacity-50`,onClick:()=>void S(),children:[v.isPending?l(A,{className:`h-3.5 w-3.5 animate-spin`}):l(I,{className:`h-3.5 w-3.5`}),n(`serverManagement.updateTo`,`Update to {{version}}`,{version:p?.latestVersion??``})]}),r(`button`,{type:`button`,className:`inline-flex items-center gap-1.5 rounded border border-border px-2.5 py-1.5 text-xs font-medium text-foreground hover:bg-surface-muted disabled:opacity-50`,disabled:!ne,onClick:()=>void C(),children:[y.isPending?l(A,{className:`h-3.5 w-3.5 animate-spin`}):l(k,{className:`h-3.5 w-3.5`}),n(`serverManagement.restart`,`Restart`)]})]}),t.isOnline&&p?.lastCheckedAtMs!=null&&r(`p`,{className:`flex items-center gap-1.5 text-[11px] text-foreground-subtle`,children:[l(Se,{className:`h-3 w-3`}),n(`serverManagement.lastChecked`,`Last checked: {{when}}`,{when:new Date(p.lastCheckedAtMs).toLocaleString()})]})]})}n();function Qt({node:e}){let t=d(),[n,i]=c(`info`),[a,o]=c(!1),s=e.processes??[],u=e.addons.map(e=>e.id),f=async()=>{if(!a){o(!0);try{await Promise.allSettled([t.trpcClient.pipelineOrchestrator.removeAgentSettings.mutate({agentNodeId:e.id}),t.trpcClient.clusterNodes.forgetNode.mutate({nodeId:e.id})])}finally{o(!1)}}};return e.isOnline?r(`div`,{className:`border border-border rounded-xl`,children:[r(`div`,{className:`flex items-center gap-3 px-4 py-3 bg-muted/30 border-b border-border rounded-t-xl`,children:[l(`div`,{className:`w-2.5 h-2.5 rounded-full bg-success`}),l(`span`,{className:`text-sm font-semibold`,children:e.name}),r(`span`,{className:`text-xs text-muted-foreground`,children:[e.cpuModel??e.platform,` ·`,` `,e.memoryMB>0?`${Math.round(e.memoryMB/1024)}GB`:``,` · `,e.arch]}),e.engines.map(e=>l(`span`,{className:`text-[9px] px-1.5 py-0.5 rounded-full bg-purple-500/10 text-purple-400 font-medium`,children:e},e)),r(`div`,{className:`ml-auto flex gap-3 text-xs text-muted-foreground`,children:[r(`span`,{className:`flex items-center gap-1`,children:[l(he,{className:`h-3 w-3`}),` `,e.cpuPercent,`%`]}),r(`span`,{className:`flex items-center gap-1`,children:[l(Ce,{className:`h-3 w-3`}),` `,e.memoryPercent,`%`]})]})]}),l(`div`,{className:`sticky top-0 z-20 flex border-b border-border px-4 bg-background overflow-x-auto`,children:[`info`,`forks`,`processes`,`load`,`settings`,`capabilities`].map(e=>l(`button`,{onClick:()=>i(e),className:`shrink-0 whitespace-nowrap px-3 py-2 text-xs font-medium border-b-2 transition-colors ${n===e?`border-primary text-primary`:`border-transparent text-muted-foreground hover:text-foreground`}`,children:e===`info`?`General`:e===`forks`?`Forks (${s.length})`:e===`processes`?`Processes`:e===`load`?`Load`:e===`settings`?`Settings`:`Capabilities`},e))}),r(`div`,{className:`px-4 py-2`,children:[n===`info`&&r(`div`,{className:`space-y-3`,children:[l(Jt,{nodeId:e.id,name:e.name,hostname:e.hostname,platform:e.platform,arch:e.arch,cpuModel:e.cpuModel,cpuCores:e.cpuCores,memoryMB:e.memoryMB,engines:e.engines,isHub:e.isHub,uptime:e.uptime,localIps:e.localIps,rootPackage:e.rootPackage}),l(`div`,{className:`border-t border-border pt-1`,children:l(Zt,{node:{id:e.id,name:e.name,isHub:e.isHub,isOnline:e.isOnline,rootPackage:e.rootPackage??null}})})]}),n===`forks`&&l(Oe,{nodeId:e.id,processes:s}),n===`processes`&&l(Me,{nodeId:e.id}),n===`load`&&l(Vt,{nodeId:e.id,isHub:e.isHub}),n===`settings`&&l(Gt,{nodeId:e.id,addonIds:u}),n===`capabilities`&&l(Kt,{nodeId:e.id,addons:e.addons})]})]}):r(`div`,{className:`border border-border rounded-xl overflow-hidden opacity-60`,children:[r(`div`,{className:`flex items-center gap-3 px-4 py-3 bg-muted/30`,children:[l(`div`,{className:`w-2.5 h-2.5 rounded-full bg-destructive`}),l(`span`,{className:`text-sm font-semibold`,children:e.name}),r(`span`,{className:`text-xs text-muted-foreground`,children:[e.cpuModel??e.platform,` ·`,` `,e.memoryMB>0?`${Math.round(e.memoryMB/1024)}GB`:``,` · `,e.arch]}),e.engines.map(e=>l(`span`,{className:`text-[9px] px-1.5 py-0.5 rounded-full bg-purple-500/10 text-purple-400 font-medium`,children:e},e)),e.rootPackage&&r(`span`,{className:`text-[10px] font-mono px-1.5 py-0.5 rounded bg-muted text-muted-foreground`,children:[e.rootPackage.name,`@`,e.rootPackage.version]}),l(`span`,{className:`ml-auto text-xs px-2 py-0.5 rounded-full bg-destructive/10 text-destructive`,children:`offline`})]}),r(`div`,{className:`flex items-center justify-between gap-3 px-4 py-3`,children:[r(`span`,{className:`text-xs text-muted-foreground`,children:[e.lastSeen?`Last seen ${new Date(e.lastSeen).toLocaleString()} — `:``,e.addons.length,` addon`,e.addons.length===1?``:`s`,` assigned; will resume when node reconnects`]}),r(`button`,{type:`button`,onClick:()=>void f(),disabled:a,title:`Forget this node — removes its saved history and pipeline assignments`,className:`flex items-center gap-1 text-xs px-2 py-1 rounded-md border border-border text-muted-foreground hover:text-destructive hover:border-destructive/50 disabled:opacity-50 transition-colors`,children:[l(ve,{className:`h-3 w-3`}),a?`Forgetting…`:`Forget node`]})]})]})}function $t({nodes:e}){return l(`div`,{className:`flex flex-col gap-4`,children:[...e].toSorted((e,t)=>e.isHub?-1:t.isHub?1:e.isOnline&&!t.isOnline?-1:!e.isOnline&&t.isOnline?1:e.name.localeCompare(t.name)).map(e=>l(`div`,{children:l(Qt,{node:e})},e.id))})}n();function en(){let{data:e,isLoading:t}=re(void 0,{staleTime:1/0}),[n,r]=c(null);return _(`cluster.topology-snapshot`,e=>{let t=e.data?.nodes;Array.isArray(t)&&r(t)}),{nodes:a(()=>n??e??[],[n,e]),isLoading:t&&!n}}function tn(){let{t}=P(),n=D(),{nodes:i,isLoading:o}=en(),s=a(()=>i.filter(e=>e.isOnline),[i]),u=s.length,d=i.filter(e=>!e.isOnline).length,f=x(),[p,m]=c(!1),h=e(async()=>{let e=[...s].sort((e,t)=>e.isHub===t.isHub?0:e.isHub?1:-1);if(await n({title:t(`serverManagement.confirmUpdateAllTitle`,`Update all nodes`),message:t(`serverManagement.confirmUpdateAllBody`,`Update and restart every online node, agents first, hub last. Up-to-date nodes are skipped; this page reconnects when the hub comes back.`),confirmLabel:t(`serverManagement.confirmUpdateAllAction`,`Update all & restart`),variant:`warning`})){m(!0);try{for(let t of e)try{await f.mutateAsync(t.isHub?{}:{nodeId:t.id})}catch{}}finally{m(!1)}}},[f,n,s,t]);return r(`div`,{className:`flex flex-col h-full gap-4 p-4`,children:[r(`div`,{className:`flex items-center justify-between gap-2 flex-wrap`,children:[r(`div`,{className:`flex items-center gap-2`,children:[u>0&&r(`span`,{className:`text-xs px-2 py-0.5 rounded-full bg-success/10 text-success`,children:[u,` online`]}),d>0&&r(`span`,{className:`text-xs px-2 py-0.5 rounded-full bg-destructive/10 text-destructive`,children:[d,` offline`]})]}),l(`div`,{className:`flex items-center gap-2`,children:u>1&&r(`button`,{type:`button`,className:`inline-flex items-center gap-1.5 rounded bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:opacity-90 disabled:opacity-50`,disabled:p,title:t(`serverManagement.updateAllHint`,`Sequenced agents-first, hub-last — up-to-date nodes are skipped.`),onClick:()=>void h(),children:[p?l(A,{className:`h-3.5 w-3.5 animate-spin`}):l(I,{className:`h-3.5 w-3.5`}),t(`serverManagement.updateAll`,`Update all nodes`)]})})]}),o?l(`div`,{className:`flex items-center justify-center flex-1 text-muted-foreground`,children:`Loading cluster topology...`}):l(`div`,{className:`flex-1 overflow-auto`,children:l($t,{nodes:i})})]})}export{tn as ClusterPage};
|