@camstack/ui-library 1.2.259 → 1.2.261

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/index.cjs CHANGED
@@ -3885,6 +3885,19 @@ var Phone = createLucideIcon("phone", [["path", {
3885
3885
  * This source code is licensed under the ISC license.
3886
3886
  * See the LICENSE file in the root directory of this source tree.
3887
3887
  */
3888
+ var Pin = createLucideIcon("pin", [["path", {
3889
+ d: "M12 17v5",
3890
+ key: "bb1du9"
3891
+ }], ["path", {
3892
+ d: "M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z",
3893
+ key: "1nkz8b"
3894
+ }]]);
3895
+ /**
3896
+ * @license lucide-react v0.576.0 - ISC
3897
+ *
3898
+ * This source code is licensed under the ISC license.
3899
+ * See the LICENSE file in the root directory of this source tree.
3900
+ */
3888
3901
  var Pipette = createLucideIcon("pipette", [
3889
3902
  ["path", {
3890
3903
  d: "m12 9-8.414 8.414A2 2 0 0 0 3 18.828v1.344a2 2 0 0 1-.586 1.414A2 2 0 0 1 3.828 21h1.344a2 2 0 0 0 1.414-.586L15 12",
@@ -12366,6 +12379,10 @@ var usePipelineAnalyticsGetTrainingExportSummary = trpc.pipelineAnalytics.getTra
12366
12379
  var usePipelineAnalyticsGetTrainingExportUrl = trpc.pipelineAnalytics.getTrainingExportUrl.useQuery;
12367
12380
  /** Generated alias around `trpc.pipelineAnalytics.listRetrainStaging.useQuery`. */
12368
12381
  var usePipelineAnalyticsListRetrainStaging = trpc.pipelineAnalytics.listRetrainStaging.useQuery;
12382
+ /** Generated alias around `trpc.pipelineAnalytics.listRetrainCorpusPage.useQuery`. */
12383
+ var usePipelineAnalyticsListRetrainCorpusPage = trpc.pipelineAnalytics.listRetrainCorpusPage.useQuery;
12384
+ /** Generated alias around `trpc.pipelineAnalytics.getRetrainCorpusKpi.useQuery`. */
12385
+ var usePipelineAnalyticsGetRetrainCorpusKpi = trpc.pipelineAnalytics.getRetrainCorpusKpi.useQuery;
12369
12386
  /** Generated alias around `trpc.pipelineAnalytics.listRetrainFrames.useQuery`. */
12370
12387
  var usePipelineAnalyticsListRetrainFrames = trpc.pipelineAnalytics.listRetrainFrames.useQuery;
12371
12388
  /** Generated alias around `trpc.pipelineAnalytics.selectRetrainFrames.useMutation`. */
@@ -12392,16 +12409,6 @@ var usePipelineAnalyticsSetRetrainFrameComplete = trpc.pipelineAnalytics.setRetr
12392
12409
  var usePipelineAnalyticsWriteRetrainArchive = trpc.pipelineAnalytics.writeRetrainArchive.useMutation;
12393
12410
  /** Generated alias around `trpc.pipelineAnalytics.offerRetrainArchive.useMutation`. */
12394
12411
  var usePipelineAnalyticsOfferRetrainArchive = trpc.pipelineAnalytics.offerRetrainArchive.useMutation;
12395
- /** Generated alias around `trpc.pipelineAnalytics.previewRetrainDataset.useQuery`. */
12396
- var usePipelineAnalyticsPreviewRetrainDataset = trpc.pipelineAnalytics.previewRetrainDataset.useQuery;
12397
- /** Generated alias around `trpc.pipelineAnalytics.createRetrainDatasetVersion.useMutation`. */
12398
- var usePipelineAnalyticsCreateRetrainDatasetVersion = trpc.pipelineAnalytics.createRetrainDatasetVersion.useMutation;
12399
- /** Generated alias around `trpc.pipelineAnalytics.listRetrainDatasetVersions.useQuery`. */
12400
- var usePipelineAnalyticsListRetrainDatasetVersions = trpc.pipelineAnalytics.listRetrainDatasetVersions.useQuery;
12401
- /** Generated alias around `trpc.pipelineAnalytics.deleteRetrainDatasetVersion.useMutation`. */
12402
- var usePipelineAnalyticsDeleteRetrainDatasetVersion = trpc.pipelineAnalytics.deleteRetrainDatasetVersion.useMutation;
12403
- /** Generated alias around `trpc.pipelineAnalytics.verifyRetrainDatasetVersion.useQuery`. */
12404
- var usePipelineAnalyticsVerifyRetrainDatasetVersion = trpc.pipelineAnalytics.verifyRetrainDatasetVersion.useQuery;
12405
12412
  /** Generated alias around `trpc.pipelineAnalytics.listRetrainAssistProfiles.useQuery`. */
12406
12413
  var usePipelineAnalyticsListRetrainAssistProfiles = trpc.pipelineAnalytics.listRetrainAssistProfiles.useQuery;
12407
12414
  /** Generated alias around `trpc.pipelineAnalytics.proposeRetrainAnnotationsWithLlm.useMutation`. */
@@ -12410,6 +12417,8 @@ var usePipelineAnalyticsProposeRetrainAnnotationsWithLlm = trpc.pipelineAnalytic
12410
12417
  var usePipelineAnalyticsCreateRetrainCollection = trpc.pipelineAnalytics.createRetrainCollection.useMutation;
12411
12418
  /** Generated alias around `trpc.pipelineAnalytics.listRetrainCollections.useQuery`. */
12412
12419
  var usePipelineAnalyticsListRetrainCollections = trpc.pipelineAnalytics.listRetrainCollections.useQuery;
12420
+ /** Generated alias around `trpc.pipelineAnalytics.resolveRetrainTrainingCorpus.useQuery`. */
12421
+ var usePipelineAnalyticsResolveRetrainTrainingCorpus = trpc.pipelineAnalytics.resolveRetrainTrainingCorpus.useQuery;
12413
12422
  /** Generated alias around `trpc.pipelineAnalytics.renameRetrainCollection.useMutation`. */
12414
12423
  var usePipelineAnalyticsRenameRetrainCollection = trpc.pipelineAnalytics.renameRetrainCollection.useMutation;
12415
12424
  /** Generated alias around `trpc.pipelineAnalytics.deleteRetrainCollection.useMutation`. */
@@ -13176,22 +13185,14 @@ var useTerminalSessionWriteInput = trpc.terminalSession.writeInput.useMutation;
13176
13185
  var useTerminalSessionClose = trpc.terminalSession.close.useMutation;
13177
13186
  /** Generated alias around `trpc.toast.onToast.useSubscription`. */
13178
13187
  var useToastOnToast = trpc.toast.onToast.useSubscription;
13179
- /** Generated alias around `trpc.training.putDatasetVersion.useMutation`. */
13180
- var useTrainingPutDatasetVersion = trpc.training.putDatasetVersion.useMutation;
13181
- /** Generated alias around `trpc.training.getDatasetVersion.useQuery`. */
13182
- var useTrainingGetDatasetVersion = trpc.training.getDatasetVersion.useQuery;
13183
- /** Generated alias around `trpc.training.listDatasetVersions.useQuery`. */
13184
- var useTrainingListDatasetVersions = trpc.training.listDatasetVersions.useQuery;
13185
- /** Generated alias around `trpc.training.findDatasetVersionIdByName.useQuery`. */
13186
- var useTrainingFindDatasetVersionIdByName = trpc.training.findDatasetVersionIdByName.useQuery;
13187
- /** Generated alias around `trpc.training.removeDatasetVersion.useMutation`. */
13188
- var useTrainingRemoveDatasetVersion = trpc.training.removeDatasetVersion.useMutation;
13189
13188
  /** Generated alias around `trpc.training.listBaseModels.useQuery`. */
13190
13189
  var useTrainingListBaseModels = trpc.training.listBaseModels.useQuery;
13191
13190
  /** Generated alias around `trpc.training.planJob.useQuery`. */
13192
13191
  var useTrainingPlanJob = trpc.training.planJob.useQuery;
13193
13192
  /** Generated alias around `trpc.training.startJob.useMutation`. */
13194
13193
  var useTrainingStartJob = trpc.training.startJob.useMutation;
13194
+ /** Generated alias around `trpc.training.startJobBatch.useMutation`. */
13195
+ var useTrainingStartJobBatch = trpc.training.startJobBatch.useMutation;
13195
13196
  /** Generated alias around `trpc.training.listJobs.useQuery`. */
13196
13197
  var useTrainingListJobs = trpc.training.listJobs.useQuery;
13197
13198
  /** Generated alias around `trpc.training.getJob.useQuery`. */
@@ -25747,7 +25748,7 @@ function DialogTrigger({ children, ...props }) {
25747
25748
  * whenever they are asymmetric (they are: ~59px top vs ~34px bottom). Every
25748
25749
  * term collapses to the previous `100dvh - 2rem` where the insets are 0.
25749
25750
  */
25750
- var contentVariants = cva("fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 m-0 w-[calc(100vw-2rem)] bg-background-elevated text-foreground border border-border rounded-lg p-4 backdrop:bg-black/50 backdrop:backdrop-blur-sm max-h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))] [&:not([open])]:hidden", {
25751
+ var contentVariants = cva("relative fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 m-0 w-[calc(100vw-2rem)] bg-background-elevated text-foreground border border-border rounded-lg p-4 backdrop:bg-black/50 backdrop:backdrop-blur-sm max-h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))] [&:not([open])]:hidden", {
25751
25752
  variants: {
25752
25753
  width: {
25753
25754
  sm: "max-w-sm",
@@ -25826,7 +25827,7 @@ var DialogContent = (0, react$1.forwardRef)(({ className, width, placement, scro
25826
25827
  if (open && !el.open) el.showModal();
25827
25828
  if (!open && el.open) el.close();
25828
25829
  }, [open, dialogRef]);
25829
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dialog", {
25830
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dialog", {
25830
25831
  ref: dialogRef,
25831
25832
  id: contentId,
25832
25833
  className: cn(contentVariants({
@@ -25836,7 +25837,15 @@ var DialogContent = (0, react$1.forwardRef)(({ className, width, placement, scro
25836
25837
  }), className),
25837
25838
  onClose: () => setOpen(false),
25838
25839
  ...props,
25839
- children
25840
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconButton, {
25841
+ type: "button",
25842
+ variant: "ghost",
25843
+ size: "sm",
25844
+ icon: X,
25845
+ "aria-label": "Close",
25846
+ className: "absolute right-4 top-4 z-10 shrink-0",
25847
+ onClick: () => setOpen(false)
25848
+ }), children]
25840
25849
  });
25841
25850
  });
25842
25851
  DialogContent.displayName = "DialogContent";
@@ -25845,7 +25854,7 @@ DialogContent.displayName = "DialogContent";
25845
25854
  * ground, or a long form squeezes its own title to nothing. */
25846
25855
  function DialogHeader({ className, ...props }) {
25847
25856
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
25848
- className: cn("flex flex-col gap-1 mb-3 shrink-0", className),
25857
+ className: cn("flex flex-col gap-1 mb-3 shrink-0 pr-10", className),
25849
25858
  ...props
25850
25859
  });
25851
25860
  }
@@ -29232,6 +29241,13 @@ function EditableArrayField({ field, value, onChange, disabled, translationFn, o
29232
29241
  };
29233
29242
  const canRemove = rows.length > minRows;
29234
29243
  const canAdd = rows.length < maxRows;
29244
+ const idKey = field.itemIdKey ?? "id";
29245
+ const rowReactKey = (row, idx) => {
29246
+ const raw = row[idKey];
29247
+ if (typeof raw === "string" && raw.length > 0) return raw;
29248
+ if (typeof raw === "number" && Number.isFinite(raw)) return String(raw);
29249
+ return `row-${String(idx)}`;
29250
+ };
29235
29251
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
29236
29252
  className: "col-span-full space-y-2",
29237
29253
  children: [
@@ -29278,7 +29294,7 @@ function EditableArrayField({ field, value, onChange, disabled, translationFn, o
29278
29294
  onAction
29279
29295
  }, sub.key))
29280
29296
  })]
29281
- }, idx))
29297
+ }, rowReactKey(row, idx)))
29282
29298
  }),
29283
29299
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
29284
29300
  type: "button",
@@ -30157,23 +30173,44 @@ var Chevron$1 = ({ open }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg",
30157
30173
  "aria-hidden": true,
30158
30174
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("polyline", { points: "9 18 15 12 9 6" })
30159
30175
  });
30176
+ function isValueBearingField(f) {
30177
+ return f.type !== "separator" && f.type !== "info" && f.type !== "button" && f.type !== "group";
30178
+ }
30160
30179
  function extractValues(schema) {
30161
30180
  const out = {};
30162
30181
  if (!schema) return out;
30163
30182
  for (const s of schema.sections) for (const f of s.fields) {
30164
- if (f.type === "separator" || f.type === "info" || f.type === "button" || f.type === "group") continue;
30183
+ if (!isValueBearingField(f)) continue;
30165
30184
  const key = f.key;
30166
30185
  out[key] = f.value;
30167
30186
  }
30168
30187
  return out;
30169
30188
  }
30189
+ /** Paint operator edits into the hydrated schema so controlled inputs keep focus. */
30190
+ function applyValuesToSchema(schema, nextValues) {
30191
+ return {
30192
+ ...schema,
30193
+ sections: schema.sections.map((s) => ({
30194
+ ...s,
30195
+ fields: s.fields.map((f) => {
30196
+ if (!isValueBearingField(f)) return f;
30197
+ const key = f.key;
30198
+ if (!(key in nextValues)) return f;
30199
+ return {
30200
+ ...f,
30201
+ value: nextValues[key]
30202
+ };
30203
+ })
30204
+ }))
30205
+ };
30206
+ }
30170
30207
  function stripValues(schema) {
30171
30208
  return {
30172
30209
  ...schema,
30173
30210
  sections: schema.sections.map((s) => ({
30174
30211
  ...s,
30175
30212
  fields: s.fields.map((f) => {
30176
- if (f.type === "separator" || f.type === "info" || f.type === "button" || f.type === "group") return f;
30213
+ if (!isValueBearingField(f)) return f;
30177
30214
  const { value: _drop, ...rest } = f;
30178
30215
  return rest;
30179
30216
  })
@@ -30189,6 +30226,8 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
30189
30226
  const [open, setOpen] = (0, react$1.useState)(defaultOpen ?? false);
30190
30227
  const [overrideValues, setOverrideValues] = (0, react$1.useState)({});
30191
30228
  const [baseValues, setBaseValues] = (0, react$1.useState)(null);
30229
+ /** Bumps on every persist edit; a stale refetch must not clobber a newer local paint. */
30230
+ const persistSeq = (0, react$1.useRef)(0);
30192
30231
  (0, react$1.useEffect)(() => {
30193
30232
  setBaseValues(null);
30194
30233
  setOverrideValues({});
@@ -30257,7 +30296,10 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
30257
30296
  const patch = {};
30258
30297
  for (const k of Object.keys(nextValues)) if (nextValues[k] !== values[k]) patch[k] = nextValues[k];
30259
30298
  if (Object.keys(patch).length === 0) return;
30299
+ const seq = ++persistSeq.current;
30300
+ setHydrated((prev) => prev === null ? prev : applyValuesToSchema(prev, nextValues));
30260
30301
  setSaving(true);
30302
+ setError(null);
30261
30303
  try {
30262
30304
  await trpc.addonSettings.updateGlobalSettings.mutate({
30263
30305
  addonId,
@@ -30268,12 +30310,12 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
30268
30310
  addonId,
30269
30311
  nodeId
30270
30312
  });
30271
- if (next) setHydrated(next);
30272
- onAfterChange?.();
30313
+ if (next && seq === persistSeq.current) setHydrated(next);
30314
+ if (seq === persistSeq.current) onAfterChange?.();
30273
30315
  } catch (err) {
30274
- setError(err instanceof Error ? err.message : String(err));
30316
+ if (seq === persistSeq.current) setError(err instanceof Error ? err.message : String(err));
30275
30317
  } finally {
30276
- setSaving(false);
30318
+ if (seq === persistSeq.current) setSaving(false);
30277
30319
  }
30278
30320
  };
30279
30321
  if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -30305,15 +30347,23 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
30305
30347
  ...values,
30306
30348
  ...overrideValues
30307
30349
  } : values;
30308
- const body = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [effectiveMode === "override" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
30309
- className: "mb-2 text-[11px] text-foreground-subtle",
30310
- children: "Benchmark override — applies to this run only. The addon's saved settings are not changed."
30311
- }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigFormBuilder, {
30312
- schema: schemaNoValues,
30313
- values: effectiveValues,
30314
- onChange: handleChange,
30315
- disabled: disabled === true || saving
30316
- })] });
30350
+ const body = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
30351
+ effectiveMode === "override" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
30352
+ className: "mb-2 text-[11px] text-foreground-subtle",
30353
+ children: "Benchmark override — applies to this run only. The addon's saved settings are not changed."
30354
+ }) : null,
30355
+ saving ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
30356
+ className: "mb-2 text-[11px] text-foreground-subtle",
30357
+ "aria-live": "polite",
30358
+ children: "Saving…"
30359
+ }) : null,
30360
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigFormBuilder, {
30361
+ schema: schemaNoValues,
30362
+ values: effectiveValues,
30363
+ onChange: handleChange,
30364
+ disabled: disabled === true
30365
+ })
30366
+ ] });
30317
30367
  if (collapsible === true) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
30318
30368
  className: "rounded-lg border border-border bg-surface overflow-hidden",
30319
30369
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
@@ -31824,6 +31874,7 @@ function Popover({ children, open: controlledOpen, onOpenChange }) {
31824
31874
  const open = controlledOpen ?? uncontrolledOpen;
31825
31875
  const triggerId = (0, react$1.useId)();
31826
31876
  const contentId = (0, react$1.useId)();
31877
+ const triggerRef = (0, react$1.useRef)(null);
31827
31878
  const setOpen = (0, react$1.useCallback)((next) => {
31828
31879
  onOpenChange?.(next);
31829
31880
  if (controlledOpen === void 0) setUncontrolledOpen(next);
@@ -31833,7 +31884,8 @@ function Popover({ children, open: controlledOpen, onOpenChange }) {
31833
31884
  open,
31834
31885
  setOpen,
31835
31886
  triggerId,
31836
- contentId
31887
+ contentId,
31888
+ triggerRef
31837
31889
  },
31838
31890
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
31839
31891
  className: "relative inline-block",
@@ -31842,9 +31894,10 @@ function Popover({ children, open: controlledOpen, onOpenChange }) {
31842
31894
  });
31843
31895
  }
31844
31896
  function PopoverTrigger({ children, ...props }) {
31845
- const { open, setOpen, triggerId, contentId } = usePopoverContext();
31897
+ const { open, setOpen, triggerId, contentId, triggerRef } = usePopoverContext();
31846
31898
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
31847
31899
  type: "button",
31900
+ ref: triggerRef,
31848
31901
  id: triggerId,
31849
31902
  "aria-haspopup": "dialog",
31850
31903
  "aria-expanded": open,
@@ -31854,15 +31907,46 @@ function PopoverTrigger({ children, ...props }) {
31854
31907
  children
31855
31908
  });
31856
31909
  }
31857
- function PopoverContent({ className, children, ...props }) {
31858
- const { open, setOpen, contentId, triggerId } = usePopoverContext();
31910
+ function PopoverContent({ className, children, align = "start", offset = 4, ...props }) {
31911
+ const { open, setOpen, contentId, triggerId, triggerRef } = usePopoverContext();
31859
31912
  const isMobile = useIsMobile();
31860
31913
  const ref = (0, react$1.useRef)(null);
31914
+ const [coords, setCoords] = (0, react$1.useState)(null);
31915
+ (0, react$1.useLayoutEffect)(() => {
31916
+ if (!open || isMobile) {
31917
+ setCoords(null);
31918
+ return;
31919
+ }
31920
+ const compute = () => {
31921
+ const trigger = triggerRef.current;
31922
+ if (!trigger) return;
31923
+ const rect = trigger.getBoundingClientRect();
31924
+ const left = align === "end" ? rect.right : rect.left;
31925
+ setCoords({
31926
+ top: rect.bottom + offset,
31927
+ left,
31928
+ minWidth: rect.width
31929
+ });
31930
+ };
31931
+ compute();
31932
+ window.addEventListener("resize", compute);
31933
+ window.addEventListener("scroll", compute, true);
31934
+ return () => {
31935
+ window.removeEventListener("resize", compute);
31936
+ window.removeEventListener("scroll", compute, true);
31937
+ };
31938
+ }, [
31939
+ open,
31940
+ isMobile,
31941
+ align,
31942
+ offset,
31943
+ triggerRef
31944
+ ]);
31861
31945
  (0, react$1.useEffect)(() => {
31862
31946
  if (!open || isMobile) return;
31863
31947
  const handler = (e) => {
31864
31948
  const el = ref.current;
31865
- const trigger = document.getElementById(triggerId);
31949
+ const trigger = triggerRef.current;
31866
31950
  if (el && !el.contains(e.target) && !trigger?.contains(e.target)) setOpen(false);
31867
31951
  };
31868
31952
  const escHandler = (e) => {
@@ -31877,7 +31961,7 @@ function PopoverContent({ className, children, ...props }) {
31877
31961
  }, [
31878
31962
  open,
31879
31963
  setOpen,
31880
- triggerId,
31964
+ triggerRef,
31881
31965
  isMobile
31882
31966
  ]);
31883
31967
  if (!open) return null;
@@ -31886,15 +31970,22 @@ function PopoverContent({ className, children, ...props }) {
31886
31970
  onClose: () => setOpen(false),
31887
31971
  children
31888
31972
  });
31889
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
31973
+ if (!coords || typeof document === "undefined") return null;
31974
+ return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
31890
31975
  ref,
31891
31976
  id: contentId,
31892
31977
  role: "dialog",
31893
31978
  "aria-labelledby": triggerId,
31894
- className: cn("absolute left-0 top-full z-50 mt-1 bg-background-elevated border border-border rounded-lg shadow-lg p-3", className),
31979
+ style: {
31980
+ position: "fixed",
31981
+ top: coords.top,
31982
+ ...align === "end" ? { right: window.innerWidth - coords.left } : { left: coords.left },
31983
+ minWidth: coords.minWidth
31984
+ },
31985
+ className: cn("z-50 bg-background-elevated border border-border rounded-lg shadow-lg p-3", className),
31895
31986
  ...props,
31896
31987
  children
31897
- });
31988
+ }), document.body);
31898
31989
  }
31899
31990
  //#endregion
31900
31991
  //#region src/primitives/tabs.tsx
@@ -32702,6 +32793,90 @@ function NetworkLinkBadge({ status, className }) {
32702
32793
  });
32703
32794
  }
32704
32795
  //#endregion
32796
+ //#region src/composites/node-color.ts
32797
+ /** Full class strings so Tailwind v4 JIT retains every node palette utility. */
32798
+ var NODE_BG_CLASS = {
32799
+ "node-a": "bg-node-a",
32800
+ "node-b": "bg-node-b",
32801
+ "node-c": "bg-node-c",
32802
+ "node-d": "bg-node-d",
32803
+ "node-e": "bg-node-e",
32804
+ "node-f": "bg-node-f",
32805
+ "node-g": "bg-node-g",
32806
+ "node-h": "bg-node-h"
32807
+ };
32808
+ var NODE_TEXT_CLASS = {
32809
+ "node-a": "text-node-a",
32810
+ "node-b": "text-node-b",
32811
+ "node-c": "text-node-c",
32812
+ "node-d": "text-node-d",
32813
+ "node-e": "text-node-e",
32814
+ "node-f": "text-node-f",
32815
+ "node-g": "text-node-g",
32816
+ "node-h": "text-node-h"
32817
+ };
32818
+ function nodeColorClass(id) {
32819
+ return NODE_BG_CLASS[id];
32820
+ }
32821
+ function nodeTextColorClass(id) {
32822
+ return NODE_TEXT_CLASS[id];
32823
+ }
32824
+ //#endregion
32825
+ //#region src/composites/role-node-pill.tsx
32826
+ /** Full class strings so Tailwind v4 JIT retains node palette opacity utilities. */
32827
+ var NODE_BG_SOFT_CLASS = {
32828
+ "node-a": "bg-node-a/12",
32829
+ "node-b": "bg-node-b/12",
32830
+ "node-c": "bg-node-c/12",
32831
+ "node-d": "bg-node-d/12",
32832
+ "node-e": "bg-node-e/12",
32833
+ "node-f": "bg-node-f/12",
32834
+ "node-g": "bg-node-g/12",
32835
+ "node-h": "bg-node-h/12"
32836
+ };
32837
+ var NODE_BG_EMPHASIZED_CLASS = {
32838
+ "node-a": "bg-node-a/22",
32839
+ "node-b": "bg-node-b/22",
32840
+ "node-c": "bg-node-c/22",
32841
+ "node-d": "bg-node-d/22",
32842
+ "node-e": "bg-node-e/22",
32843
+ "node-f": "bg-node-f/22",
32844
+ "node-g": "bg-node-g/22",
32845
+ "node-h": "bg-node-h/22"
32846
+ };
32847
+ var NODE_RING_CLASS = {
32848
+ "node-a": "ring-node-a/45",
32849
+ "node-b": "ring-node-b/45",
32850
+ "node-c": "ring-node-c/45",
32851
+ "node-d": "ring-node-d/45",
32852
+ "node-e": "ring-node-e/45",
32853
+ "node-f": "ring-node-f/45",
32854
+ "node-g": "ring-node-g/45",
32855
+ "node-h": "ring-node-h/45"
32856
+ };
32857
+ function RoleNodePill({ roleLabel, nodeName, colorId, emphasized = false, pinned = false }) {
32858
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
32859
+ "data-testid": "role-node-pill",
32860
+ title: pinned ? `${roleLabel} pinned on ${nodeName}` : `${roleLabel} on ${nodeName}`,
32861
+ className: cn("inline-flex max-w-full items-center gap-1 rounded-full px-2 py-0.5 text-[10px] leading-tight ring-1 ring-inset", emphasized ? cn("role-node-pill-emphasized font-semibold ring-2", NODE_BG_EMPHASIZED_CLASS[colorId], NODE_RING_CLASS[colorId], nodeTextColorClass(colorId)) : cn("font-medium text-foreground-muted ring-border/60", NODE_BG_SOFT_CLASS[colorId])),
32862
+ children: [
32863
+ pinned && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pin, {
32864
+ className: "h-2.5 w-2.5 shrink-0 opacity-80",
32865
+ "aria-label": "pinned"
32866
+ }),
32867
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
32868
+ className: "shrink-0",
32869
+ children: roleLabel
32870
+ }),
32871
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
32872
+ className: cn("min-w-0 truncate", emphasized ? nodeTextColorClass(colorId) : "text-foreground-subtle"),
32873
+ children: nodeName
32874
+ }),
32875
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: cn("h-1.5 w-1.5 shrink-0 rounded-full", nodeColorClass(colorId)) })
32876
+ ]
32877
+ });
32878
+ }
32879
+ //#endregion
32705
32880
  //#region src/composites/breadcrumb.tsx
32706
32881
  /**
32707
32882
  * Breadcrumb navigation component.
@@ -37639,6 +37814,141 @@ function HubSessionTestCard({ trpc, serverUrl, deviceId, cameraField, runMs = HU
37639
37814
  });
37640
37815
  }
37641
37816
  //#endregion
37817
+ //#region src/composites/training/root-detector-placements.ts
37818
+ /**
37819
+ * Pure mapper: per-node inference devices → placements of each effective root
37820
+ * detector model. Training's base-model picker lists every `node · device`
37821
+ * where a trainable base is the cluster's object-detection root.
37822
+ *
37823
+ * Mirrors Model Studio's `acceleratorsRunningModel` decision (effective model
37824
+ * via {@link resolveEffectiveStepModel}) but aggregates across nodes and does
37825
+ * not gate on on-disk currency — "in use" here means the root the node would
37826
+ * run. ui-library must not import addon-model-studio; a sync guard can later
37827
+ * hold the two pure paths equal.
37828
+ */
37829
+ /** Root detection step — the only step whose models are trainable bases. */
37830
+ var ROOT_DETECTOR_STEP_ID = "object-detection";
37831
+ function comparePlacement(a, b) {
37832
+ const byNode = a.nodeId.localeCompare(b.nodeId);
37833
+ if (byNode !== 0) return byNode;
37834
+ const byLabel = a.label.localeCompare(b.label);
37835
+ if (byLabel !== 0) return byLabel;
37836
+ return a.deviceKey.localeCompare(b.deviceKey);
37837
+ }
37838
+ /**
37839
+ * For each modelId that is the effective root on at least one enabled device,
37840
+ * the full list of placements (sorted by node, then device label).
37841
+ */
37842
+ function mapRootDetectorPlacements(nodes, stepId = ROOT_DETECTOR_STEP_ID) {
37843
+ const buckets = /* @__PURE__ */ new Map();
37844
+ for (const node of nodes) for (const device of node.devices) {
37845
+ if (!device.enabled) continue;
37846
+ if (!stepHasModelForFormat(node.catalog.models, device.format)) continue;
37847
+ const effective = resolveEffectiveStepModel({
37848
+ catalog: node.catalog,
37849
+ device,
37850
+ base: device.steps?.[stepId]?.modelId
37851
+ });
37852
+ if (effective === void 0) continue;
37853
+ const list = buckets.get(effective) ?? [];
37854
+ list.push({
37855
+ nodeId: node.nodeId,
37856
+ deviceKey: device.key,
37857
+ label: acceleratorShortLabel(device)
37858
+ });
37859
+ buckets.set(effective, list);
37860
+ }
37861
+ const out = /* @__PURE__ */ new Map();
37862
+ for (const [modelId, list] of buckets) out.set(modelId, [...list].toSorted(comparePlacement));
37863
+ return out;
37864
+ }
37865
+ /** Model ids that appear as an effective root somewhere in the cluster. */
37866
+ function clusterRootModelIds(placements) {
37867
+ return [...placements.keys()].toSorted((a, b) => a.localeCompare(b));
37868
+ }
37869
+ /**
37870
+ * Intersection of listed trainable models and cluster root detectors — the
37871
+ * Select-all-roots action. Order follows `trainableModelIds`.
37872
+ */
37873
+ function defaultSelectClusterRoots(trainableModelIds, clusterRootIds) {
37874
+ const roots = new Set(clusterRootIds);
37875
+ return trainableModelIds.filter((id) => roots.has(id));
37876
+ }
37877
+ //#endregion
37878
+ //#region src/composites/training/TrainingBaseModelPicker.tsx
37879
+ var EMPTY_PLACEMENTS = "Not in use on any node";
37880
+ function placementLine(placement) {
37881
+ return `${placement.nodeId} · ${placement.label}`;
37882
+ }
37883
+ function toggleModel(selected, modelId, checked) {
37884
+ if (checked) {
37885
+ if (selected.includes(modelId)) return selected;
37886
+ return [...selected, modelId];
37887
+ }
37888
+ return selected.filter((id) => id !== modelId);
37889
+ }
37890
+ /**
37891
+ * Multi-select of trainable base models with full multi-placement listing and
37892
+ * Select-all-roots / Clear over cluster root detectors.
37893
+ */
37894
+ function TrainingBaseModelPicker({ models, clusterRootModelIds, value, onChange, disabled = false }) {
37895
+ const selected = new Set(value);
37896
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
37897
+ className: "space-y-2",
37898
+ "data-testid": "training-base-model-picker",
37899
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
37900
+ className: "flex flex-wrap items-center gap-1.5",
37901
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
37902
+ type: "button",
37903
+ variant: "secondary",
37904
+ size: "sm",
37905
+ disabled,
37906
+ onClick: () => onChange(defaultSelectClusterRoots(models.map((m) => m.modelId), clusterRootModelIds)),
37907
+ children: "Select all roots"
37908
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
37909
+ type: "button",
37910
+ variant: "ghost",
37911
+ size: "sm",
37912
+ disabled: disabled || value.length === 0,
37913
+ onClick: () => onChange([]),
37914
+ children: "Clear"
37915
+ })]
37916
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
37917
+ className: "divide-y divide-border-subtle rounded-md border border-border bg-surface",
37918
+ children: models.map((model) => {
37919
+ const checked = selected.has(model.modelId);
37920
+ const label = model.recommended ? `${model.label} (recommended)` : model.label;
37921
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
37922
+ className: "px-2 py-2 sm:px-3",
37923
+ "data-testid": `training-base-model-${model.modelId}`,
37924
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
37925
+ className: "flex min-w-0 cursor-pointer items-start gap-2",
37926
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Checkbox, {
37927
+ className: "mt-0.5",
37928
+ checked,
37929
+ disabled,
37930
+ "aria-label": model.label,
37931
+ onChange: (event) => onChange(toggleModel(value, model.modelId, event.target.checked))
37932
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
37933
+ className: "min-w-0 flex-1 space-y-1",
37934
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
37935
+ className: "block text-sm text-foreground",
37936
+ children: label
37937
+ }), model.placements.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
37938
+ className: cn(TEXT_HINT, "block"),
37939
+ children: EMPTY_PLACEMENTS
37940
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
37941
+ className: cn(TEXT_HINT, "flex flex-wrap gap-x-2 gap-y-0.5"),
37942
+ children: model.placements.map((p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: placementLine(p) }, `${p.nodeId}:${p.deviceKey}`))
37943
+ })]
37944
+ })]
37945
+ })
37946
+ }, model.modelId);
37947
+ })
37948
+ })]
37949
+ });
37950
+ }
37951
+ //#endregion
37642
37952
  //#region src/composites/cap-settings/scene-monitor-copy.ts
37643
37953
  /** The lighting variants an operator is OFFERED. The resolver can also report
37644
37954
  * `night`, `dawn` and `dusk`; those are shown when present but never demanded,
@@ -57627,7 +57937,8 @@ function KebabMenu({ items, header, triggerClassName, title = "More actions" })
57627
57937
  className: cn("inline-flex items-center justify-center rounded-lg p-2", "text-foreground-subtle hover:text-foreground hover:bg-surface-hover", "border border-transparent transition-colors", triggerClassName),
57628
57938
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EllipsisVertical, { className: "h-4 w-4" })
57629
57939
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(PopoverContent, {
57630
- className: "left-auto right-0 mt-1 min-w-[200px] p-1",
57940
+ align: "end",
57941
+ className: "min-w-[200px] p-1",
57631
57942
  children: [header && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
57632
57943
  className: "px-2 py-1 text-[10px] uppercase tracking-wider text-foreground-subtle",
57633
57944
  children: header
@@ -58116,6 +58427,208 @@ function ProviderBadge({ provider, showLabel = true, className }) {
58116
58427
  });
58117
58428
  }
58118
58429
  //#endregion
58430
+ //#region src/composites/provider-entries/AddProviderEntryDialog.tsx
58431
+ /**
58432
+ * AddProviderEntryDialog — create one credential entry for a provider type.
58433
+ *
58434
+ * The host supplies the creatable types (`describeTypes`); the dialog never
58435
+ * invents them. Submit hands `{ typeId, name }` to `onCreate` — credentials
58436
+ * and settings live on the entry body after create (Task 11).
58437
+ */
58438
+ function AddProviderEntryDialog({ open, onOpenChange, types, onCreate, submitting = false, title = "Add provider entry", description = "Pick a provider type and name this credential set." }) {
58439
+ const typeFieldId = (0, react$1.useId)();
58440
+ const nameFieldId = (0, react$1.useId)();
58441
+ const [typeId, setTypeId] = (0, react$1.useState)("");
58442
+ const [name, setName] = (0, react$1.useState)("");
58443
+ (0, react$1.useEffect)(() => {
58444
+ if (!open) return;
58445
+ setTypeId(types[0]?.typeId ?? "");
58446
+ setName("");
58447
+ }, [open, types]);
58448
+ const canSubmit = typeId !== "" && name.trim().length > 0 && !submitting && types.length > 0;
58449
+ const handleSubmit = () => {
58450
+ if (!canSubmit) return;
58451
+ onCreate({
58452
+ typeId,
58453
+ name: name.trim()
58454
+ });
58455
+ };
58456
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dialog, {
58457
+ open,
58458
+ onOpenChange: (next) => !submitting && onOpenChange(next),
58459
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DialogContent, {
58460
+ width: "sm",
58461
+ placement: "sheet-on-mobile",
58462
+ scroll: "body",
58463
+ children: [
58464
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DialogHeader, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogTitle, { children: title }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogDescription, { children: description })] }),
58465
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogBody, {
58466
+ className: "space-y-3",
58467
+ children: types.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
58468
+ className: "text-xs text-foreground-subtle",
58469
+ children: "No provider types are available yet. Install a training provider addon first."
58470
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
58471
+ className: "space-y-1",
58472
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label, {
58473
+ htmlFor: typeFieldId,
58474
+ children: "Provider type"
58475
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
58476
+ className: "flex items-center gap-2",
58477
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TypeIcon, { url: types.find((t) => t.typeId === typeId)?.iconUrl ?? null }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Select, {
58478
+ id: typeFieldId,
58479
+ "aria-label": "Provider type",
58480
+ className: "flex-1",
58481
+ value: typeId,
58482
+ onChange: (event) => setTypeId(event.target.value),
58483
+ options: types.map((t) => ({
58484
+ value: t.typeId,
58485
+ label: t.label
58486
+ })),
58487
+ disabled: submitting
58488
+ })]
58489
+ })]
58490
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
58491
+ className: "space-y-1",
58492
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label, {
58493
+ htmlFor: nameFieldId,
58494
+ children: "Name"
58495
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Input, {
58496
+ id: nameFieldId,
58497
+ "aria-label": "Name",
58498
+ value: name,
58499
+ onChange: (event) => setName(event.target.value),
58500
+ placeholder: "Production",
58501
+ disabled: submitting,
58502
+ onKeyDown: (event) => {
58503
+ if (event.key === "Enter") {
58504
+ event.preventDefault();
58505
+ handleSubmit();
58506
+ }
58507
+ }
58508
+ })]
58509
+ })] })
58510
+ }),
58511
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DialogFooter, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
58512
+ type: "button",
58513
+ variant: "ghost",
58514
+ size: "sm",
58515
+ disabled: submitting,
58516
+ onClick: () => onOpenChange(false),
58517
+ children: "Cancel"
58518
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
58519
+ type: "button",
58520
+ size: "sm",
58521
+ disabled: !canSubmit,
58522
+ onClick: handleSubmit,
58523
+ children: [submitting && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoaderCircle, {
58524
+ className: "h-3.5 w-3.5 animate-spin",
58525
+ "aria-hidden": true
58526
+ }), "Create"]
58527
+ })] })
58528
+ ]
58529
+ })
58530
+ });
58531
+ }
58532
+ function TypeIcon({ url }) {
58533
+ if (url === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
58534
+ className: cn("inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md", "border border-border bg-surface text-[10px] text-foreground-subtle"),
58535
+ "aria-hidden": true,
58536
+ children: "?"
58537
+ });
58538
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
58539
+ src: url,
58540
+ alt: "",
58541
+ className: "h-7 w-7 shrink-0 rounded-md border border-border bg-surface object-contain p-0.5"
58542
+ });
58543
+ }
58544
+ //#endregion
58545
+ //#region src/composites/provider-entries/ProviderEntryPills.tsx
58546
+ /**
58547
+ * ProviderEntryPills — one pill per credential entry (never a bare type).
58548
+ *
58549
+ * Visual language echoes the admin IntegrationHub strip: icon + name + status
58550
+ * dot, wrapping at every width. Selection is a button callback — the host
58551
+ * owns the URL (`?entry=`). Add is optional; when present it is a dashed
58552
+ * trailing control that opens the host's create dialog.
58553
+ */
58554
+ var PILL_BASE = cn(CHIP_BASE, "min-w-0 max-w-full gap-1.5 py-1 pl-1 pr-2.5 text-xs font-normal", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40");
58555
+ var PILL_CURRENT = cn(CHIP_ACTIVE, "font-medium");
58556
+ var PILL_OTHER = CHIP_INACTIVE;
58557
+ var STATE_DOT = {
58558
+ ok: "bg-success",
58559
+ warning: "bg-warning",
58560
+ error: "bg-danger",
58561
+ unknown: "border border-foreground-subtle bg-transparent"
58562
+ };
58563
+ var STATE_LABEL = {
58564
+ ok: "OK",
58565
+ warning: "Warning",
58566
+ error: "Error",
58567
+ unknown: "Unknown"
58568
+ };
58569
+ function ProviderEntryPills({ label, entries, selectedEntryId, onSelect, onAdd, addLabel = "Add provider" }) {
58570
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("nav", {
58571
+ "aria-label": label,
58572
+ className: "min-w-0",
58573
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
58574
+ className: "flex min-w-0 flex-wrap items-center gap-1.5",
58575
+ children: [entries.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryPill, {
58576
+ entry,
58577
+ current: entry.entryId === selectedEntryId,
58578
+ onSelect
58579
+ }, entry.entryId)), onAdd !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
58580
+ type: "button",
58581
+ onClick: onAdd,
58582
+ className: cn(PILL_BASE, "border-dashed border-border pl-2 text-foreground-subtle", "hover:border-primary/50 hover:text-foreground"),
58583
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Plus, {
58584
+ className: "h-3.5 w-3.5 shrink-0",
58585
+ "aria-hidden": true
58586
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
58587
+ className: "truncate",
58588
+ children: addLabel
58589
+ })]
58590
+ })]
58591
+ })
58592
+ });
58593
+ }
58594
+ function EntryPill({ entry, current, onSelect }) {
58595
+ const quiet = entry.status === "ok";
58596
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
58597
+ type: "button",
58598
+ "aria-current": current ? "true" : void 0,
58599
+ "data-testid": `provider-entry-pill-${entry.entryId}`,
58600
+ onClick: () => onSelect(entry.entryId),
58601
+ className: cn(PILL_BASE, current ? PILL_CURRENT : PILL_OTHER),
58602
+ children: [
58603
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryIcon, { url: entry.iconUrl }),
58604
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
58605
+ className: "truncate",
58606
+ children: entry.name
58607
+ }),
58608
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
58609
+ className: cn("h-1.5 w-1.5 shrink-0 rounded-full", STATE_DOT[entry.status]),
58610
+ "aria-hidden": true
58611
+ }),
58612
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
58613
+ className: quiet ? "sr-only" : "shrink-0 text-[10px] font-normal text-foreground-subtle",
58614
+ children: STATE_LABEL[entry.status]
58615
+ })
58616
+ ]
58617
+ });
58618
+ }
58619
+ function EntryIcon({ url }) {
58620
+ if (url === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
58621
+ className: "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-surface text-[9px] text-foreground-subtle",
58622
+ "aria-hidden": true,
58623
+ children: "?"
58624
+ });
58625
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
58626
+ src: url,
58627
+ alt: "",
58628
+ className: "h-5 w-5 shrink-0 rounded-full object-contain"
58629
+ });
58630
+ }
58631
+ //#endregion
58119
58632
  //#region src/composites/response-log.tsx
58120
58633
  /**
58121
58634
  * Expandable log box showing the raw JSON response from a pipeline run.
@@ -62070,6 +62583,7 @@ var SceneMonitorEditor = (0, react$1.lazy)(() => Promise.resolve().then(() => re
62070
62583
  /** Lazy-wrapped `PrivacyMaskSettings` — code-split off the main bundle. */
62071
62584
  var PrivacyMaskSettings = (0, react$1.lazy)(() => Promise.resolve().then(() => require("./PrivacyMaskSettings-BqjXsXZR.cjs")).then((m) => ({ default: m.PrivacyMaskSettings })));
62072
62585
  //#endregion
62586
+ exports.AddProviderEntryDialog = AddProviderEntryDialog;
62073
62587
  exports.AddonGlobalSettingsForm = AddonGlobalSettingsForm;
62074
62588
  exports.AdminLinkQuickAction = AdminLinkQuickAction;
62075
62589
  exports.AgentStepEditor = AgentStepEditor;
@@ -62261,6 +62775,7 @@ exports.MobileDrawer = MobileDrawer;
62261
62775
  exports.ModelPicker = ModelPicker;
62262
62776
  exports.MotionZonesSettings = MotionZonesSettings;
62263
62777
  exports.NAVIGATION_DRIVE_INTERVAL_MS = NAVIGATION_DRIVE_INTERVAL_MS;
62778
+ exports.NODE_COLOR_IDS = _camstack_types.NODE_COLOR_IDS;
62264
62779
  exports.NatResultCard = NatResultCard;
62265
62780
  exports.NavigationPanel = NavigationPanel;
62266
62781
  exports.NetworkLinkBadge = NetworkLinkBadge;
@@ -62288,6 +62803,7 @@ exports.PRIORITY = PRIORITY;
62288
62803
  exports.PTZOverlay = PTZOverlay;
62289
62804
  exports.PageHeader = PageHeader;
62290
62805
  exports.PageSizeSelect = PageSizeSelect;
62806
+ exports.Pagination = Pagination;
62291
62807
  exports.PasswordInput = PasswordInput;
62292
62808
  exports.PhaseIcon = PhaseIcon;
62293
62809
  exports.PipelineBuilder = PipelineBuilder;
@@ -62302,6 +62818,7 @@ exports.PopoverTrigger = PopoverTrigger;
62302
62818
  exports.PrimaryChildPicker = PrimaryChildPicker;
62303
62819
  exports.PrivacyMaskSettings = PrivacyMaskSettings;
62304
62820
  exports.ProviderBadge = ProviderBadge;
62821
+ exports.ProviderEntryPills = ProviderEntryPills;
62305
62822
  exports.PtzPanel = PtzPanel;
62306
62823
  exports.QrCode = QrCode;
62307
62824
  exports.RECONNECT_POLICY = RECONNECT_POLICY;
@@ -62309,12 +62826,14 @@ exports.RECORDED_PLAYBACK_MODES = RECORDED_PLAYBACK_MODES;
62309
62826
  exports.RIGHT = RIGHT;
62310
62827
  exports.ROI_AREA_WARN_FRACTION = ROI_AREA_WARN_FRACTION;
62311
62828
  exports.ROLE_DESCRIPTOR = ROLE_DESCRIPTOR;
62829
+ exports.ROOT_DETECTOR_STEP_ID = ROOT_DETECTOR_STEP_ID;
62312
62830
  exports.RadialGauge = RadialGauge;
62313
62831
  exports.RecordedPlaybackProvider = RecordedPlaybackProvider;
62314
62832
  exports.RecordingPanel = RecordingPanel;
62315
62833
  exports.ResponseLog = ResponseLog;
62316
62834
  exports.RoleDisplayDefaultsFromServer = RoleDisplayDefaultsFromServer;
62317
62835
  exports.RoleDisplayDefaultsProvider = RoleDisplayDefaultsProvider;
62836
+ exports.RoleNodePill = RoleNodePill;
62318
62837
  exports.RootModelSourceControl = RootModelSourceControl;
62319
62838
  exports.RootSuppliedModelNote = RootSuppliedModelNote;
62320
62839
  exports.RotateCcw = RotateCcw;
@@ -62397,6 +62916,7 @@ exports.TimezoneSelector = TimezoneSelector;
62397
62916
  exports.Tooltip = Tooltip;
62398
62917
  exports.TooltipContent = TooltipContent;
62399
62918
  exports.TooltipTrigger = TooltipTrigger;
62919
+ exports.TrainingBaseModelPicker = TrainingBaseModelPicker;
62400
62920
  exports.TrainingCollectionPicker = TrainingCollectionPicker;
62401
62921
  exports.Trash2 = Trash2;
62402
62922
  exports.UnitPicker = UnitPicker;
@@ -62423,6 +62943,7 @@ exports.allDeviceTypeFilterOptions = allDeviceTypeFilterOptions;
62423
62943
  exports.applyFleetQueryDefaults = applyFleetQueryDefaults;
62424
62944
  exports.applyPickerFilters = applyPickerFilters;
62425
62945
  exports.ariaSortForColumn = ariaSortForColumn;
62946
+ exports.assignNodeColorId = _camstack_types.assignNodeColorId;
62426
62947
  exports.badgeFor = badgeFor;
62427
62948
  exports.badgeFor$1 = badgeFor;
62428
62949
  exports.bindsToModel = bindsToModel;
@@ -62436,9 +62957,11 @@ exports.classifyAddressScope = classifyAddressScope;
62436
62957
  exports.classifyCapability = classifyCapability;
62437
62958
  exports.classifySessionVerdict = classifySessionVerdict;
62438
62959
  exports.clearPickerGroup = clearPickerGroup;
62960
+ exports.clusterRootModelIds = clusterRootModelIds;
62439
62961
  exports.cn = cn;
62440
62962
  exports.columnsForContext = columnsForContext;
62441
62963
  exports.compareSrflxMappings = compareSrflxMappings;
62964
+ exports.computePageButtons = computePageButtons;
62442
62965
  exports.containerChildToRef = containerChildToRef;
62443
62966
  exports.countableDevices = countableDevices;
62444
62967
  exports.coverHighlight = coverHighlight;
@@ -62452,6 +62975,7 @@ exports.darkColors = require_theme_index.darkColors$1;
62452
62975
  exports.dataTableFacetGroups = dataTableFacetGroups;
62453
62976
  exports.dataTableFacets = dataTableFacets;
62454
62977
  exports.defaultOfField = defaultOfField;
62978
+ exports.defaultSelectClusterRoots = defaultSelectClusterRoots;
62455
62979
  exports.defaultTheme = require_theme_index.defaultTheme$1;
62456
62980
  exports.deriveDeviceKind = deriveDeviceKind;
62457
62981
  exports.deriveWebrtcDebugStats = deriveWebrtcDebugStats;
@@ -62515,6 +63039,7 @@ exports.lawnMowerActivityMeta = lawnMowerActivityMeta;
62515
63039
  exports.lightColors = require_theme_index.lightColors$1;
62516
63040
  exports.loadRemoteBundle = loadRemoteBundle;
62517
63041
  exports.makeScrubBridge = makeScrubBridge;
63042
+ exports.mapRootDetectorPlacements = mapRootDetectorPlacements;
62518
63043
  exports.metadataEntries = metadataEntries;
62519
63044
  exports.metadataString = metadataString;
62520
63045
  exports.mirror = mirror;
@@ -62525,6 +63050,8 @@ exports.nextReconnectAction = nextReconnectAction;
62525
63050
  exports.nextSort = nextSort;
62526
63051
  exports.nextSortDirection = nextSortDirection;
62527
63052
  exports.nextTableSort = nextTableSort;
63053
+ exports.nodeColorClass = nodeColorClass;
63054
+ exports.nodeTextColorClass = nodeTextColorClass;
62528
63055
  exports.normalizeForSearch = normalizeForSearch;
62529
63056
  exports.offListSelections = offListSelections;
62530
63057
  exports.openTopLayer = openTopLayer;
@@ -63287,10 +63814,8 @@ exports.usePipelineAnalyticsCompleteRetrainTrack = usePipelineAnalyticsCompleteR
63287
63814
  exports.usePipelineAnalyticsCountRelocatableMedia = usePipelineAnalyticsCountRelocatableMedia;
63288
63815
  exports.usePipelineAnalyticsCountUnstampedEventMedia = usePipelineAnalyticsCountUnstampedEventMedia;
63289
63816
  exports.usePipelineAnalyticsCreateRetrainCollection = usePipelineAnalyticsCreateRetrainCollection;
63290
- exports.usePipelineAnalyticsCreateRetrainDatasetVersion = usePipelineAnalyticsCreateRetrainDatasetVersion;
63291
63817
  exports.usePipelineAnalyticsDeleteDeviceEvents = usePipelineAnalyticsDeleteDeviceEvents;
63292
63818
  exports.usePipelineAnalyticsDeleteRetrainCollection = usePipelineAnalyticsDeleteRetrainCollection;
63293
- exports.usePipelineAnalyticsDeleteRetrainDatasetVersion = usePipelineAnalyticsDeleteRetrainDatasetVersion;
63294
63819
  exports.usePipelineAnalyticsDeleteTracks = usePipelineAnalyticsDeleteTracks;
63295
63820
  exports.usePipelineAnalyticsDeselectRetrainFrame = usePipelineAnalyticsDeselectRetrainFrame;
63296
63821
  exports.usePipelineAnalyticsGetActiveTracks = usePipelineAnalyticsGetActiveTracks;
@@ -63308,6 +63833,7 @@ exports.usePipelineAnalyticsGetMediaReclaimStatus = usePipelineAnalyticsGetMedia
63308
63833
  exports.usePipelineAnalyticsGetMotionEvents = usePipelineAnalyticsGetMotionEvents;
63309
63834
  exports.usePipelineAnalyticsGetObjectEmbeddingRebuildStatus = usePipelineAnalyticsGetObjectEmbeddingRebuildStatus;
63310
63835
  exports.usePipelineAnalyticsGetObjectEvents = usePipelineAnalyticsGetObjectEvents;
63836
+ exports.usePipelineAnalyticsGetRetrainCorpusKpi = usePipelineAnalyticsGetRetrainCorpusKpi;
63311
63837
  exports.usePipelineAnalyticsGetRetrainExportUrl = usePipelineAnalyticsGetRetrainExportUrl;
63312
63838
  exports.usePipelineAnalyticsGetRetrainFrameImage = usePipelineAnalyticsGetRetrainFrameImage;
63313
63839
  exports.usePipelineAnalyticsGetSensorEvents = usePipelineAnalyticsGetSensorEvents;
@@ -63328,7 +63854,7 @@ exports.usePipelineAnalyticsListRetrainAnnotations = usePipelineAnalyticsListRet
63328
63854
  exports.usePipelineAnalyticsListRetrainAssistProfiles = usePipelineAnalyticsListRetrainAssistProfiles;
63329
63855
  exports.usePipelineAnalyticsListRetrainCollectionFrames = usePipelineAnalyticsListRetrainCollectionFrames;
63330
63856
  exports.usePipelineAnalyticsListRetrainCollections = usePipelineAnalyticsListRetrainCollections;
63331
- exports.usePipelineAnalyticsListRetrainDatasetVersions = usePipelineAnalyticsListRetrainDatasetVersions;
63857
+ exports.usePipelineAnalyticsListRetrainCorpusPage = usePipelineAnalyticsListRetrainCorpusPage;
63332
63858
  exports.usePipelineAnalyticsListRetrainFrames = usePipelineAnalyticsListRetrainFrames;
63333
63859
  exports.usePipelineAnalyticsListRetrainStaging = usePipelineAnalyticsListRetrainStaging;
63334
63860
  exports.usePipelineAnalyticsListTrackMedia = usePipelineAnalyticsListTrackMedia;
@@ -63337,7 +63863,6 @@ exports.usePipelineAnalyticsListTracks = usePipelineAnalyticsListTracks;
63337
63863
  exports.usePipelineAnalyticsOfferRetrainArchive = usePipelineAnalyticsOfferRetrainArchive;
63338
63864
  exports.usePipelineAnalyticsOwnersWithMedia = usePipelineAnalyticsOwnersWithMedia;
63339
63865
  exports.usePipelineAnalyticsPauseForStorageMigration = usePipelineAnalyticsPauseForStorageMigration;
63340
- exports.usePipelineAnalyticsPreviewRetrainDataset = usePipelineAnalyticsPreviewRetrainDataset;
63341
63866
  exports.usePipelineAnalyticsProposeRetrainAnnotations = usePipelineAnalyticsProposeRetrainAnnotations;
63342
63867
  exports.usePipelineAnalyticsProposeRetrainAnnotationsWithLlm = usePipelineAnalyticsProposeRetrainAnnotationsWithLlm;
63343
63868
  exports.usePipelineAnalyticsPruneEvents = usePipelineAnalyticsPruneEvents;
@@ -63351,6 +63876,7 @@ exports.usePipelineAnalyticsRefreshStorageLocationsForMigration = usePipelineAna
63351
63876
  exports.usePipelineAnalyticsRelocateMedia = usePipelineAnalyticsRelocateMedia;
63352
63877
  exports.usePipelineAnalyticsRemoveRetrainFrameFromCollection = usePipelineAnalyticsRemoveRetrainFrameFromCollection;
63353
63878
  exports.usePipelineAnalyticsRenameRetrainCollection = usePipelineAnalyticsRenameRetrainCollection;
63879
+ exports.usePipelineAnalyticsResolveRetrainTrainingCorpus = usePipelineAnalyticsResolveRetrainTrainingCorpus;
63354
63880
  exports.usePipelineAnalyticsRestageRetrainTrack = usePipelineAnalyticsRestageRetrainTrack;
63355
63881
  exports.usePipelineAnalyticsResumeForStorageMigration = usePipelineAnalyticsResumeForStorageMigration;
63356
63882
  exports.usePipelineAnalyticsSaveRetrainAnnotations = usePipelineAnalyticsSaveRetrainAnnotations;
@@ -63361,7 +63887,6 @@ exports.usePipelineAnalyticsSetTrackFlags = usePipelineAnalyticsSetTrackFlags;
63361
63887
  exports.usePipelineAnalyticsSetTrackPurity = usePipelineAnalyticsSetTrackPurity;
63362
63888
  exports.usePipelineAnalyticsSetTrackRelation = usePipelineAnalyticsSetTrackRelation;
63363
63889
  exports.usePipelineAnalyticsStartStorageMigrationMove = usePipelineAnalyticsStartStorageMigrationMove;
63364
- exports.usePipelineAnalyticsVerifyRetrainDatasetVersion = usePipelineAnalyticsVerifyRetrainDatasetVersion;
63365
63890
  exports.usePipelineAnalyticsWipeAllAnalytics = usePipelineAnalyticsWipeAllAnalytics;
63366
63891
  exports.usePipelineAnalyticsWipeObjectEmbeddings = usePipelineAnalyticsWipeObjectEmbeddings;
63367
63892
  exports.usePipelineAnalyticsWriteRetrainArchive = usePipelineAnalyticsWriteRetrainArchive;
@@ -63749,19 +64274,15 @@ exports.useToastOnToast = useToastOnToast;
63749
64274
  exports.useTrainingCanaryResult = useTrainingCanaryResult;
63750
64275
  exports.useTrainingCancelJob = useTrainingCancelJob;
63751
64276
  exports.useTrainingDiscardResult = useTrainingDiscardResult;
63752
- exports.useTrainingFindDatasetVersionIdByName = useTrainingFindDatasetVersionIdByName;
63753
- exports.useTrainingGetDatasetVersion = useTrainingGetDatasetVersion;
63754
64277
  exports.useTrainingGetJob = useTrainingGetJob;
63755
64278
  exports.useTrainingGetJobResult = useTrainingGetJobResult;
63756
64279
  exports.useTrainingListBaseModels = useTrainingListBaseModels;
63757
- exports.useTrainingListDatasetVersions = useTrainingListDatasetVersions;
63758
64280
  exports.useTrainingListJobs = useTrainingListJobs;
63759
64281
  exports.useTrainingPlanJob = useTrainingPlanJob;
63760
- exports.useTrainingPutDatasetVersion = useTrainingPutDatasetVersion;
63761
64282
  exports.useTrainingRegisterResult = useTrainingRegisterResult;
63762
- exports.useTrainingRemoveDatasetVersion = useTrainingRemoveDatasetVersion;
63763
64283
  exports.useTrainingRollbackCanary = useTrainingRollbackCanary;
63764
64284
  exports.useTrainingStartJob = useTrainingStartJob;
64285
+ exports.useTrainingStartJobBatch = useTrainingStartJobBatch;
63765
64286
  exports.useTurnProviderGetTurnServers = useTurnProviderGetTurnServers;
63766
64287
  exports.useUpdateGetStatus = useUpdateGetStatus;
63767
64288
  exports.useUpdateInstallUpdate = useUpdateInstallUpdate;