@camstack/addon-admin-ui 1.2.40 → 1.2.41
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-_UpnD2Rb.js → AddLocationWizard-BMebDBIA.js} +1 -1
- package/dist/assets/{AddonCollectionPage-DsqpERSx.js → AddonCollectionPage-r3MDTb2U.js} +1 -1
- package/dist/assets/Addons-IfPdw6C0.js +1 -0
- package/dist/assets/{AdminTabs-C1b21Umm.js → AdminTabs-BN9bq2Fe.js} +1 -1
- package/dist/assets/{AiProfiles-CxmKPOGN.js → AiProfiles-CaU_0vCA.js} +1 -1
- package/dist/assets/{BrokerForm-BxVQ7-k2.js → BrokerForm-pR2D2FEG.js} +1 -1
- package/dist/assets/{Build-eERcQhc5.js → Build-BDfaId30.js} +4 -4
- package/dist/assets/{Capabilities-CkTJoG8P.js → Capabilities-DCYvjUOV.js} +1 -1
- package/dist/assets/{CapabilityBadges-Pi0oFNyA.js → CapabilityBadges-BrUlJxX7.js} +1 -1
- package/dist/assets/Cluster-sFTMFphL.js +1 -0
- package/dist/assets/{ClusterRecordingTab-g0pESRbc.js → ClusterRecordingTab-CKyWHM6i.js} +1 -1
- package/dist/assets/{Dashboard-BOdpB8Zi.js → Dashboard-jy4FWmQo.js} +1 -1
- package/dist/assets/{Data-D_lbeA81.js → Data-BE3nk7HN.js} +1 -1
- package/dist/assets/{DetectionIntelligence-Dsj8oMfR.js → DetectionIntelligence-CVACMVUz.js} +1 -1
- package/dist/assets/{DeviceAggregateSection-UayHxH_7.js → DeviceAggregateSection-BGpxGM1L.js} +1 -1
- package/dist/assets/DeviceDetail-BN3ud2_r.js +2 -0
- package/dist/assets/{Devices-Ctgv5UD9.js → Devices-Xl3xsFW3.js} +1 -1
- package/dist/assets/{EmbedPlayerPage-BH6rYrQY.js → EmbedPlayerPage-NqPvTLKU.js} +1 -1
- package/dist/assets/Events-Bq860K-k.js +1 -0
- package/dist/assets/{FormBuilder-4y2vfIFX.js → FormBuilder-BrkB_Vuo.js} +1 -1
- package/dist/assets/{Identity-lIu4PKp0.js → Identity-5C3sPUQm.js} +1 -1
- package/dist/assets/IntegrationDetail-TpeJiSq_.js +1 -0
- package/dist/assets/Integrations-D7OMgnaW.js +1 -0
- package/dist/assets/{Integrations-CtXQURhT.js → Integrations-DrSyeMHp.js} +1 -1
- package/dist/assets/{Logs-CjKk3Pid.js → Logs-q6ZBX4ns.js} +1 -1
- package/dist/assets/{MotionZonesSettings-Lydieqfe.js → MotionZonesSettings-blj7QMMa.js} +1 -1
- package/dist/assets/{MyAccess-W28I5kd-.js → MyAccess-DtT6FFYG.js} +1 -1
- package/dist/assets/Network-Z4oREGTh.js +1 -0
- package/dist/assets/{NodeAddonsSettingsPanel-BI-P31wN.js → NodeAddonsSettingsPanel-DiBk6Fev.js} +1 -1
- package/dist/assets/{NodeInferenceDevices-BmhhZKpR.js → NodeInferenceDevices-LHaBTVxw.js} +1 -1
- package/dist/assets/{Notifications-BGKlEsy-.js → Notifications-BZLN5NsG.js} +1 -1
- package/dist/assets/Pipeline-Dt2CTPL5.js +1 -0
- package/dist/assets/{Plates-CXXsVO_i.js → Plates-z1VqssCX.js} +1 -1
- package/dist/assets/{PrivacyMaskSettings-Cm6_Ayev.js → PrivacyMaskSettings-BgOgmwS6.js} +1 -1
- package/dist/assets/{ProviderIcon-NBKDrcT9.js → ProviderIcon-D3veqTWe.js} +1 -1
- package/dist/assets/Recordings-T7rllaEV.js +1 -0
- package/dist/assets/{ScanNetworkModal-BEJE3rpa.js → ScanNetworkModal-o5xFugCK.js} +1 -1
- package/dist/assets/{Settings-2DUxyOI7.js → Settings-cx5X8HsR.js} +1 -1
- package/dist/assets/{Showroom-DsDBDxPb.js → Showroom-CDrrv1TO.js} +1 -1
- package/dist/assets/{Terminal-DsDxn595.js → Terminal-D5vXOWT2.js} +2 -2
- package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-DuoUM9go.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-BlAsWS9v.js} +1 -1
- package/dist/assets/{boxes-byknuFCy.js → boxes-rTzctUbU.js} +1 -1
- package/dist/assets/{build-cluster-graph-gWLixa2m.js → build-cluster-graph-Coy_GdHx.js} +2 -2
- package/dist/assets/circle-check-big-CRchJGb3.js +1 -0
- package/dist/assets/circle-x-D0bWsIts.js +1 -0
- package/dist/assets/clock-C25GXwpo.js +1 -0
- package/dist/assets/{copy-DtilJJvc.js → copy-DySg8B81.js} +1 -1
- package/dist/assets/{debounced-invalidate-DHj6wyxg.js → debounced-invalidate-D5kf3uDk.js} +1 -1
- package/dist/assets/{dist-CL9jy06y.js → dist-CKpGYpil.js} +1 -1
- package/dist/assets/dist-DBLYemqE.js +345 -0
- package/dist/assets/{download-Dj8UGwXy.js → download-CF59Q1Zv.js} +1 -1
- package/dist/assets/{face-bbox-BFrLPrmw.js → face-bbox-DOKrhacR.js} +1 -1
- package/dist/assets/{hostInit-dir45U0P.js → hostInit-D_uPN66O.js} +1 -1
- package/dist/assets/index-D1Lv9nnm.js +4 -0
- package/dist/assets/{key-round-DmdC7g1C.js → key-round-DFR8IuYK.js} +1 -1
- package/dist/assets/{mf-entry-bootstrap-0-7417bcdb.js → mf-entry-bootstrap-0-803942ee.js} +2 -2
- package/dist/assets/{pencil-CM0OcKoQ.js → pencil-Chd1XFvs.js} +1 -1
- package/dist/assets/play-BS6NorXW.js +1 -0
- package/dist/assets/{player-overlays-CM9K8NbB.js → player-overlays-RSBJ34HJ.js} +1 -1
- package/dist/assets/plus-CLA9DCBk.js +1 -0
- package/dist/assets/{radio-C1-CuToc.js → radio-CN2vqo__.js} +1 -1
- package/dist/assets/{refresh-cw-BCQ0uqSo.js → refresh-cw-Blid1l_b.js} +1 -1
- package/dist/assets/remoteEntry-C9ffs8f0.js +1 -0
- package/dist/assets/rotate-ccw-twRh3mwW.js +1 -0
- package/dist/assets/rotate-cw-CMVPPwHk.js +1 -0
- package/dist/assets/search-BmreiQPf.js +1 -0
- package/dist/assets/{send-85b3c2pF.js → send-CInmQKy1.js} +1 -1
- package/dist/assets/{server-CqHxFx4j.js → server-CsrhvWyN.js} +1 -1
- package/dist/assets/square-BAUrJi-y.js +1 -0
- package/dist/assets/{square-check-big-BFcA-8wr.js → square-check-big-rQeR1daL.js} +1 -1
- package/dist/assets/src-CrugYgqk.js +345 -0
- package/dist/assets/src-RAEsAO7u.js +67 -0
- package/dist/assets/{undo-2-DDQAKjyU.js → undo-2-DWkYdwKX.js} +1 -1
- package/dist/assets/{upload-D0e5f6HZ.js → upload-COgXhe8s.js} +1 -1
- package/dist/assets/{useEventInvalidation-BnSiq41g.js → useEventInvalidation-CINRwQED.js} +1 -1
- package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-1o9kxso_.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-DZ3nAi20.js} +2 -2
- package/dist/assets/{wifi-CkMq-H2F.js → wifi-CRvgXCEx.js} +1 -1
- package/dist/assets/{zap-C0CZz-JF.js → zap-Bz2U4Gui.js} +1 -1
- package/dist/index.html +5 -5
- package/dist/server/addon.js +249 -2
- package/package.json +1 -1
- package/dist/assets/Addons-Cbzvs2ne.js +0 -1
- package/dist/assets/Cluster-D7MeMUz9.js +0 -1
- package/dist/assets/DeviceDetail-2vx05ko3.js +0 -2
- package/dist/assets/Events-GU0DqH5U.js +0 -1
- package/dist/assets/IntegrationDetail-C0Zcxbgi.js +0 -1
- package/dist/assets/Integrations-BP2jk3NT.js +0 -1
- package/dist/assets/Network-Cnq4bp10.js +0 -1
- package/dist/assets/Pipeline-6vY94dNS.js +0 -1
- package/dist/assets/Recordings-fIC-_Plr.js +0 -1
- package/dist/assets/circle-check-big-D8Wjv0ct.js +0 -1
- package/dist/assets/clock-ISV-5mJ1.js +0 -1
- package/dist/assets/dist-DwLd0mpq.js +0 -345
- package/dist/assets/index-BMoYnIQI.js +0 -4
- package/dist/assets/play-CBwgjWMW.js +0 -1
- package/dist/assets/plus-CByuXPqh.js +0 -1
- package/dist/assets/remoteEntry-BtIghGso.js +0 -1
- package/dist/assets/rotate-ccw-CiIETsd8.js +0 -1
- package/dist/assets/rotate-cw-Bo4UhVCj.js +0 -1
- package/dist/assets/search-m5N8S4EI.js +0 -1
- package/dist/assets/square-CwYcDkPi.js +0 -1
- package/dist/assets/src-BaYQ7lHC.js +0 -345
- package/dist/assets/src-s1tm1Ako.js +0 -67
package/dist/server/addon.js
CHANGED
|
@@ -7094,6 +7094,104 @@ object({
|
|
|
7094
7094
|
})
|
|
7095
7095
|
});
|
|
7096
7096
|
/**
|
|
7097
|
+
* Adoption job — the background form of `device-adoption.adopt`.
|
|
7098
|
+
*
|
|
7099
|
+
* ## Why this exists
|
|
7100
|
+
*
|
|
7101
|
+
* `adopt({childNativeIds: [...]})` materialises one CamStack device per
|
|
7102
|
+
* candidate PLUS every accessory child, and the whole array shares ONE UDS
|
|
7103
|
+
* request deadline (60s). Measured on the live hub against Home Assistant:
|
|
7104
|
+
* each device the kernel creates costs ~450 ms — `devices.create` pre-seeds
|
|
7105
|
+
* meta with up to eleven SEQUENTIAL round trips (`setName`, `setType`,
|
|
7106
|
+
* `setRole`, … `persistConfig`) before the class is constructed — and an
|
|
7107
|
+
* accessory child costs the same as its parent. So the real unit of work is
|
|
7108
|
+
* the CHILD, not the candidate:
|
|
7109
|
+
*
|
|
7110
|
+
* - 25 candidates averaging 6 children → ~150 devices → **>60s, times out**
|
|
7111
|
+
* - ONE candidate with 217 children → ~217 devices → **>60s, times out**
|
|
7112
|
+
*
|
|
7113
|
+
* That second line is why this is a job and not a smaller batch. No chunking,
|
|
7114
|
+
* no bounded concurrency over candidates and no per-call tuning can fix a
|
|
7115
|
+
* shape where **N=1 already exceeds the deadline** — the count that blows the
|
|
7116
|
+
* budget is the source system's accessory fan-out, which the operator does not
|
|
7117
|
+
* choose and cannot see. A design that only works below some N is the same bug
|
|
7118
|
+
* deferred.
|
|
7119
|
+
*
|
|
7120
|
+
* ## What the timeout did NOT do
|
|
7121
|
+
*
|
|
7122
|
+
* It did not stop the work. The UDS deadline ends the CALLER's wait; the
|
|
7123
|
+
* provider's loop runs to completion. Measured: a 25-candidate adopt that
|
|
7124
|
+
* "failed" at 60s had adopted 17 by 87s and all 25 by ~130s. The operator saw
|
|
7125
|
+
* an error and had no way to learn that. Every field below exists so that
|
|
7126
|
+
* question has an answer.
|
|
7127
|
+
*
|
|
7128
|
+
* ## Idempotency
|
|
7129
|
+
*
|
|
7130
|
+
* Jobs are in-RAM; a restart forgets them. That is safe here because adoption
|
|
7131
|
+
* is keyed by a stable id (`ha:<broker>:dev:<nativeId>` and equivalents), so
|
|
7132
|
+
* re-running a job re-adopts nothing: an already-adopted candidate is SKIPPED
|
|
7133
|
+
* by the engine before any provider call and lands in `alreadyAdopted`. It is
|
|
7134
|
+
* never a duplicate device, and never an error the operator has to interpret.
|
|
7135
|
+
*/
|
|
7136
|
+
var AdoptionJobStateSchema = _enum([
|
|
7137
|
+
"running",
|
|
7138
|
+
"done",
|
|
7139
|
+
"failed",
|
|
7140
|
+
"cancelled"
|
|
7141
|
+
]);
|
|
7142
|
+
/**
|
|
7143
|
+
* Per-candidate result. Every candidate the job was asked to adopt ends in
|
|
7144
|
+
* exactly one of these buckets — there is no silent drop, and the operator can
|
|
7145
|
+
* always answer "which of my 25 landed?".
|
|
7146
|
+
*
|
|
7147
|
+
* - `adopted` — created now by this job.
|
|
7148
|
+
* - `already-adopted` — a device for this candidate existed before the job
|
|
7149
|
+
* reached it (a re-run, or a retry after a timeout). Not an error.
|
|
7150
|
+
* - `failed` — the provider threw; `error` carries the message.
|
|
7151
|
+
* - `cancelled` — the operator cancelled before this candidate was reached.
|
|
7152
|
+
*/
|
|
7153
|
+
var AdoptionOutcomeSchema = _enum([
|
|
7154
|
+
"adopted",
|
|
7155
|
+
"already-adopted",
|
|
7156
|
+
"failed",
|
|
7157
|
+
"cancelled"
|
|
7158
|
+
]);
|
|
7159
|
+
var AdoptionCandidateResultSchema = object({
|
|
7160
|
+
childNativeId: string(),
|
|
7161
|
+
outcome: AdoptionOutcomeSchema,
|
|
7162
|
+
/** The materialised parent device id — null for `failed` / `cancelled`. */
|
|
7163
|
+
parentDeviceId: number().int().nonnegative().nullable(),
|
|
7164
|
+
/** Accessory children created for this candidate. */
|
|
7165
|
+
accessoryCount: number().int().nonnegative(),
|
|
7166
|
+
/** Failure message; null unless `outcome === 'failed'`. */
|
|
7167
|
+
error: string().nullable()
|
|
7168
|
+
});
|
|
7169
|
+
var AdoptionJobSchema = object({
|
|
7170
|
+
jobId: string(),
|
|
7171
|
+
/** The integration provider this job adopts through (the `addonId` pin). */
|
|
7172
|
+
addonId: string(),
|
|
7173
|
+
integrationId: string(),
|
|
7174
|
+
state: AdoptionJobStateSchema,
|
|
7175
|
+
/** Candidates the job was asked to adopt. Known up front, so never null. */
|
|
7176
|
+
total: number().int().nonnegative(),
|
|
7177
|
+
/** Candidates that have reached a terminal bucket. */
|
|
7178
|
+
processed: number().int().nonnegative(),
|
|
7179
|
+
adopted: number().int().nonnegative(),
|
|
7180
|
+
alreadyAdopted: number().int().nonnegative(),
|
|
7181
|
+
failed: number().int().nonnegative(),
|
|
7182
|
+
/** Accessory child devices created across every candidate — the real unit
|
|
7183
|
+
* of work, surfaced so a slow job is legible rather than mysterious. */
|
|
7184
|
+
accessoriesCreated: number().int().nonnegative(),
|
|
7185
|
+
/** The candidate currently being adopted; null when idle or finished. */
|
|
7186
|
+
currentChildNativeId: string().nullable(),
|
|
7187
|
+
/** One entry per candidate, in the order they were processed. */
|
|
7188
|
+
results: array(AdoptionCandidateResultSchema).readonly(),
|
|
7189
|
+
startedAt: number(),
|
|
7190
|
+
finishedAt: number().nullable(),
|
|
7191
|
+
/** Set only when the job itself broke (not a per-candidate failure). */
|
|
7192
|
+
error: string().nullable()
|
|
7193
|
+
});
|
|
7194
|
+
/**
|
|
7097
7195
|
* Per-camera FUNCTION SWITCHES — the one coherent on/off surface over the
|
|
7098
7196
|
* pipeline functions an operator thinks in terms of.
|
|
7099
7197
|
*
|
|
@@ -11760,6 +11858,15 @@ method(object({
|
|
|
11760
11858
|
}), method(ReleaseInputSchema.extend({ addonId: string() }), _void(), {
|
|
11761
11859
|
kind: "mutation",
|
|
11762
11860
|
auth: "admin"
|
|
11861
|
+
}), method(AdoptInputSchema.extend({ addonId: string() }), object({ jobId: string() }), {
|
|
11862
|
+
kind: "mutation",
|
|
11863
|
+
auth: "admin"
|
|
11864
|
+
}), method(object({
|
|
11865
|
+
addonId: string(),
|
|
11866
|
+
integrationId: string().optional()
|
|
11867
|
+
}), array(AdoptionJobSchema).readonly(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
11868
|
+
kind: "mutation",
|
|
11869
|
+
auth: "admin"
|
|
11763
11870
|
}), method(ResyncInputSchema, ResyncResultSchema, {
|
|
11764
11871
|
kind: "mutation",
|
|
11765
11872
|
auth: "admin"
|
|
@@ -17697,6 +17804,37 @@ DeviceType.Camera, method(object({
|
|
|
17697
17804
|
lastCapturedAt: number().nullable(),
|
|
17698
17805
|
cacheAgeMs: number().nullable(),
|
|
17699
17806
|
etag: string().nullable()
|
|
17807
|
+
}))), systemMethod(object({
|
|
17808
|
+
/** The tiles a surface is actually rendering. One entry per (device,
|
|
17809
|
+
* width) the caller will paint — the width is snapped to the server's
|
|
17810
|
+
* ladder and becomes part of the link's SIGNED identity. */
|
|
17811
|
+
targets: array(object({
|
|
17812
|
+
deviceId: number(),
|
|
17813
|
+
/** Target width in px. Omit for the frame as captured — correct
|
|
17814
|
+
* for a full-bleed surface, wrong (and expensive) for a grid. */
|
|
17815
|
+
width: number().int().positive().optional()
|
|
17816
|
+
})).min(1).max(200) }), array(object({
|
|
17817
|
+
deviceId: number(),
|
|
17818
|
+
/** Root-relative signed path, or null when the link plane is not
|
|
17819
|
+
* served (no data-plane facility). Present even for a device that has
|
|
17820
|
+
* never captured — the request is what triggers the first one (D94). */
|
|
17821
|
+
url: string().nullable(),
|
|
17822
|
+
/** Epoch ms of the frame this link serves. Null = never captured.
|
|
17823
|
+
* THE honest age: the tRPC path carried none before this. */
|
|
17824
|
+
capturedAt: number().nullable(),
|
|
17825
|
+
/** Age of that frame at the moment the answer was built. */
|
|
17826
|
+
ageMs: number().nullable(),
|
|
17827
|
+
/** Epoch ms after which `url` stops verifying. */
|
|
17828
|
+
expiresAt: number().nullable(),
|
|
17829
|
+
/** Ladder rung the bytes are at; null = the frame as captured. */
|
|
17830
|
+
width: number().nullable(),
|
|
17831
|
+
/** The device has never produced a frame. An empty state, not a
|
|
17832
|
+
* failure — and never a reason to withhold the link (D94). */
|
|
17833
|
+
neverCaptured: boolean(),
|
|
17834
|
+
/** A sleeping battery camera: the frame is deliberately stale and will
|
|
17835
|
+
* NOT refresh in the background. A surface should say so rather than
|
|
17836
|
+
* present it as current. */
|
|
17837
|
+
sleeping: boolean()
|
|
17700
17838
|
})));
|
|
17701
17839
|
/**
|
|
17702
17840
|
* `sso-bridge` — internal hub-only cap that lets SSO-style auth
|
|
@@ -19447,6 +19585,37 @@ DeviceType.Light, method(object({
|
|
|
19447
19585
|
mireds: number().int().optional(),
|
|
19448
19586
|
lastChangedAt: number()
|
|
19449
19587
|
});
|
|
19588
|
+
var ConnectionTestOutcomeSchema = discriminatedUnion("outcome", [
|
|
19589
|
+
object({
|
|
19590
|
+
outcome: literal("validated"),
|
|
19591
|
+
/** Round-trip of the sign-in, when the provider measured it. */
|
|
19592
|
+
latencyMs: number().nonnegative().optional(),
|
|
19593
|
+
/** Optional human detail worth showing next to the tick
|
|
19594
|
+
* ("3 devices visible on this account"). */
|
|
19595
|
+
detail: string().optional()
|
|
19596
|
+
}).strict(),
|
|
19597
|
+
object({
|
|
19598
|
+
outcome: literal("rejected"),
|
|
19599
|
+
error: string()
|
|
19600
|
+
}).strict(),
|
|
19601
|
+
object({
|
|
19602
|
+
outcome: literal("inconclusive"),
|
|
19603
|
+
error: string()
|
|
19604
|
+
}).strict()
|
|
19605
|
+
]);
|
|
19606
|
+
var ConnectionTestInputSchema = object({
|
|
19607
|
+
/** Candidate integration settings, exactly as the create form collected them. */
|
|
19608
|
+
settings: record(string(), unknown()) });
|
|
19609
|
+
/**
|
|
19610
|
+
* What the provider's test actually DOES, so the UI can say it in words before
|
|
19611
|
+
* the operator presses the button ("Signs in to the Dreo cloud"). Purely
|
|
19612
|
+
* descriptive — it never changes routing.
|
|
19613
|
+
*/
|
|
19614
|
+
var ConnectionTestDescriptorSchema = object({ label: string() });
|
|
19615
|
+
method(ConnectionTestInputSchema, ConnectionTestOutcomeSchema, {
|
|
19616
|
+
kind: "mutation",
|
|
19617
|
+
auth: "admin"
|
|
19618
|
+
}), method(_void(), ConnectionTestDescriptorSchema, { auth: "admin" });
|
|
19450
19619
|
object({
|
|
19451
19620
|
/** True when the upstream system considers the entity connected. */
|
|
19452
19621
|
connected: boolean(),
|
|
@@ -20348,15 +20517,57 @@ var AvailableIntegrationTypeSchema = object({
|
|
|
20348
20517
|
* flow can import (e.g. HA areas). Drives the adopt modal's "import
|
|
20349
20518
|
* locations" checkbox. Provider-declared in the addon manifest. */
|
|
20350
20519
|
supportsLocationImport: boolean(),
|
|
20520
|
+
/**
|
|
20521
|
+
* True when this integration DECLARES a pre-creation test (the
|
|
20522
|
+
* `connection-test` cap, or a broker whose settings it stores). Drives the
|
|
20523
|
+
* Test button: an integration that cannot be tested must say so up front
|
|
20524
|
+
* rather than offering a button that always answers the same nonsense.
|
|
20525
|
+
*/
|
|
20526
|
+
canTest: boolean(),
|
|
20351
20527
|
existingInstances: array(object({
|
|
20352
20528
|
id: string(),
|
|
20353
20529
|
name: string()
|
|
20354
20530
|
})),
|
|
20355
20531
|
canAdd: boolean()
|
|
20356
20532
|
});
|
|
20533
|
+
/**
|
|
20534
|
+
* Why a test could not be answered as a plain boolean.
|
|
20535
|
+
*
|
|
20536
|
+
* `success` alone collapsed four different situations into one red box, and the
|
|
20537
|
+
* one that mattered most — "nobody ever asked the remote anything" — looked
|
|
20538
|
+
* exactly like "the remote said no". The status is the discriminator:
|
|
20539
|
+
*
|
|
20540
|
+
* - `validated` — a provider-declared test ran and the remote ACCEPTED.
|
|
20541
|
+
* - `rejected` — a provider-declared test ran and the remote REFUSED.
|
|
20542
|
+
* The only status that blocks `integrations.create`.
|
|
20543
|
+
* - `inconclusive` — a test IS declared but could not complete (timeout,
|
|
20544
|
+
* DNS, 5xx). Nothing was observed; not a failure.
|
|
20545
|
+
* - `unsupported` — this integration declares NO test. Nothing was
|
|
20546
|
+
* observed either; not a failure, and not a pass.
|
|
20547
|
+
*
|
|
20548
|
+
* `unsupported` and `inconclusive` both carry `success: false` so an older
|
|
20549
|
+
* client can never read them as a green tick, and both carry an `error` string
|
|
20550
|
+
* that SAYS the test did not run rather than inventing a failure.
|
|
20551
|
+
*/
|
|
20552
|
+
var TestConnectionStatusEnum = _enum([
|
|
20553
|
+
"validated",
|
|
20554
|
+
"rejected",
|
|
20555
|
+
"inconclusive",
|
|
20556
|
+
"unsupported"
|
|
20557
|
+
]);
|
|
20357
20558
|
var TestConnectionResultSchema$1 = object({
|
|
20559
|
+
/** True ONLY for `validated`. Never true for a test that did not run. */
|
|
20358
20560
|
success: boolean(),
|
|
20359
|
-
error: string().optional()
|
|
20561
|
+
error: string().optional(),
|
|
20562
|
+
/** Optional for wire back-compat with clients built before the tri-state;
|
|
20563
|
+
* the server always sets it. */
|
|
20564
|
+
status: TestConnectionStatusEnum.optional(),
|
|
20565
|
+
/** Addon id whose declared test answered — `null` when none did. Lets the UI
|
|
20566
|
+
* attribute a result instead of blaming "the integration". */
|
|
20567
|
+
testedBy: string().nullable().optional(),
|
|
20568
|
+
latencyMs: number().nonnegative().optional(),
|
|
20569
|
+
/** Human detail from a `validated` result ("3 devices on this account"). */
|
|
20570
|
+
detail: string().optional()
|
|
20360
20571
|
});
|
|
20361
20572
|
var CreateIntegrationInputSchema = object({
|
|
20362
20573
|
addonId: string(),
|
|
@@ -24602,6 +24813,18 @@ Object.freeze({
|
|
|
24602
24813
|
addonId: null,
|
|
24603
24814
|
access: "create"
|
|
24604
24815
|
},
|
|
24816
|
+
"connectionTest.describeTest": {
|
|
24817
|
+
capName: "connection-test",
|
|
24818
|
+
capScope: "system",
|
|
24819
|
+
addonId: null,
|
|
24820
|
+
access: "view"
|
|
24821
|
+
},
|
|
24822
|
+
"connectionTest.testSettings": {
|
|
24823
|
+
capName: "connection-test",
|
|
24824
|
+
capScope: "system",
|
|
24825
|
+
addonId: null,
|
|
24826
|
+
access: "create"
|
|
24827
|
+
},
|
|
24605
24828
|
"consumables.reset": {
|
|
24606
24829
|
capName: "consumables",
|
|
24607
24830
|
capScope: "device",
|
|
@@ -24992,6 +25215,12 @@ Object.freeze({
|
|
|
24992
25215
|
addonId: null,
|
|
24993
25216
|
access: "create"
|
|
24994
25217
|
},
|
|
25218
|
+
"deviceManager.adoptionCancelJob": {
|
|
25219
|
+
capName: "device-manager",
|
|
25220
|
+
capScope: "system",
|
|
25221
|
+
addonId: null,
|
|
25222
|
+
access: "create"
|
|
25223
|
+
},
|
|
24995
25224
|
"deviceManager.adoptionListCandidateFilters": {
|
|
24996
25225
|
capName: "device-manager",
|
|
24997
25226
|
capScope: "system",
|
|
@@ -25004,6 +25233,12 @@ Object.freeze({
|
|
|
25004
25233
|
addonId: null,
|
|
25005
25234
|
access: "view"
|
|
25006
25235
|
},
|
|
25236
|
+
"deviceManager.adoptionListJobs": {
|
|
25237
|
+
capName: "device-manager",
|
|
25238
|
+
capScope: "system",
|
|
25239
|
+
addonId: null,
|
|
25240
|
+
access: "view"
|
|
25241
|
+
},
|
|
25007
25242
|
"deviceManager.adoptionRefresh": {
|
|
25008
25243
|
capName: "device-manager",
|
|
25009
25244
|
capScope: "system",
|
|
@@ -25022,6 +25257,12 @@ Object.freeze({
|
|
|
25022
25257
|
addonId: null,
|
|
25023
25258
|
access: "create"
|
|
25024
25259
|
},
|
|
25260
|
+
"deviceManager.adoptionStartJob": {
|
|
25261
|
+
capName: "device-manager",
|
|
25262
|
+
capScope: "system",
|
|
25263
|
+
addonId: null,
|
|
25264
|
+
access: "create"
|
|
25265
|
+
},
|
|
25025
25266
|
"deviceManager.allocateDeviceId": {
|
|
25026
25267
|
capName: "device-manager",
|
|
25027
25268
|
capScope: "system",
|
|
@@ -28160,6 +28401,12 @@ Object.freeze({
|
|
|
28160
28401
|
addonId: null,
|
|
28161
28402
|
access: "view"
|
|
28162
28403
|
},
|
|
28404
|
+
"snapshot.getSnapshotLinks": {
|
|
28405
|
+
capName: "snapshot",
|
|
28406
|
+
capScope: "device",
|
|
28407
|
+
addonId: null,
|
|
28408
|
+
access: "view"
|
|
28409
|
+
},
|
|
28163
28410
|
"snapshot.getSnapshotOverview": {
|
|
28164
28411
|
capName: "snapshot",
|
|
28165
28412
|
capScope: "device",
|
|
@@ -29453,7 +29700,7 @@ var AdminUIAddon = class extends BaseAddon {
|
|
|
29453
29700
|
capability: adminUiCapability,
|
|
29454
29701
|
provider: {
|
|
29455
29702
|
getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
|
|
29456
|
-
getVersion: async () => ({ version: "1.2.
|
|
29703
|
+
getVersion: async () => ({ version: "1.2.41" })
|
|
29457
29704
|
}
|
|
29458
29705
|
}];
|
|
29459
29706
|
}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{Ct as e,Dt as t,Hr as n,Ir as r,Mt as i,Nt as a,Ot as o,St as s,Tt as c,_t as l,bt as u,g as ee,gt as d,ht as f,io as te,jt as p,kt as m,m as h,mt as g,pt as _,so as v,uo as ne,v as re,vt as ie,wt as y,yt as ae}from"./src-s1tm1Ako.js";import{I as b,K as x,Q as S,R as oe,S as C,W as w,b as T,o as se,q as E,x as D,z as O}from"./_virtual_mf___mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DTufy7Ue.js";import{$ as ce}from"./src-BaYQ7lHC.js";import{p as le}from"./player-overlays-CM9K8NbB.js";import{t as k}from"./clock-ISV-5mJ1.js";import{t as A}from"./download-Dj8UGwXy.js";import{t as ue}from"./plus-CByuXPqh.js";import{t as j}from"./refresh-cw-BCQ0uqSo.js";import{t as de}from"./search-m5N8S4EI.js";import{t as M}from"./upload-D0e5f6HZ.js";import{G as N,L as P,N as fe,R as F,S as I,Y as L,g as pe,i as R,m as z,p as me,q as B,s as V}from"./index-BMoYnIQI.js";import{t as H}from"./AdminPage-Dq33XE9j.js";import{t as he}from"./NodeAddonsSettingsPanel-BI-P31wN.js";var ge=N(`chevron-up`,[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]]),U=N(`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`}]]),W=N(`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`}]]),G=N(`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`}]]);S();var K=new Set([`completed`,`failed`,`partially-failed`,`cancelled`]),q=new Set([`done`,`failed`,`skipped`]);function J(e){return!q.has(e.phase)&&!K.has(e.jobState)}function _e(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 ve(){let{data:e}=s({activeOnly:!0},{refetchOnWindowFocus:!1,refetchInterval:e=>(e.state.data?.length??0)>0?3e3:!1}),{map:t}=ne(ce.AddonsJobProgress,e=>e.job.jobId);return w(()=>{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 _e([...n.values()],Date.now())},[e,t])}var Y={queued:{icon:k,cls:`bg-muted text-foreground-subtle`,label:`queued`},fetching:{icon:I,cls:`bg-primary/10 text-primary`,label:`fetching`,spin:!0},staged:{icon:I,cls:`bg-primary/10 text-primary`,label:`staged`,spin:!0},validating:{icon:I,cls:`bg-primary/10 text-primary`,label:`validating`,spin:!0},applying:{icon:I,cls:`bg-primary/10 text-primary`,label:`applying`,spin:!0},restarting:{icon:I,cls:`bg-amber-500/10 text-amber-600 dark:text-amber-400`,label:`restarting`,spin:!0},applied:{icon:I,cls:`bg-primary/10 text-primary`,label:`finalizing`,spin:!0},done:{icon:F,cls:`bg-success/10 text-success`,label:`updated`},failed:{icon:U,cls:`bg-danger/10 text-danger`,label:`failed`},skipped:{icon:G,cls:`bg-muted text-foreground-subtle`,label:`skipped`}};function ye({progress:e}){let t=Y[e.phase],n=t.icon,r=e.error??`${e.packageName}: ${e.fromVersion??`?`} → ${e.toVersion}`;return C(`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:[D(n,{className:`w-2.5 h-2.5 ${t.spin?`animate-spin`:``}`}),t.label,C(`span`,{className:`font-mono`,children:[`→ `,e.toVersion]})]})}function be({packageName:e,currentVersion:t,installSource:n,onInstall:r,onClose:i,onSelect:a,selectedVersion:o}){let s=n===`upload`||n===`local`,{data:c,isLoading:l}=ie({name:e});return C(`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:[C(`div`,{className:`flex items-center justify-between px-3 py-2 border-b border-border`,children:[D(`span`,{className:`text-[10px] uppercase tracking-wide text-foreground-subtle font-medium`,children:`Versions`}),D(`button`,{type:`button`,onClick:i,className:`text-foreground-subtle hover:text-foreground`,children:D(R,{className:`h-3 w-3`})})]}),s&&C(`div`,{className:`flex items-start gap-2 px-3 py-2 border-b border-border bg-cyan-500/10 text-[10px]`,children:[D(M,{className:`h-3 w-3 mt-0.5 text-cyan-500 shrink-0`}),C(`div`,{className:`text-cyan-700 dark:text-cyan-200`,children:[C(`span`,{className:`font-semibold`,children:[n===`upload`?`Uploaded copy`:`Local copy`,` in place.`]}),` `,`Re-install `,D(`span`,{className:`font-mono`,children:t}),` from npm to track upstream releases again.`]})]}),l&&C(`div`,{className:`flex items-center justify-center gap-2 py-6 text-[10px] text-foreground-subtle`,children:[D(I,{className:`h-3.5 w-3.5 animate-spin`}),`Loading versions...`]}),c&&D(`div`,{className:`max-h-64 overflow-auto divide-y divide-border`,children:c.map(e=>{let n=e.version===t,i=a!==void 0&&e.version===o,c=/-(alpha|beta|rc|dev|canary|next)/i.test(e.version),l=C(T,{children:[D(`span`,{className:`font-mono flex-1 text-left ${n?`text-primary font-semibold`:c?`text-amber-400`:`text-foreground`}`,children:e.version}),n&&D(`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=>D(`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&&D(`span`,{className:`text-[9px] text-red-400 line-through`,children:`deprecated`}),D(`span`,{className:`text-[9px] text-foreground-subtle shrink-0`,children:new Date(e.publishedAt).toLocaleDateString()})]});return a?C(`button`,{type:`button`,"aria-label":`Select ${e.version}`,onClick:()=>a(e.version),className:`w-full flex items-center gap-2 px-3 py-2 text-[11px] ${i?`bg-primary/5`:`hover:bg-surface-hover`} transition-colors`,children:[l,i?D(F,{className:`h-3 w-3 text-primary shrink-0`}):D(`span`,{className:`w-3 shrink-0`})]},e.version):C(`div`,{className:`flex items-center gap-2 px-3 py-2 text-[11px] ${n?`bg-primary/5`:`hover:bg-surface-hover`} transition-colors`,children:[l,n&&!s?D(F,{className:`h-3 w-3 text-primary shrink-0`}):D(`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:D(A,{className:`h-3 w-3`})})]},e.version)})}),c&&c.length===0&&D(`div`,{className:`py-4 text-center text-[10px] text-foreground-subtle`,children:`No versions found`})]})}var xe={queued:{icon:k,bg:`bg-muted text-foreground-subtle`,label:`queued`},updating:{icon:I,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:F,bg:`bg-success/10 text-success`,label:`done`},failed:{icon:U,bg:`bg-danger/10 text-danger`,label:`failed`}};function Se({item:e}){let t=xe[e.status],n=t.icon;return C(`span`,{className:`inline-flex items-center gap-1 px-1.5 py-0.5 text-[10px] rounded ${t.bg}`,title:e.error,children:[D(n,{className:`w-2.5 h-2.5 ${t.spin?`animate-spin`:``}`}),t.label]})}S();var X=`device-export`;function Ce(e){return e.capabilities.some(e=>(typeof e==`string`?e:e.name)===X)}function we({isBundle:e,installSource:t,addonId:n,iconPath:r,color:i}){let[a,o]=E(!1),s=i?{backgroundColor:`${i.startsWith(`#`)?i:`#${i}`}26`}:void 0,c=e?`bg-indigo-500/20 text-indigo-700 dark:text-indigo-300`:`bg-purple-500/20 text-purple-700 dark:text-purple-300`,l=n&&r?`/api/addon-assets/${n}/${r}`:null,u=!!l&&!a;return C(`div`,{className:`relative flex-shrink-0`,children:[D(`div`,{className:`h-9 w-9 rounded-lg flex items-center justify-center ${s?``:c}`,style:s,children:u?D(`img`,{src:l,alt:n,className:`h-5 w-5`,onError:()=>o(!0)}):D(e?W:pe,{className:`h-4 w-4`})}),t===`local`&&D(`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`&&D(`span`,{className:`absolute -top-1 -left-1 w-4 h-4 rounded bg-[#cb3837] flex items-center justify-center -rotate-12 shadow-sm`,children:D(`svg`,{viewBox:`0 0 780 250`,className:`w-[11px] h-[11px]`,children:D(`path`,{fill:`#fff`,d:`M240 250h100V50h100v200h340V0H0v250z`})})}),t===`upload`&&D(`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:D(M,{className:`h-2.5 w-2.5 text-white`})})]})}function Te({version:e,availableUpdate:t,selectedVersion:n,isUpdating:r,installSource:i,disabled:a,onUpdate:o,onOpenPicker:s,children:c}){if(r)return C(`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:[D(I,{className:`h-3 w-3 animate-spin`}),`Updating…`]});if(t){let r=n??t;return C(`div`,{className:`relative inline-flex items-center gap-1 shrink-0`,children:[o&&C(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),o()},disabled:a,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:[D(A,{className:`h-3 w-3`}),`Update`]}),C(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),s()},disabled:a,"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:[D(`span`,{className:`font-normal opacity-70`,children:e}),D(`span`,{className:`font-normal opacity-70`,children:`→`}),r,D(P,{className:`h-3 w-3`})]}),c]})}return C(`div`,{className:`relative inline-flex items-center gap-1 shrink-0`,children:[C(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),s()},disabled:a,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`,i===`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,D(P,{className:`h-3 w-3 opacity-50`})]}),c]})}function Ee({addonId:e}){let t=se(),{data:n=`inherit`}=f({addonId:e}),r=m({onSuccess:()=>{t.invalidateQueries({queryKey:[[`addons`,`getAddonAutoUpdate`]]})}});return D(`div`,{className:`flex rounded-lg border border-border overflow-hidden text-[10px] font-medium`,children:[`inherit`,`off`,`latest`,`beta`].map(t=>D(`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:n=[],clusterStatus:r,hideVersion:a,availableUpdate:o,onUpdate:s,isUpdating:l,jobProgress:u,bundle:d,bulkItem:f,disabledByBulk:p,isSystem:m}){let[g,_]=E(!1),[v,ne]=E(!1),[ie,y]=E(!1),[b,x]=E(null);O(()=>{x(null)},[o]);let S=b??o,[oe,w]=E(!1),[ce,k]=E(!1),[A,de]=E(`logs`),M=se(),N=le(),fe=B(),F=te(),{manifest:I}=e,L=e.installedOn??[],pe=!d&&!I.protected&&I.removable!==!1,H=!!d,G=d?.displayName??I.name,K=d?.packageName??I.packageName,q=d?.version??I.packageVersion??I.version,J=d?.installSource??e.installSource,_e=d?d.bundle?.description??d.addons[0]?.manifest.description:I.description,ve=i({onSuccess:()=>{M.invalidateQueries({queryKey:[[`addons`]]}),M.invalidateQueries({queryKey:[[`addonPages`]]}),M.invalidateQueries({queryKey:[[`capabilities`]]})}}),Y=c({onSuccess:()=>{M.invalidateQueries({queryKey:[[`addons`]]})}}),xe=ae({onSuccess:()=>{M.invalidateQueries({queryKey:[[`addons`]]}),M.invalidateQueries({queryKey:[[`addonPages`]]}),M.invalidateQueries({queryKey:[[`capabilities`]]}),M.invalidateQueries({queryKey:[[`integrations`]]})}}),X=t({onSuccess:()=>{M.invalidateQueries({queryKey:[[`addons`]]}),M.invalidateQueries({queryKey:[[`alerts`]]})}}),Z=e.health,Q=Z?.phase===`failed`&&!Z.inGracePeriod,Oe=Q&&Z?.nextRetryAt&&!Z.retrying;return C(`div`,{className:`rounded-lg border bg-surface overflow-hidden ${Q?`border-red-500/50`:`border-border`}`,children:[Q&&Z&&C(`div`,{className:`bg-danger/10 border-b border-danger/30 px-4 py-2.5 flex items-start gap-2.5`,children:[D(U,{className:`h-4 w-4 text-danger shrink-0 mt-0.5`}),C(`div`,{className:`flex-1 min-w-0`,children:[C(`div`,{className:`text-xs font-semibold text-danger`,children:[`Failed to load (attempt #`,Z.retryCount,`)`]}),D(`div`,{className:`text-[11px] text-foreground mt-0.5 break-words font-mono`,children:Z.lastError?.message??`Unknown error`}),Oe&&Z.nextRetryAt&&C(`div`,{className:`text-[10px] text-foreground-subtle mt-1`,children:[`Auto-retry at `,new Date(Z.nextRetryAt).toLocaleTimeString()]})]}),C(`button`,{type:`button`,disabled:X.isPending||Z.retrying,onClick:e=>{e.stopPropagation(),X.mutate({packageName:K})},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:[D(j,{className:`h-3 w-3 ${X.isPending||Z.retrying?`animate-spin`:``}`}),`Retry now`]})]}),C(`div`,{className:`flex items-start gap-3 px-4 py-3`,children:[D(we,{isBundle:H||!!I.components&&I.components.length>1,installSource:J,addonId:H?d.addons[0]?.manifest.id:I.id,iconPath:H?d.bundle?.icon??d.addons[0]?.manifest.icon:I.icon,color:H?d.addons[0]?.manifest.color:I.color}),C(`div`,{className:`flex-1 min-w-0`,children:[C(`div`,{className:`flex items-start justify-between gap-2`,children:[D(`span`,{className:`text-sm font-semibold text-foreground truncate min-w-0`,children:G}),!a&&D(Te,{version:q,availableUpdate:o,...S===void 0?{}:{selectedVersion:S},isUpdating:l,installSource:J,disabled:p,...s&&S!==void 0?{onUpdate:()=>s(S)}:{},onOpenPicker:()=>y(e=>!e),children:ie&&D(be,{packageName:K,currentVersion:q,...J?{installSource:J}:{},...o!==void 0&&S!==void 0?{selectedVersion:S,onSelect:e=>{x(e),y(!1)}}:{},onInstall:e=>{y(!1),xe.mutate({packageName:K,version:e})},onClose:()=>y(!1)})})]}),C(`div`,{className:`flex flex-wrap items-center gap-x-1.5 gap-y-1 mt-0.5`,children:[K!==G&&D(`span`,{className:`text-[10px] text-foreground-subtle font-mono truncate max-w-full`,children:K}),H&&C(`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:[D(W,{className:`h-3 w-3`}),d.addons.length]}),m&&C(`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:[D(j,{className:`h-3 w-3`}),`System`]}),f!=null&&D(Se,{item:f}),u!=null&&D(ye,{progress:u})]}),_e&&D(`p`,{className:`text-[10px] text-foreground-subtle mt-1 line-clamp-1`,children:_e}),!H&&e.process&&C(`div`,{className:`flex flex-wrap items-center gap-1.5 mt-1`,children:[D(`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&&C(`span`,{className:`text-[9px] font-mono text-foreground-subtle`,children:[`PID `,e.process.pid]}),D(`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})]})]})]}),!H&&C(`div`,{className:`flex items-center gap-1 px-4 py-1.5 border-t border-border/50 bg-surface-hover/20`,children:[C(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),Y.mutate({addonId:I.id})},disabled:Y.isPending||p,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:[D(j,{className:`h-3 w-3 ${Y.isPending?`animate-spin`:``}`}),`Restart`]}),C(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),w(e=>!e)},className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border transition-colors ${oe?`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:[D(z,{className:`h-3 w-3`}),`Logs`]}),!H&&C(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),k(!0)},className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border transition-colors ${ce?`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:[D(me,{className:`h-3 w-3`}),`Settings`]}),D(`div`,{className:`flex-1`}),pe&&C(`button`,{type:`button`,onClick:async e=>{e.stopPropagation(),await F({title:`Uninstall ${I.name}?`,message:`This will remove the addon package and all its data. This action cannot be undone.`,confirmLabel:`Uninstall`,variant:`danger`})&&ve.mutate({packageName:I.packageName})},disabled:ve.isPending||p,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:[D(V,{className:`h-3 w-3`}),ve.isPending?`Removing...`:`Uninstall`]})]}),r&&r.nodes.length>1&&!H&&C(`div`,{className:`border-t border-border px-4 py-2 bg-muted/10`,children:[D(`div`,{className:`text-[10px] font-medium text-foreground-subtle mb-1.5`,children:`Cluster Deployment`}),D(`div`,{className:`space-y-1`,children:r.nodes.map(e=>C(`div`,{className:`flex items-center gap-2 text-[10px]`,children:[D(`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`}`}),D(`span`,{className:`font-medium text-foreground min-w-[60px]`,children:e.name}),D(`span`,{className:`font-mono text-foreground-subtle`,children:e.version}),!e.synced&&e.status!==`offline`&&D(`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`&&D(`span`,{className:`text-[9px] px-1 py-0.5 rounded bg-muted text-muted-foreground`,children:`offline`}),e.synced&&e.status!==`offline`&&D(`span`,{className:`text-[9px] text-success`,children:`synced`})]},e.nodeId))})]}),oe&&!H&&C(`div`,{className:`border-t border-border`,children:[C(`div`,{className:`flex items-center px-4 py-1 bg-surface-hover/20 border-b border-border/50`,children:[C(`div`,{className:`flex rounded border border-border overflow-hidden text-[9px]`,children:[D(`button`,{type:`button`,onClick:()=>de(`logs`),className:`px-2 py-0.5 transition-colors ${A===`logs`?`bg-primary/10 text-primary`:`text-foreground-subtle hover:bg-surface-hover`}`,children:`Logs`}),D(`button`,{type:`button`,onClick:()=>de(`events`),className:`px-2 py-0.5 border-l border-border transition-colors ${A===`events`?`bg-primary/10 text-primary`:`text-foreground-subtle hover:bg-surface-hover`}`,children:`Events`})]}),D(`div`,{className:`flex-1`}),D(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),w(!1)},className:`text-foreground-subtle hover:text-foreground`,children:D(R,{className:`h-3.5 w-3.5`})})]}),A===`logs`&&D(ee,{addonId:I.id,maxHeight:`max-h-64`,showFilters:!1}),A===`events`&&D(h,{addonId:I.id,category:`addon.*`,maxHeight:`max-h-64`})]}),H&&C(T,{children:[D(`button`,{type:`button`,onClick:()=>_(e=>!e),className:`w-full flex items-center justify-center border-t border-border py-1 hover:bg-surface-hover/50 transition-colors`,children:D(g?ge:P,{className:`h-3.5 w-3.5 text-foreground-subtle`})}),g&&D(`div`,{className:`border-t border-border px-3 py-2 space-y-2`,children:d.addons.map(e=>D(De,{addon:e,agents:n,hideVersion:!0},e.manifest.id))})]}),ce&&!H&&D(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4`,onClick:()=>k(!1),children:C(`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:[C(`div`,{className:`flex items-center justify-between px-5 py-3 border-b border-border flex-shrink-0`,children:[C(`div`,{className:`flex items-center gap-2`,children:[D(me,{className:`h-4 w-4 text-primary`}),C(`h2`,{className:`text-sm font-semibold text-foreground`,children:[G,` Settings`]})]}),D(`button`,{onClick:()=>k(!1),className:`text-foreground-subtle hover:text-foreground transition-colors p-1 rounded`,children:D(R,{className:`h-4 w-4`})})]}),C(`div`,{className:`flex-1 overflow-y-auto px-5 py-4 space-y-4`,children:[D(he,{nodeId:`hub`,addonIds:[I.id],level:`global`}),Ce(I)&&C(`div`,{children:[D(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:`Device export`}),D(re,{addonId:I.id,trpc:N.trpcClient,onOpenDevice:e=>fe(`/devices/${e}`)})]}),J===`npm`&&C(`div`,{children:[D(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:`Auto-Update`}),D(Ee,{addonId:I.id})]}),I.components&&I.components.length>0&&C(`div`,{children:[C(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:[`Components (`,I.components.length,`)`]}),D(`div`,{className:`flex flex-wrap gap-1`,children:I.components.map(e=>D(`span`,{className:`text-[10px] rounded bg-background border border-border px-1.5 py-0.5 text-foreground-subtle font-mono`,children:e},e))})]}),n.length>=2&&C(`div`,{children:[D(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:`Installed on`}),C(`div`,{className:`flex items-center gap-1.5 flex-wrap`,children:[L.length===0&&D(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Hub (local)`}),L.map(e=>D(`span`,{className:`rounded-full bg-surface-hover border border-border px-2 py-0.5 text-[10px] text-foreground-subtle`,children:e},e)),C(`div`,{className:`relative`,children:[C(`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:[D(ue,{className:`h-3 w-3`}),`Add agent`]}),v&&C(`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:[n.filter(e=>!e.isHub&&!L.includes(e.name)).map(e=>D(`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)),n.filter(e=>!e.isHub&&!L.includes(e.name)).length===0&&D(`div`,{className:`px-3 py-1.5 text-[10px] text-foreground-subtle`,children:`No available agents`})]})]})]})]})]}),D(`div`,{className:`flex items-center justify-end px-5 py-3 border-t border-border flex-shrink-0`,children:D(`button`,{type:`button`,onClick:()=>k(!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`})})]})})]})}S();var Z=`.tgz,.tar.gz,.zip`;function Q({onUploadSuccess:e}){let[t,n]=E(!1),r=x(null),i=b(async t=>{n(!0);let r=new FormData;r.append(`file`,t);let i=localStorage.getItem(`camstack_admin_token`)??``;try{(await(await fetch(`/api/addons/upload`,{method:`POST`,headers:{Authorization:`Bearer ${i}`},body:r})).json()).success&&e()}finally{n(!1)}},[e]);return C(T,{children:[D(`input`,{ref:r,type:`file`,accept:Z,onChange:b(e=>{let t=e.target.files?.[0];t&&i(t),e.target.value=``},[i]),className:`hidden`}),C(`button`,{type:`button`,onClick:()=>r.current?.click(),disabled:t,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:[t?D(I,{className:`w-3.5 h-3.5 animate-spin`}):D(M,{className:`w-3.5 h-3.5`}),t?`Uploading...`:`Upload`]})]})}S();var Oe=new Set([`@camstack/system`,`@camstack/types`,`@camstack/sdk`,`@camstack/shm-ring`,`@camstack/ui-library`]);function ke(e){return e!==void 0&&Oe.has(e)}function Ae(e,t){let n=e??`hub-only`;return n===`any-node`?!0:n===`hub-only`?t:!t}function je(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 Me(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 Ne({addons:t,clusterStatus:n,selectedNode:r,onRefresh:i,isRefreshing:s}){let c=se(),[u,ee]=E(``),f=oe(u),[m,h]=E(!1),g=x(null);O(()=>{if(!m)return;let e=e=>{g.current&&!g.current.contains(e.target)&&h(!1)};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[m]);let{data:v}=e({nodeId:r.id}),ne=w(()=>{let e=new Map;for(let t of v??[])e.set(t.name,t.latestVersion);return e},[v]),re=w(()=>(v??[]).filter(e=>!e.isSystem).length,[v]),[ie,y]=E(()=>new Set),[S,T]=E(()=>new Map),ce=b(e=>{y(t=>new Set(t).add(e))},[]),le=b(e=>{y(t=>{if(!t.has(e))return t;let n=new Set(t);return n.delete(e),n})},[]),k=b((e,t)=>{T(n=>new Map(n).set(e,t))},[]),ue=b(e=>{T(t=>{if(!t.has(e))return t;let n=new Map(t);return n.delete(e),n})},[]),M=a({onMutate:e=>{ce(e.name),ue(e.name)},onSuccess:(e,t)=>{le(t.name);let n=e;if(n&&n.success===!1){k(t.name,n.error??`Update failed (no error message returned by server)`);return}c.invalidateQueries({queryKey:[[`addons`]]}),c.invalidateQueries({queryKey:[[`addons`,`listUpdates`]]})},onError:(e,t)=>{le(t.name),k(t.name,e instanceof Error?e.message:String(e))}}),N=ve(),P=x(new Set);O(()=>{let e=new Set;for(let[t,n]of N)J(n)&&e.add(t);let t=[...P.current].some(t=>!e.has(t));P.current=e,t&&(c.invalidateQueries({queryKey:[[`addons`]]}),c.invalidateQueries({queryKey:[[`addons`,`listUpdates`]]}))},[N,c]);let{data:pe}=d(void 0),R=_({onSuccess:()=>{c.invalidateQueries({queryKey:[[`addons`,`getAutoUpdateSettings`]]})}}),{data:z,isFetching:me}=o({query:f||void 0},{enabled:m}),B=p(),{data:V}=l(void 0),H=V?.requestedAt,[he,ge]=E(null),[U,W]=E(!1);O(()=>{if(V?.kind===`framework-bulk-update`&&V.requestedAt!==he){ge(V.requestedAt),W(!0);let e=window.setTimeout(()=>W(!1),6e3);return()=>window.clearTimeout(e)}},[H,he,V]),te();let G=b(async()=>{let e=(v??[]).filter(e=>!e.isSystem);e.length!==0&&await B.mutateAsync({kind:`update`,targets:e.map(e=>({name:e.name,version:e.latestVersion})),nodeIds:[r.id]})},[v,r.id,B]),K=ae({onSuccess:()=>{c.invalidateQueries({queryKey:[[`addons`]]}),c.invalidateQueries({queryKey:[[`addonPages`]]}),c.invalidateQueries({queryKey:[[`capabilities`]]}),c.invalidateQueries({queryKey:[[`integrations`]]})}}),[q,_e]=E(`type`),[Y,ye]=E(()=>typeof window>`u`?`grouped`:window.localStorage.getItem(`camstack.addons.viewMode`)===`flat`?`flat`:`grouped`),be=e=>{ye(e),typeof window<`u`&&window.localStorage.setItem(`camstack.addons.viewMode`,e)},[xe,Se]=L(),X=xe.get(`capability`),Ce=w(()=>{let e=t.filter(e=>!ke(e.manifest.packageName));return r.isHub||(e=e.filter(e=>Ae(e.placement,r.isHub))),X&&(e=e.filter(e=>(e.manifest.capabilities??[]).some(e=>(typeof e==`string`?e:e.name)===X))),e},[t,r.isHub,X]),we=()=>{let e=new URLSearchParams(xe);e.delete(`capability`),Se(e,{replace:!0})},Te=Y===`flat`?Ce:Me(Ce),Ee=w(()=>{let e=[...Te];switch(q){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},[Te,q]);return C(`div`,{className:`space-y-4`,children:[[...S.entries()].map(([e,t])=>D(`div`,{className:`rounded-md border border-danger/30 bg-danger/5 px-3 py-2 text-[11px]`,children:C(`div`,{className:`flex items-start justify-between gap-3`,children:[C(`div`,{className:`space-y-0.5`,children:[C(`div`,{className:`font-medium text-danger`,children:[`Failed to update `,e]}),D(`div`,{className:`text-foreground-subtle font-mono`,children:t})]}),D(`button`,{type:`button`,onClick:()=>ue(e),className:`text-foreground-subtle hover:text-foreground text-[10px]`,children:`dismiss`})]})},e)),C(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[C(`div`,{className:`flex items-center gap-1.5`,children:[D(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Sort:`}),C(`select`,{value:q,onChange:e=>_e(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:[D(`option`,{value:`type`,children:`Bundles first`}),D(`option`,{value:`name`,children:`Name`}),D(`option`,{value:`source`,children:`Install source`})]})]}),C(`div`,{className:`flex items-center gap-1.5`,children:[D(`span`,{className:`text-[10px] text-foreground-subtle`,children:`View:`}),D(`div`,{className:`flex rounded-md border border-border overflow-hidden text-[10px] font-medium`,children:[`grouped`,`flat`].map(e=>D(`button`,{type:`button`,onClick:()=>be(e),className:`px-2.5 py-1.5 transition-colors capitalize ${Y===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))})]}),r.isHub&&C(`div`,{className:`flex items-center gap-1.5`,children:[D(j,{className:`h-3 w-3 text-foreground-subtle`}),D(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Auto-Update:`}),D(`div`,{className:`flex rounded-md border border-border overflow-hidden text-[10px] font-medium`,children:[`off`,`latest`,`beta`].map(e=>D(`button`,{type:`button`,onClick:()=>R.mutate({channel:e}),disabled:R.isPending,className:`px-2.5 py-1.5 transition-colors capitalize ${pe?.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))})]}),re>0&&C(`button`,{type:`button`,onClick:()=>void G(),disabled:B.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:[B.isPending?D(I,{className:`w-3 h-3 animate-spin`}):D(A,{className:`w-3 h-3`}),B.isPending?`Updating…`:`Update All (${re})`]}),C(`button`,{type:`button`,onClick:i,disabled:s||B.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:[D(j,{className:`w-3 h-3 ${s?`animate-spin`:``}`}),`Refresh`]})]}),C(`div`,{className:`flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3`,children:[C(`div`,{className:`relative flex-1 min-w-0 sm:min-w-[200px]`,ref:g,children:[D(de,{className:`absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-foreground-subtle`}),D(`input`,{type:`text`,value:u,onChange:e=>{ee(e.target.value),h(!0)},onFocus:()=>h(!0),placeholder:`Search addons on npm...`,disabled:B.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`}),me&&D(I,{className:`absolute right-2.5 top-1/2 -translate-y-1/2 h-3 w-3 text-foreground-subtle animate-spin`}),m&&z&&z.length>0&&C(`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:[z.length>0&&C(`div`,{className:`px-3 py-1.5 text-[10px] uppercase tracking-wide text-foreground-subtle border-b border-border`,children:[`npm results (`,z.length,`)`]}),z&&z.length>0&&D(`div`,{className:`max-h-72 overflow-auto divide-y divide-border`,children:z.map(e=>C(`div`,{className:`flex items-center gap-3 px-3 py-2 hover:bg-surface-hover transition-colors`,children:[D(`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()}),C(`div`,{className:`flex-1 min-w-0`,children:[C(`div`,{className:`flex items-baseline gap-2 min-w-0`,children:[D(`span`,{className:`text-[11px] font-semibold break-words`,children:e.name.replace(/^@camstack\/(addon-)?/,``)}),C(`span`,{className:`text-[10px] text-foreground-subtle shrink-0`,children:[`v`,e.version]})]}),D(`div`,{className:`font-mono text-[9px] text-foreground-subtle/80 truncate`,children:e.name}),e.description&&D(`div`,{className:`text-[10px] text-foreground-subtle truncate`,children:e.description})]}),e.installed?C(`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:[D(F,{className:`h-3 w-3`}),e.installedVersion??`Installed`]}):C(`button`,{type:`button`,onClick:()=>K.mutate({packageName:e.name}),disabled:K.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:[K.isPending?D(I,{className:`h-3 w-3 animate-spin`}):D(A,{className:`h-3 w-3`}),`Install`]})]},e.name))})]})]}),D(Q,{onUploadSuccess:()=>{c.invalidateQueries({queryKey:[[`addons`]]}),i()}})]}),X&&C(`div`,{className:`flex items-center gap-2 px-3 py-2 rounded-lg bg-primary/10 border border-primary/30 text-sm`,children:[D(`span`,{className:`text-foreground-subtle`,children:`Filtering by capability:`}),D(`span`,{className:`font-mono text-primary font-semibold`,children:X}),D(`button`,{type:`button`,onClick:we,className:`ml-auto text-xs text-foreground-subtle hover:text-foreground underline`,children:`Clear`})]}),U&&C(`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:[D(fe,{className:`w-4 h-4 shrink-0 mt-0.5 text-green-400`}),C(`div`,{children:[D(`div`,{className:`text-[11px] font-semibold text-foreground`,children:`Bulk update completed`}),D(`div`,{className:`text-[10px] text-foreground-subtle mt-0.5`,children:`System packages updated — hub restarted successfully.`})]})]}),Ce.length===0&&D(`div`,{className:`text-xs text-foreground-subtle`,children:t.length===0?`No addons installed`:X?`No installed addons declare the "${X}" capability. Browse the npm catalog above to find a compatible addon.`:`No addons compatible with ${r.name} (placement filter active)`}),D(`div`,{className:`space-y-2`,children:Ee.map(e=>{let t=$(e)?e.bundle.packageName:e.manifest.packageName,i=ne.get(t),a=$(e)?e.representative:e,o=i?e=>M.mutate({name:t,version:e,nodeId:r.id}):void 0,s=N.get(t)??null,c=s!==null&&J(s);return D(De,{addon:a,clusterStatus:n?.[a.manifest.id],bundle:$(e)?e.bundle:void 0,availableUpdate:i,isUpdating:ie.has(t)||c,jobProgress:s,onUpdate:o,disabledByBulk:B.isPending},$(e)?t:e.manifest.id)})})]})}function Pe(){let e=se(),{data:t,isLoading:i,isError:a}=u(),{data:o}=r(void 0),{data:s}=n(void 0,{refetchInterval:1e4}),c=w(()=>{let e=new Map;e.set(`hub`,{id:`hub`,name:`Hub`,isHub:!0});for(let t of s??[]){let n=String(t.id??``);n&&e.set(n,{id:n,name:String(t.name??n),isHub:!!t.isHub})}return[...e.values()]},[s]),[l,ee]=E(`hub`),d=c.find(e=>e.id===l)??c[0],f=g(),te=y(),p=f.isPending||te.isPending,m=async()=>{await f.mutateAsync({nodeId:l}),await te.mutateAsync(),e.invalidateQueries({queryKey:[[`addons`]]})},h=x(f);h.current=f,O(()=>{h.current.mutate({nodeId:`hub`})},[]);let _=(t??[]).map(je).filter(e=>e!==null);return C(H,{children:[C(`div`,{className:`flex items-center justify-between gap-3 flex-wrap`,children:[D(v,{selectedNodeId:l,onSelect:ee}),C(`div`,{className:`flex items-center gap-3 flex-wrap`,children:[!i&&!a&&C(`span`,{className:`text-[10px] rounded-full bg-primary/10 text-primary px-2 py-0.5 font-medium`,children:[_.length,` installed`]}),C(`button`,{type:`button`,onClick:()=>void m(),disabled:p,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:[D(j,{className:`w-3 h-3 ${p?`animate-spin`:``}`}),`Check for updates`]})]})]}),!d.isHub&&C(`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`,` `,D(`span`,{className:`font-medium text-foreground`,children:d.name}),` — agents only run`,` `,D(`code`,{className:`font-mono`,children:`agent-only`}),` and`,` `,D(`code`,{className:`font-mono`,children:`any-node`}),` addons. Install / uninstall is hub-driven; agents auto-sync from the hub.`]}),i&&D(`div`,{className:`text-xs text-foreground-subtle animate-pulse`,children:`Loading…`}),a&&D(`div`,{className:`text-xs text-danger`,children:`Failed to load addons`}),!i&&!a&&D(Ne,{addons:_,clusterStatus:o,selectedNode:d,onRefresh:()=>void m(),isRefreshing:p})]})}export{Pe as AddonsPage};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{Ao as e,Ar as t,Br as n,Ca as r,Di as i,Gi as a,Hr as o,Lr as s,Mo as c,No as l,Rr as u,Sa as d,Ur as f,Vr as p,ba as m,do as h,g,io as _,jo as v,jr as y,lo as b,m as x,xa as S,zr as C}from"./src-s1tm1Ako.js";import{I as w,K as T,Q as E,S as D,W as O,o as k,q as A,x as j,z as M}from"./_virtual_mf___mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DTufy7Ue.js";import{p as N}from"./player-overlays-CM9K8NbB.js";import{t as P}from"./pencil-CM0OcKoQ.js";import{t as F}from"./radio-C1-CuToc.js";import{t as I}from"./refresh-cw-BCQ0uqSo.js";import{t as L}from"./rotate-cw-Bo4UhVCj.js";import{t as ee}from"./server-CqHxFx4j.js";import{t as R}from"./upload-D0e5f6HZ.js";import{F as z,G as B,L as te,M as ne,R as re,S as V,V as ie,i as ae,m as H,o as U,s as W,t as G}from"./index-BMoYnIQI.js";import{n as K,t as q}from"./build-cluster-graph-gWLixa2m.js";import{t as J}from"./format-size-CO9d3C3-.js";import{t as oe}from"./NodeAddonsSettingsPanel-BI-P31wN.js";var Y=B(`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=B(`git-fork`,[[`circle`,{cx:`12`,cy:`18`,r:`3`,key:`1mpf1b`}],[`circle`,{cx:`6`,cy:`6`,r:`3`,key:`1lh9wr`}],[`circle`,{cx:`18`,cy:`6`,r:`3`,key:`1h7g24`}],[`path`,{d:`M18 9v2c0 .6-.4 1-1 1H7c-.6 0-1-.4-1-1V9`,key:`1uq4wg`}],[`path`,{d:`M12 12v3`,key:`158kv8`}]]),ce=B(`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`}]]),le=B(`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`}]]),X=B(`skull`,[[`path`,{d:`m12.5 17-.5-1-.5 1h1z`,key:`3me087`}],[`path`,{d:`M15 22a1 1 0 0 0 1-1v-1a2 2 0 0 0 1.56-3.25 8 8 0 1 0-11.12 0A2 2 0 0 0 8 20v1a1 1 0 0 0 1 1z`,key:`1o5pge`}],[`circle`,{cx:`15`,cy:`12`,r:`1`,key:`1tmaij`}],[`circle`,{cx:`9`,cy:`12`,r:`1`,key:`1vctgf`}]]),ue=B(`table-2`,[[`path`,{d:`M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 1 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 1-2-2V9m0 0h18`,key:`gugj83`}]]);E();function de(e){let t=new FormData;return t.append(`file`,e.file,e.file.name),t.append(`nodeId`,e.nodeId),e.addonId&&t.append(`addonId`,e.addonId),new Promise((n,r)=>{let i=new XMLHttpRequest;i.open(`POST`,`/api/addons/upload`),e.token&&i.setRequestHeader(`Authorization`,`Bearer ${e.token}`),i.upload.addEventListener(`progress`,t=>{t.lengthComputable&&e.onProgress(Math.round(t.loaded/t.total*100))}),i.addEventListener(`load`,()=>{let e;try{e=JSON.parse(i.responseText)}catch{r(Error(`HTTP ${i.status}`));return}i.status>=200&&i.status<300?n(e):r(Error(e.error??`HTTP ${i.status}`))}),i.addEventListener(`error`,()=>r(Error(`Network error during upload`))),i.addEventListener(`abort`,()=>r(Error(`Upload aborted`))),i.send(t)})}function fe({nodeId:e,addons:t,isHub:n}){let r=k(),i=_(),[a,o]=A(null),[c,l]=A(null),[u,d]=A(!1),[p,m]=A(null),[h,g]=A(0),v=T(null),y=C(),b=f(),x=s({nodeId:e}),S=x.data??[],w=new Map(t.map(e=>[e.id,e.capabilities])),E=S.length>0?S.map(e=>({id:e.id,status:e.status,capabilities:w.get(e.id)??[],version:e.version,packageName:e.packageName})):t.map(e=>({id:e.id,status:e.status,capabilities:e.capabilities,version:void 0,packageName:void 0})),O=()=>{r.invalidateQueries({queryKey:[[`nodes`,`topology`]]}),x.refetch()},M=async t=>{o(t);try{await y.mutateAsync({nodeId:e,addonId:t}),O()}catch(e){console.error(`Failed to restart addon:`,e)}finally{o(null)}},N=async t=>{if(await i({title:`Uninstall addon`,message:`Remove "${t}" from ${e}? The addon directory will be deleted on disk.`,confirmLabel:`Uninstall`,variant:`danger`})){l(t);try{await b.mutateAsync({nodeId:e,addonId:t}),O()}catch(e){console.error(`Failed to uninstall addon:`,e)}finally{l(null)}}},P=D(`div`,{className:`flex items-center gap-2 mb-2`,children:[j(`input`,{ref:v,type:`file`,accept:`.tgz,.tar.gz`,className:`hidden`,onChange:async t=>{let n=t.target.files?.[0];if(n){t.target.value=``,m(null),d(!0),g(0);try{await de({file:n,nodeId:e,token:localStorage.getItem(`camstack_admin_token`),onProgress:g}),O()}catch(e){m(e instanceof Error?e.message:String(e))}finally{d(!1),g(0)}}}}),D(`button`,{onClick:()=>v.current?.click(),disabled:u,className:`inline-flex items-center gap-1.5 rounded-md border border-border px-2.5 py-1 text-[11px] font-medium text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors disabled:opacity-50`,children:[u?j(V,{className:`h-3 w-3 animate-spin`}):j(R,{className:`h-3 w-3`}),u?`Uploading… ${h}%`:`Upload addon (.tgz)`]}),u&&j(`div`,{className:`flex-1 h-1 rounded-full bg-muted overflow-hidden max-w-[140px]`,children:j(`div`,{className:`h-full bg-primary transition-all`,style:{width:`${h}%`}})}),p&&j(`span`,{className:`text-[10px] text-destructive`,children:p})]});return E.length===0?D(`div`,{children:[P,j(`div`,{className:`py-4 text-xs text-muted-foreground text-center`,children:x.isLoading?`Loading addons…`:`No addons on this node`})]}):D(`div`,{children:[P,j(`div`,{className:`rounded-lg border border-border max-h-[60vh] overflow-auto`,children:D(`table`,{className:`w-full text-xs`,children:[j(`thead`,{className:`sticky top-0 z-10 bg-surface`,children:D(`tr`,{className:`text-muted-foreground text-left`,children:[j(`th`,{className:`px-3 py-2 font-medium`,children:`Addon`}),j(`th`,{className:`px-3 py-2 font-medium`,children:`Version`}),j(`th`,{className:`px-3 py-2 font-medium`,children:`Capabilities`}),j(`th`,{className:`px-3 py-2 font-medium`,children:`Status`}),j(`th`,{className:`px-3 py-2 font-medium w-16`})]})}),j(`tbody`,{children:E.map(e=>D(`tr`,{className:`border-t border-border/50`,children:[D(`td`,{className:`px-3 py-2 font-medium`,children:[j(`div`,{children:e.id}),e.packageName&&j(`div`,{className:`text-[9px] text-muted-foreground`,children:e.packageName})]}),j(`td`,{className:`px-3 py-2 text-muted-foreground`,children:e.version??`—`}),j(`td`,{className:`px-3 py-2`,children:j(`div`,{className:`flex flex-wrap gap-1`,children:e.capabilities.length>0?e.capabilities.map(e=>j(`span`,{className:`text-[9px] px-1 py-0.5 rounded bg-blue-500/10 text-blue-400`,children:e},e)):j(`span`,{className:`text-muted-foreground`,children:`—`})})}),j(`td`,{className:`px-3 py-2`,children:j(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded-full ${e.status===`running`?`bg-success/10 text-success`:e.status===`error`?`bg-destructive/10 text-destructive`:`bg-muted text-muted-foreground`}`,children:e.status})}),j(`td`,{className:`px-3 py-2`,children:D(`div`,{className:`flex items-center gap-1 justify-end`,children:[j(`button`,{onClick:()=>M(e.id),disabled:a===e.id||c===e.id,className:`p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50`,title:`Restart ${e.id}`,children:j(L,{className:`h-3 w-3 ${a===e.id?`animate-spin`:``}`})}),j(`button`,{onClick:()=>N(e.id),disabled:a===e.id||c===e.id,className:`p-1 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive transition-colors disabled:opacity-50`,title:`Uninstall ${e.id}`,children:c===e.id?j(V,{className:`h-3 w-3 animate-spin`}):j(W,{className:`h-3 w-3`})})]})})]},e.id))})]})})]})}E();function pe(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 me({state:e}){return j(`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 he=[`trace`,`debug`,`info`,`warn`,`error`];function ge({proc:t,nodeId:r,defaultExpanded:i,activePanel:a,onTogglePanel:o}){let s=t.services??[],u=s.length===1,[d,f]=A(u||i),[m,h]=A(null),[_,y]=A(`info`),b=t.name.includes(`(core)`),S=C(),w=n(),T=p(),E=async e=>{h(e);try{await S.mutateAsync({nodeId:r,addonId:e})}catch(e){console.error(`Failed to restart addon:`,e)}finally{h(null)}},O=async()=>{h(t.name);try{await w.mutateAsync({nodeId:r,processName:t.name})}catch(e){console.error(`Failed to restart process:`,e)}finally{h(null)}},k=async e=>{let n=`${r}/${t.name}`;try{await T.mutateAsync({nodeId:n,level:e}),y(e)}catch(e){console.error(`Failed to set log level:`,e)}};return D(`div`,{className:`border border-border/50 rounded-lg overflow-hidden`,children:[D(`div`,{role:u?void 0:`button`,tabIndex:u?void 0:0,onClick:u?void 0:()=>f(!d),onKeyDown:u?void 0:e=>{(e.key===`Enter`||e.key===` `)&&f(!d)},className:`flex items-center gap-2 w-full px-3 py-2 bg-muted/20 transition-colors text-left select-none ${u?``:`hover:bg-muted/40 cursor-pointer`}`,children:[u?j(`span`,{className:`h-3 w-3 shrink-0`}):j(d?te:z,{className:`h-3 w-3 text-muted-foreground shrink-0`}),b?j(ee,{className:`h-3.5 w-3.5 text-primary shrink-0`}):j(ie,{className:`h-3.5 w-3.5 text-amber-500 shrink-0`}),j(`span`,{className:`text-xs font-semibold flex-1`,children:t.name}),D(`span`,{className:`text-[10px] text-muted-foreground tabular-nums`,children:[`PID `,t.pid]}),j(me,{state:t.state}),D(`span`,{className:`text-[10px] text-muted-foreground tabular-nums`,children:[t.cpuPercent,`% CPU`]}),j(`span`,{className:`text-[10px] text-muted-foreground tabular-nums`,children:J(t.memoryRss)}),j(`span`,{className:`text-[10px] text-muted-foreground tabular-nums`,children:pe(t.uptimeSeconds)}),!b&&D(`div`,{className:`flex items-center gap-1`,onClick:e=>e.stopPropagation(),children:[D(e,{children:[j(l,{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:_}),j(v,{align:`end`,className:`min-w-[70px] py-0.5`,children:he.map(e=>j(c,{onClick:()=>k(e),className:`h-auto px-2 py-1 text-[10px] font-mono ${e===_?`text-primary font-semibold`:``}`,children:e},e))})]}),j(`button`,{onClick:O,disabled:m===t.name,className:`p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50`,title:`Restart process`,children:j(L,{className:`h-3 w-3 ${m===t.name?`animate-spin`:``}`})})]})]}),d&&s.length>0&&j(`div`,{className:`divide-y divide-border/30`,children:s.map(e=>D(`div`,{children:[D(`div`,{className:`flex items-center gap-2 px-3 py-1.5 pl-9 hover:bg-muted/10 transition-colors`,children:[j(`div`,{className:`h-1.5 w-1.5 rounded-full shrink-0 ${e.status===`running`?`bg-success`:`bg-muted-foreground/30`}`}),j(`span`,{className:`text-xs font-medium flex-1 min-w-0 truncate`,children:e.addonId}),e.capabilities.length>0&&D(`div`,{className:`flex gap-1 flex-shrink-0`,children:[e.capabilities.slice(0,3).map(e=>j(`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&&D(`span`,{className:`text-[9px] text-muted-foreground`,children:[`+`,e.capabilities.length-3]})]}),D(`div`,{className:`flex items-center gap-1 shrink-0`,children:[j(`button`,{onClick:()=>o(e.addonId,`logs`),className:`p-0.5 rounded transition-colors ${a?.addonId===e.addonId&&a.type===`logs`?`bg-primary/10 text-primary`:`hover:bg-muted text-muted-foreground hover:text-foreground`}`,title:`Show logs for ${e.addonId}`,children:j(H,{className:`h-3 w-3`})}),j(`button`,{onClick:()=>o(e.addonId,`events`),className:`p-0.5 rounded transition-colors ${a?.addonId===e.addonId&&a.type===`events`?`bg-primary/10 text-primary`:`hover:bg-muted text-muted-foreground hover:text-foreground`}`,title:`Show events for ${e.addonId}`,children:j(F,{className:`h-3 w-3`})}),j(`button`,{onClick:()=>E(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:j(L,{className:`h-3 w-3 ${m===e.addonId?`animate-spin`:``}`})})]})]}),a?.addonId===e.addonId&&a.type===`logs`&&j(`div`,{className:`border-t border-border/40 bg-muted/5`,children:j(g,{addonId:e.addonId,agentId:r,maxHeight:`max-h-48`,showFilters:!1,onClose:()=>o(e.addonId,`logs`)})}),a?.addonId===e.addonId&&a.type===`events`&&j(`div`,{className:`border-t border-border/40 bg-muted/5`,children:j(x,{addonId:e.addonId,category:`addon.*`,maxHeight:`max-h-48`,onClose:()=>o(e.addonId,`events`)})})]},e.addonId))}),d&&s.length===0&&j(`div`,{className:`px-3 py-2 pl-9 text-[10px] text-muted-foreground`,children:`No services`})]})}function _e({nodeId:e,processes:t}){let[n,r]=A(null),i=(e,t)=>{r(n=>n?.addonId===e&&n.type===t?null:{addonId:e,type:t})};return t.length===0?j(`div`,{className:`py-4 text-xs text-muted-foreground text-center`,children:`No processes on this node`}):j(`div`,{className:`space-y-2 py-1`,children:t.map((t,r)=>j(ge,{proc:t,nodeId:e,defaultExpanded:r===0,activePanel:n,onTogglePanel:i},t.name))})}E();function ve(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 ye(e,t=80){return e.length<=t?e:`…${e.slice(e.length-t+1)}`}function be({nodeId:e}){let n=k(),r=_(),[i,a]=A(`all`),o=b(`metrics.node-processes-snapshot`,t=>t.nodeId===e),{data:s}=y({nodeId:e}),c=o?.processes??s,l=O(()=>c?[...c]:[],[c]),u=O(()=>i===`ghost`?l.filter(e=>e.classification===`ghost`):l,[l,i]),d=O(()=>{let e=l.filter(e=>e.classification===`ghost`),t=new Map;for(let n of e)t.has(n.ppid)||t.set(n.ppid,[]),t.get(n.ppid).push(n);return[...t.entries()].filter(([,e])=>e.length>1).map(([e,t])=>({ppid:e,children:t})).toSorted((e,t)=>t.children.length-e.children.length)},[l]),f=t({onSettled:()=>{n.invalidateQueries({queryKey:[[`metricsProvider`,`listNodeProcesses`]]})}}),p=O(()=>{let e=new Map;for(let t of l)e.set(t.pid,t.classification);return e},[l]),m=async(t,n)=>{if(t.classification===`root`||t.classification===`system`)return;let i=t.classification===`ghost`?`ghost`:t.addonId??`process`,a=n?`SIGKILL`:`SIGTERM`;await r({title:`Send ${a}?`,message:`Target pid ${t.pid} (${i}) on node ${e}.`,confirmLabel:`Send ${a}`,variant:`danger`})&&f.mutate({nodeId:e,pid:t.pid,force:n})},h=async(t,n)=>{try{await f.mutateAsync({nodeId:e,pid:t,force:n})}catch{}},g=async t=>{let i=p.get(t.ppid);if(i===`root`||i===`system`){await r({title:`Cannot kill protected ancestor`,message:i===`root`?`pid ${t.ppid} is the current node supervisor. Restart the node via the cluster page instead.`:`pid ${t.ppid} is a system ancestor (concurrently / vite / npm wrapper). Killing it would tear down the dev tree.`,confirmLabel:`OK`,cancelLabel:`Close`,variant:`warning`});return}await r({title:`Kill ghost parent + ${t.children.length} child(ren)?`,message:`SIGKILL parent pid ${t.ppid} and SIGTERM ${t.children.length} ghost child(ren) on node ${e}.`,confirmLabel:`Kill all`,variant:`danger`})&&(await Promise.all([h(t.ppid,!0),...t.children.map(e=>h(e.pid,!1))]),n.invalidateQueries({queryKey:[[`metricsProvider`,`listNodeProcesses`]]}))},v=async()=>{let t=l.filter(e=>e.classification===`ghost`);t.length!==0&&await r({title:`Kill all ${t.length} ghost process(es)?`,message:`SIGKILL ${t.length} ghost process(es) on node ${e}. This is irreversible.`,confirmLabel:`Kill all`,variant:`danger`})&&(await Promise.all(t.map(e=>h(e.pid,!0))),n.invalidateQueries({queryKey:[[`metricsProvider`,`listNodeProcesses`]]}))},x=l.filter(e=>e.classification===`ghost`).length,S=l.filter(e=>e.classification===`managed`).length,C=l.filter(e=>e.classification===`root`).length,w=l.filter(e=>e.classification===`system`).length;return D(`div`,{className:`space-y-4`,children:[D(`div`,{className:`flex items-start justify-between gap-4`,children:[D(`p`,{className:`text-[11px] text-foreground-subtle`,children:[`ps`," scan + kernel `$process.list` cross-reference. Ghosts = camstack-shaped commands with no managed binding (usually orphaned to ppid=1). Refreshes every 10s."]}),D(`button`,{type:`button`,onClick:()=>n.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:[j(I,{className:`h-3 w-3`}),` Refresh`]})]}),D(`div`,{className:`grid grid-cols-4 gap-3`,children:[D(`div`,{className:`rounded-lg border border-border p-3`,children:[j(`div`,{className:`text-[10px] uppercase tracking-wider text-foreground-subtle`,children:`Root`}),j(`div`,{className:`text-xl font-semibold text-foreground`,children:C})]}),D(`div`,{className:`rounded-lg border border-border p-3`,children:[j(`div`,{className:`text-[10px] uppercase tracking-wider text-foreground-subtle`,children:`Managed`}),j(`div`,{className:`text-xl font-semibold text-foreground`,children:S})]}),D(`div`,{className:`rounded-lg border border-border p-3`,children:[j(`div`,{className:`text-[10px] uppercase tracking-wider text-foreground-subtle`,children:`System`}),j(`div`,{className:`text-xl font-semibold text-foreground`,children:w})]}),D(`div`,{className:`rounded-lg border p-3 ${x>0?`border-destructive/40 bg-destructive/5`:`border-border`}`,children:[D(`div`,{className:`text-[10px] uppercase tracking-wider text-foreground-subtle flex items-center gap-1`,children:[x>0&&j(X,{className:`h-3 w-3 text-destructive`}),` Ghosts`]}),j(`div`,{className:`text-xl font-semibold ${x>0?`text-destructive`:`text-foreground`}`,children:x})]})]}),d.length>0&&D(`div`,{className:`rounded-lg border border-amber-500/40 bg-amber-500/5 p-3`,children:[D(`div`,{className:`flex items-center gap-1 text-[11px] font-semibold text-amber-400 mb-2`,children:[j(U,{className:`h-3 w-3`}),` Recurring ghost parents (`,d.length,`)`]}),j(`div`,{className:`space-y-1.5`,children:d.map(e=>D(`div`,{className:`text-[11px] text-foreground flex items-center justify-between gap-2`,children:[D(`div`,{className:`flex items-center gap-2`,children:[D(`span`,{className:`font-mono text-foreground-subtle`,children:[`ppid `,e.ppid]}),D(`span`,{children:[`→ `,e.children.length,` ghost(s)`]})]}),D(`button`,{type:`button`,disabled:f.isPending,onClick:()=>{g(e)},className:`inline-flex items-center gap-1 rounded border border-amber-500/40 bg-amber-500/10 px-2 py-0.5 text-[10px] text-amber-400 hover:bg-amber-500/20 disabled:opacity-30`,children:[j(X,{className:`h-3 w-3`}),` Kill parent + `,e.children.length]})]},e.ppid))})]}),D(`div`,{className:`flex items-center justify-between gap-2 text-[11px]`,children:[D(`div`,{className:`flex items-center gap-2`,children:[j(`span`,{className:`text-foreground-subtle`,children:`Filter:`}),D(`button`,{type:`button`,className:`px-2 py-0.5 rounded ${i===`all`?`bg-primary text-primary-foreground`:`border border-border text-foreground hover:bg-surface-hover`}`,onClick:()=>a(`all`),children:[`All (`,l.length,`)`]}),D(`button`,{type:`button`,className:`px-2 py-0.5 rounded ${i===`ghost`?`bg-destructive text-destructive-foreground`:`border border-border text-foreground hover:bg-surface-hover`}`,onClick:()=>a(`ghost`),children:[`Ghost only (`,x,`)`]})]}),x>0&&D(`button`,{type:`button`,disabled:f.isPending,onClick:()=>{v()},className:`inline-flex items-center gap-1 rounded border border-destructive/40 bg-destructive/10 px-2 py-1 text-[11px] font-medium text-destructive hover:bg-destructive/20 disabled:opacity-30`,children:[j(X,{className:`h-3 w-3`}),` Kill all `,x,` ghost(s)`]})]}),j(`div`,{className:`rounded-lg border border-border max-h-[60vh] overflow-auto`,children:D(`table`,{className:`w-full text-xs`,children:[j(`thead`,{className:`sticky top-0 z-10 bg-surface`,children:D(`tr`,{className:`text-foreground-subtle text-[10px] uppercase tracking-wider`,children:[j(`th`,{className:`text-left px-3 py-2`,children:`Class`}),j(`th`,{className:`text-right px-3 py-2`,children:`PID`}),j(`th`,{className:`text-right px-3 py-2`,children:`PPID`}),j(`th`,{className:`text-left px-3 py-2`,children:`Addon`}),j(`th`,{className:`text-left px-3 py-2`,children:`Command`}),j(`th`,{className:`text-right px-3 py-2`,children:`CPU%`}),j(`th`,{className:`text-right px-3 py-2`,children:`RSS`}),j(`th`,{className:`text-right px-3 py-2`,children:`Uptime`}),j(`th`,{className:`w-44`})]})}),D(`tbody`,{children:[u.length===0&&j(`tr`,{children:j(`td`,{colSpan:9,className:`px-3 py-4 text-center text-foreground-subtle text-[11px]`,children:i===`ghost`?`No ghost processes detected.`:`Scanning…`})}),u.map(e=>D(`tr`,{className:`border-t border-border ${e.classification===`ghost`?`bg-destructive/5`:``}`,children:[j(`td`,{className:`px-3 py-2`,children:j(`span`,{className:`inline-block rounded-full px-1.5 py-0.5 text-[10px] font-medium ${e.classification===`ghost`?`bg-destructive/20 text-destructive`: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})}),j(`td`,{className:`px-3 py-2 text-right font-mono text-foreground`,children:e.pid}),D(`td`,{className:`px-3 py-2 text-right font-mono text-foreground-subtle`,children:[e.ppid,e.orphaned?` ⚠`:``]}),j(`td`,{className:`px-3 py-2 text-foreground-subtle text-[11px]`,children:e.addonId??`—`}),j(`td`,{className:`px-3 py-2 font-mono text-[10px] text-foreground-subtle break-all`,children:ye(e.command)}),j(`td`,{className:`px-3 py-2 text-right text-foreground`,children:e.cpuPercent.toFixed(1)}),j(`td`,{className:`px-3 py-2 text-right text-foreground`,children:J(e.memoryRssBytes)}),j(`td`,{className:`px-3 py-2 text-right text-foreground-subtle`,children:ve(e.uptimeSec)}),j(`td`,{className:`px-3 py-2 text-right`,children:D(`div`,{className:`inline-flex gap-1`,children:[D(`button`,{type:`button`,disabled:f.isPending||e.classification===`root`||e.classification===`system`,onClick:()=>{m(e,!1)},title:`SIGTERM`,className:`inline-flex items-center gap-1 px-1.5 py-0.5 rounded border border-border text-[10px] text-foreground hover:bg-surface-hover disabled:opacity-30`,children:[j(W,{className:`h-3 w-3`}),` Term`]}),D(`button`,{type:`button`,disabled:f.isPending||e.classification===`root`||e.classification===`system`,onClick:()=>{m(e,!0)},title:`SIGKILL`,className:`inline-flex items-center gap-1 px-1.5 py-0.5 rounded border border-destructive/30 text-[10px] text-destructive hover:bg-destructive/10 disabled:opacity-30`,children:[j(X,{className:`h-3 w-3`}),` Kill`]})]})})]},e.pid))]})]})}),f.isError&&D(`div`,{className:`rounded-md border border-destructive/30 bg-destructive/5 px-3 py-2 text-[11px] text-destructive`,children:[`Kill failed:`,` `,f.error instanceof Error?f.error.message:`unknown`]})]})}function xe({nodeId:e,addonIds:t}){return t.length===0?j(`div`,{className:`py-4 text-xs text-muted-foreground text-center`,children:`No addons on this node`}):j(`div`,{className:`w-full py-2`,children:j(oe,{nodeId:e,addonIds:t,level:`global`,selfTabbed:!0})})}E();function Se({nodeId:e,addons:t}){let n=k(),{data:r,isLoading:o}=i({nodeId:e}),s=O(()=>{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=a({onSuccess:()=>{n.invalidateQueries({queryKey:[[`pipelineOrchestrator`,`getCapabilityBindings`]]})}});return s.length===0?j(`div`,{className:`py-4 text-xs text-muted-foreground text-center`,children:`No capabilities on this node`}):j(`div`,{className:`rounded-lg border border-border max-h-[60vh] overflow-auto`,children:D(`table`,{className:`w-full text-xs`,children:[j(`thead`,{className:`sticky top-0 z-10 bg-surface`,children:D(`tr`,{className:`text-muted-foreground text-left`,children:[j(`th`,{className:`px-3 py-2 font-medium w-1/2`,children:`Capability`}),j(`th`,{className:`px-3 py-2 font-medium`,children:`Bound provider`})]})}),j(`tbody`,{children:s.map(({capName:t,providers:n})=>{let i=r?.[t]??n[0]??``,a=n.length===1;return D(`tr`,{className:`border-t border-border/50`,children:[j(`td`,{className:`px-3 py-2 font-medium`,children:t}),j(`td`,{className:`px-3 py-2`,children:j(`select`,{value:i,onChange:n=>c.mutate({nodeId:e,capName:t,addonId:n.target.value}),disabled:a||c.isPending||o,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:n.map(e=>j(`option`,{value:e,children:e},e))})})]},t)})})]})})}E();function Z(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 Ce(e){let[t,n]=A(!1),[r,i]=A(e.name),a=k(),o=u({onSuccess:()=>{a.invalidateQueries({queryKey:[[`nodes`,`topology`]]})}}),s=(e.localIps??[]).filter(e=>!e.includes(`:`)),c=(e.localIps??[]).filter(e=>e.includes(`:`)),l=async()=>{if(!r.trim()||r===e.name){n(!1);return}try{await o.mutateAsync({nodeId:e.nodeId,name:r.trim()}),n(!1)}catch(e){console.error(`Rename failed:`,e)}},d=[[`Node ID`,j(`span`,{className:`font-mono text-xs`,children:e.nodeId})],[`Display Name`,t?D(`div`,{className:`flex items-center gap-1.5`,children:[j(`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:r,onChange:e=>i(e.target.value),onKeyDown:e=>{e.key===`Enter`&&l(),e.key===`Escape`&&n(!1)},disabled:o.isPending,autoFocus:!0}),j(`button`,{onClick:()=>void l(),disabled:o.isPending,className:`p-0.5 text-success hover:bg-success/10 rounded`,title:`Save`,children:j(re,{className:`h-3.5 w-3.5`})}),j(`button`,{onClick:()=>n(!1),className:`p-0.5 text-muted-foreground hover:bg-muted rounded`,title:`Cancel`,children:j(ae,{className:`h-3.5 w-3.5`})})]}):D(`div`,{className:`flex items-center gap-1.5`,children:[j(`span`,{className:`text-xs`,children:e.name}),!e.isHub&&j(`button`,{onClick:()=>{i(e.name),n(!0)},className:`p-0.5 text-muted-foreground hover:text-primary rounded`,title:`Rename`,children:j(P,{className:`h-3 w-3`})})]})],[`Hostname`,j(`span`,{className:`text-xs`,children:e.hostname})],[`Role`,e.isHub?j(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded bg-primary/10 text-primary font-medium`,children:`Hub`}):j(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded bg-muted text-muted-foreground font-medium`,children:`Agent`})],[`Root Package`,e.rootPackage?D(`span`,{className:`font-mono text-xs`,children:[e.rootPackage.name,`@`,e.rootPackage.version]}):j(`span`,{className:`text-xs text-muted-foreground`,children:`—`})],[`Platform`,D(`span`,{className:`text-xs`,children:[e.platform,` / `,e.arch]})],[`CPU`,D(`span`,{className:`text-xs`,children:[e.cpuModel??`—`,` (`,e.cpuCores,` cores)`]})],[`Memory`,j(`span`,{className:`text-xs`,children:e.memoryMB>0?`${(e.memoryMB/1024).toFixed(1)} GB`:`—`})],[`Uptime`,j(`span`,{className:`text-xs`,children:Z(e.uptime)})],[`Engines`,e.engines.length>0?j(`div`,{className:`flex flex-wrap gap-1`,children:e.engines.map(e=>j(`span`,{className:`text-[9px] px-1.5 py-0.5 rounded-full bg-purple-500/10 text-purple-400 font-medium`,children:e},e))}):j(`span`,{className:`text-xs text-muted-foreground`,children:`—`})]];return s.length>0&&d.push([`IPv4`,j(`div`,{className:`flex flex-wrap gap-1.5`,children:s.map((e,t)=>j(`span`,{className:`font-mono text-xs px-1.5 py-0.5 rounded bg-muted`,children:e},`${e}-${t}`))})]),c.length>0&&d.push([`IPv6`,j(`div`,{className:`flex flex-wrap gap-1.5`,children:c.map((e,t)=>j(`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}`))})]),j(`div`,{className:`py-2`,children:j(`table`,{className:`w-full text-sm`,children:j(`tbody`,{children:d.map(([e,t],n)=>D(`tr`,{className:n%2==0?`bg-muted/20`:``,children:[j(`td`,{className:`py-1.5 px-2 text-xs font-medium text-muted-foreground w-28 align-top whitespace-nowrap`,children:e}),j(`td`,{className:`py-1.5 px-2`,children:t})]},e))})})})}E();var we=[[`serverManagement`,`getServerPackageStatus`]];function Q({label:e,tone:t}){return j(`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 D(`div`,{className:`flex items-center justify-between gap-4 text-sm`,children:[j(`span`,{className:`text-foreground-subtle`,children:e}),j(`span`,{className:`font-mono text-foreground`,children:t??`—`})]})}function Te({node:e}){let{t}=G(),n=k(),i=_(),[a,o]=A(!1),s=e.isHub?void 0:{nodeId:e.id},c=d(s,{refetchInterval:1e4,enabled:e.isOnline,retry:1}),l=c.data??null,u=w(()=>{n.invalidateQueries({queryKey:we})},[n]),f=S({onSettled:u}),p=m({onSettled:u}),h=r({onSettled:u}),g=w(async()=>{l?.latestVersion!=null&&await i({title:t(`serverManagement.confirmUpdateTitle`,`Update node root package`),message:t(`serverManagement.confirmUpdateBody`,`Install {{pkg}}@{{version}} on "{{node}}" and restart to apply.`,{pkg:l.packageName,version:l.latestVersion,node:e.name}),confirmLabel:t(`serverManagement.confirmUpdateAction`,`Update & restart`)})&&(await p.mutateAsync({version:l.latestVersion,...s})).restarting&&o(!0)},[p,i,e.name,s,l,t]),v=w(async()=>{await i({title:t(`serverManagement.confirmRestartTitle`,`Restart node`),message:t(`serverManagement.confirmRestartBody`,`Restart "{{node}}"? In-flight requests to this node are dropped.`,{node:e.name}),confirmLabel:t(`serverManagement.confirmRestartAction`,`Restart`),variant:`warning`})&&(await h.mutateAsync(s)).restarting&&o(!0)},[i,e.name,h,s,t]),y=()=>{switch(l?.bootMode){case`data-root`:return{label:t(`serverManagement.bootDataRoot`,`runtime-updatable`),tone:`ok`};case`workspace`:return{label:t(`serverManagement.bootWorkspace`,`dev workspace`),tone:`info`};default:return{label:t(`serverManagement.bootBaked`,`baked image seed`),tone:`neutral`}}},b=()=>{if(l==null)return null;switch(l.updateState){case`checking`:return{label:t(`serverManagement.stateChecking`,`checking…`),tone:`info`};case`staging`:return{label:t(`serverManagement.stateStaging`,`updating…`),tone:`info`};case`pending-restart`:return{label:t(`serverManagement.statePending`,`restart pending`),tone:`warn`};default:return l.updateAvailable?{label:t(`serverManagement.stateUpdateAvailable`,`update available`),tone:`warn`}:{label:t(`serverManagement.stateUpToDate`,`up to date`),tone:`ok`}}},x=l?.bootMode===`workspace`,C=e.isOnline&&l!=null&&!x&&l.updateAvailable&&l.updateState===`idle`&&!p.isPending,T=e.isOnline&&l!=null&&l.updateState===`idle`&&!h.isPending,E=e.isOnline?b():null;return D(`div`,{className:`space-y-4 py-2`,children:[D(`div`,{className:`flex items-center justify-between gap-3`,children:[D(`div`,{className:`flex items-center gap-2 min-w-0`,children:[j(`span`,{className:`font-mono text-xs text-foreground-subtle truncate`,children:l?.packageName??e.rootPackage?.name??`@camstack/server`}),e.isOnline&&l!=null&&j(Q,{...y()})]}),E!=null&&j(Q,{...E})]}),!e.isOnline&&j($,{label:t(`serverManagement.lastReportedVersion`,`Last reported version`),value:e.rootPackage?.version??null}),e.isOnline&&c.isLoading&&D(`div`,{className:`flex items-center gap-2 text-sm text-foreground-subtle`,children:[j(V,{className:`h-4 w-4 animate-spin`}),t(`common.loading`,`Loading…`)]}),e.isOnline&&c.isError&&D(`div`,{className:`space-y-1.5`,children:[j(`p`,{className:`text-sm text-red-500`,children:t(`serverManagement.loadError`,`Could not load the node root-package status.`)}),e.rootPackage!=null&&j($,{label:t(`serverManagement.lastReportedVersion`,`Last reported version`),value:e.rootPackage.version})]}),e.isOnline&&l!=null&&D(`div`,{className:`space-y-1.5`,children:[j($,{label:t(`serverManagement.runningVersion`,`Running version`),value:l.runningVersion}),j($,{label:t(`serverManagement.latestVersion`,`Latest on registry`),value:l.latestVersion}),j($,{label:t(`serverManagement.imageSeedVersion`,`Image seed (baked)`),value:l.seedVersion}),j($,{label:t(`serverManagement.nodeRuntimeVersion`,`Node.js runtime`),value:l.nodeRuntimeVersion}),l.pendingVersion!=null&&j($,{label:t(`serverManagement.pendingVersion`,`Staged (applies on restart)`),value:l.pendingVersion})]}),e.isOnline&&(l?.imageContract?.state===`behind-series`||l?.imageContract?.state===`behind-patch`)&&D(`div`,{className:`rounded-md border px-3 py-2 text-xs leading-relaxed ${l.imageContract.state===`behind-series`?`border-red-500/40 bg-red-500/10 text-red-500`:`border-amber-500/40 bg-amber-500/10 text-amber-500`}`,children:[j(`p`,{className:`mb-0.5 font-semibold`,children:t(`serverManagement.imageContractDiverged`,`Container image diverges from the deployment contract`)}),j(`p`,{children:l.imageContract.message})]}),e.isOnline&&x&&j(`p`,{className:`text-xs text-foreground-subtle`,children:t(`serverManagement.workspaceNote`,`Development workspace detected — runtime updates are disabled (the dev loop resolves code from the workspace).`)}),a&&D(`div`,{className:`flex items-center gap-2 text-sm text-amber-500`,children:[j(V,{className:`h-4 w-4 animate-spin`}),t(`serverManagement.nodeRestarting`,`The node is restarting to apply the change…`)]}),e.isOnline&&D(`div`,{className:`flex flex-wrap items-center gap-2 pt-1`,children:[D(`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:f.isPending||l?.updateState===`staging`,onClick:()=>f.mutate(s),children:[f.isPending?j(V,{className:`h-3.5 w-3.5 animate-spin`}):j(I,{className:`h-3.5 w-3.5`}),t(`serverManagement.checkForUpdate`,`Check for update`)]}),C&&D(`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 g(),children:[p.isPending?j(V,{className:`h-3.5 w-3.5 animate-spin`}):j(Y,{className:`h-3.5 w-3.5`}),t(`serverManagement.updateTo`,`Update to {{version}}`,{version:l?.latestVersion??``})]}),D(`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:!T,onClick:()=>void v(),children:[h.isPending?j(V,{className:`h-3.5 w-3.5 animate-spin`}):j(L,{className:`h-3.5 w-3.5`}),t(`serverManagement.restart`,`Restart`)]})]}),e.isOnline&&l?.lastCheckedAtMs!=null&&D(`p`,{className:`flex items-center gap-1.5 text-[11px] text-foreground-subtle`,children:[j(ce,{className:`h-3 w-3`}),t(`serverManagement.lastChecked`,`Last checked: {{when}}`,{when:new Date(l.lastCheckedAtMs).toLocaleString()})]})]})}E();function Ee({node:e}){let t=N(),[n,r]=A(`info`),[i,a]=A(!1),o=e.processes??[],s=e.addons.map(e=>e.id),c=async()=>{if(!i){a(!0);try{await Promise.allSettled([t.trpcClient.pipelineOrchestrator.removeAgentSettings.mutate({agentNodeId:e.id}),t.trpcClient.clusterNodes.forgetNode.mutate({nodeId:e.id})])}finally{a(!1)}}};return e.isOnline?D(`div`,{className:`border border-border rounded-xl`,children:[D(`div`,{className:`flex items-center gap-3 px-4 py-3 bg-muted/30 border-b border-border rounded-t-xl`,children:[j(`div`,{className:`w-2.5 h-2.5 rounded-full bg-success`}),j(`span`,{className:`text-sm font-semibold`,children:e.name}),D(`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=>j(`span`,{className:`text-[9px] px-1.5 py-0.5 rounded-full bg-purple-500/10 text-purple-400 font-medium`,children:e},e)),D(`div`,{className:`ml-auto flex gap-3 text-xs text-muted-foreground`,children:[D(`span`,{className:`flex items-center gap-1`,children:[j(ne,{className:`h-3 w-3`}),` `,e.cpuPercent,`%`]}),D(`span`,{className:`flex items-center gap-1`,children:[j(le,{className:`h-3 w-3`}),` `,e.memoryPercent,`%`]})]})]}),j(`div`,{className:`sticky top-0 z-20 flex border-b border-border px-4 bg-background overflow-x-auto`,children:[`info`,`addons`,`forks`,`processes`,`settings`,`capabilities`].map(t=>j(`button`,{onClick:()=>r(t),className:`shrink-0 whitespace-nowrap px-3 py-2 text-xs font-medium border-b-2 transition-colors ${n===t?`border-primary text-primary`:`border-transparent text-muted-foreground hover:text-foreground`}`,children:t===`info`?`General`:t===`addons`?`Addons (${e.addons.length})`:t===`forks`?`Forks (${o.length})`:t===`processes`?`Processes`:t===`settings`?`Settings`:`Capabilities`},t))}),D(`div`,{className:`px-4 py-2`,children:[n===`info`&&D(`div`,{className:`space-y-3`,children:[j(Ce,{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}),j(`div`,{className:`border-t border-border pt-1`,children:j(Te,{node:{id:e.id,name:e.name,isHub:e.isHub,isOnline:e.isOnline,rootPackage:e.rootPackage??null}})})]}),n===`addons`&&j(fe,{nodeId:e.id,addons:e.addons,isHub:e.isHub}),n===`forks`&&j(_e,{nodeId:e.id,processes:o}),n===`processes`&&j(be,{nodeId:e.id}),n===`settings`&&j(xe,{nodeId:e.id,addonIds:s}),n===`capabilities`&&j(Se,{nodeId:e.id,addons:e.addons})]})]}):D(`div`,{className:`border border-border rounded-xl overflow-hidden opacity-60`,children:[D(`div`,{className:`flex items-center gap-3 px-4 py-3 bg-muted/30`,children:[j(`div`,{className:`w-2.5 h-2.5 rounded-full bg-destructive`}),j(`span`,{className:`text-sm font-semibold`,children:e.name}),D(`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=>j(`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&&D(`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]}),j(`span`,{className:`ml-auto text-xs px-2 py-0.5 rounded-full bg-destructive/10 text-destructive`,children:`offline`})]}),D(`div`,{className:`flex items-center justify-between gap-3 px-4 py-3`,children:[D(`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`]}),D(`button`,{type:`button`,onClick:()=>void c(),disabled:i,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:[j(W,{className:`h-3 w-3`}),i?`Forgetting…`:`Forget node`]})]})]})}E();function De({nodes:e,focusNodeId:t,focusNonce:n}){let r=[...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)),i=T(null);return M(()=>{if(!t)return;let e=i.current?.querySelector(`#node-card-${CSS.escape(t)}`);e&&e.scrollIntoView({behavior:`smooth`,block:`start`})},[t,n]),j(`div`,{ref:i,className:`flex flex-col gap-4`,children:r.map(e=>j(`div`,{id:`node-card-${e.id}`,children:j(Ee,{node:e})},e.id))})}E();function Oe(e){let[t,n]=A(()=>typeof window<`u`?window.matchMedia(e).matches:!1);return M(()=>{let t=window.matchMedia(e),r=e=>n(e.matches);return t.addEventListener(`change`,r),()=>t.removeEventListener(`change`,r)},[e]),t}function ke(){let{data:e,isLoading:t}=o(void 0,{staleTime:1/0}),[n,r]=A(null);return h(`cluster.topology-snapshot`,e=>{let t=e.data?.nodes;Array.isArray(t)&&r(t)}),{nodes:O(()=>n??e??[],[n,e]),isLoading:t&&!n}}function Ae(){let{t:e}=G(),t=_(),[n,r]=A(`table`),[i,a]=A(void 0),[o,s]=A(0),c=Oe(`(max-width: 767px)`),l=c&&n===`graph`?`table`:n,{nodes:u,isLoading:d}=ke(),f=O(()=>q(u),[u]),p=O(()=>u.filter(e=>e.isOnline),[u]),h=p.length,g=u.filter(e=>!e.isOnline).length,v=m(),[y,b]=A(!1),x=w(async()=>{let n=[...p].sort((e,t)=>e.isHub===t.isHub?0:e.isHub?1:-1);if(await t({title:e(`serverManagement.confirmUpdateAllTitle`,`Update all nodes`),message:e(`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:e(`serverManagement.confirmUpdateAllAction`,`Update all & restart`),variant:`warning`})){b(!0);try{for(let e of n)try{await v.mutateAsync(e.isHub?{}:{nodeId:e.id})}catch{}}finally{b(!1)}}},[v,t,p,e]),S=w(e=>{r(`table`),a(e),s(e=>e+1)},[]),C=(e,t,i)=>D(`button`,{onClick:()=>r(e),className:`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-medium transition-colors ${n===e?`bg-primary text-primary-foreground`:`text-muted-foreground hover:text-foreground`}`,children:[j(i,{className:`h-3.5 w-3.5`}),t]});return D(`div`,{className:`flex flex-col h-full gap-4 p-4`,children:[D(`div`,{className:`flex items-center justify-between gap-2 flex-wrap`,children:[D(`div`,{className:`flex items-center gap-2`,children:[h>0&&D(`span`,{className:`text-xs px-2 py-0.5 rounded-full bg-success/10 text-success`,children:[h,` online`]}),g>0&&D(`span`,{className:`text-xs px-2 py-0.5 rounded-full bg-destructive/10 text-destructive`,children:[g,` offline`]})]}),D(`div`,{className:`flex items-center gap-2`,children:[h>1&&D(`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:y,title:e(`serverManagement.updateAllHint`,`Sequenced agents-first, hub-last — up-to-date nodes are skipped.`),onClick:()=>void x(),children:[y?j(V,{className:`h-3.5 w-3.5 animate-spin`}):j(Y,{className:`h-3.5 w-3.5`}),e(`serverManagement.updateAll`,`Update all nodes`)]}),D(`div`,{className:`flex gap-0.5 p-1 rounded-lg bg-muted`,children:[C(`table`,`Table`,ue),!c&&C(`graph`,`Graph`,se)]})]})]}),d?j(`div`,{className:`flex items-center justify-center flex-1 text-muted-foreground`,children:`Loading cluster topology...`}):l===`graph`?j(K,{graph:f,onOpenNodeDetail:S}):j(`div`,{className:`flex-1 overflow-auto`,children:j(De,{nodes:u,focusNodeId:i,focusNonce:o})})]})}export{Ae as ClusterPage};
|