@camstack/ui-library 1.1.27 → 1.1.29

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
@@ -3748,37 +3748,41 @@ function mirror(input) {
3748
3748
  });
3749
3749
  continue;
3750
3750
  }
3751
- const srcModel = findModel(targetAddon, srcCfg.modelId);
3752
- const canUseSource = srcModel !== null && Boolean(srcModel.formats[target.engine.format]);
3753
3751
  let chosenModelId;
3754
3752
  let outcome;
3755
- if (canUseSource) {
3756
- chosenModelId = srcCfg.modelId;
3753
+ if (srcCfg.modelId === void 0) {
3754
+ chosenModelId = void 0;
3757
3755
  outcome = "exact";
3758
3756
  } else {
3759
- const fallback = firstModelFor(targetAddon, target.engine.format);
3760
- if (!fallback) {
3761
- out.push({
3762
- addonId,
3763
- outcome: "skip",
3764
- modelId: null,
3765
- reason: "no compatible model for target format",
3766
- patch: null
3767
- });
3768
- continue;
3757
+ const srcModel = findModel(targetAddon, srcCfg.modelId);
3758
+ if (srcModel !== null && Boolean(srcModel.formats[target.engine.format])) {
3759
+ chosenModelId = srcCfg.modelId;
3760
+ outcome = "exact";
3761
+ } else {
3762
+ const fallback = firstModelFor(targetAddon, target.engine.format);
3763
+ if (!fallback) {
3764
+ out.push({
3765
+ addonId,
3766
+ outcome: "skip",
3767
+ modelId: null,
3768
+ reason: "no compatible model for target format",
3769
+ patch: null
3770
+ });
3771
+ continue;
3772
+ }
3773
+ chosenModelId = fallback.id;
3774
+ outcome = "mapped";
3769
3775
  }
3770
- chosenModelId = fallback.id;
3771
- outcome = "mapped";
3772
3776
  }
3773
3777
  const patch = {
3774
3778
  enabled: srcCfg.enabled,
3775
- modelId: chosenModelId,
3779
+ ...chosenModelId ? { modelId: chosenModelId } : {},
3776
3780
  settings: dropModelSpecific(srcCfg.settings, targetAddon)
3777
3781
  };
3778
3782
  out.push({
3779
3783
  addonId,
3780
3784
  outcome,
3781
- modelId: chosenModelId,
3785
+ modelId: chosenModelId ?? null,
3782
3786
  patch
3783
3787
  });
3784
3788
  }
@@ -13268,10 +13272,11 @@ function modelsForStep(schema) {
13268
13272
  name: m.name
13269
13273
  }));
13270
13274
  }
13271
- function PipelineStep({ step, schema, allSchemas: _allSchemas, depth: _depth = 0, onChange, onDelete: _onDelete, readOnly = false, toggleMode = "simple", overrideState = null, onOverrideChange, inheritedEnabled, hideModelAndSettings = false }) {
13275
+ function PipelineStep({ step, schema, allSchemas: _allSchemas, depth: _depth = 0, onChange, onDelete: _onDelete, readOnly = false, toggleMode = "simple", overrideState = null, onOverrideChange, inheritedEnabled, hideModelAndSettings = false, allowAutoModel = false }) {
13272
13276
  const [expanded, setExpanded] = (0, react$1.useState)(false);
13273
13277
  const models = modelsForStep(schema);
13274
- if (models.length > 0 && !models.some((m) => m.id === step.modelId) && !readOnly) {
13278
+ const isAutoSentinel = allowAutoModel && step.modelId === "";
13279
+ if (models.length > 0 && !isAutoSentinel && !models.some((m) => m.id === step.modelId) && !readOnly) {
13275
13280
  const fallback = (schema?.defaultModelId ? models.find((m) => m.id === schema.defaultModelId) : null) ?? models[0];
13276
13281
  if (fallback && fallback.id !== step.modelId) queueMicrotask(() => onChange({
13277
13282
  ...step,
@@ -13356,59 +13361,28 @@ function PipelineStep({ step, schema, allSchemas: _allSchemas, depth: _depth = 0
13356
13361
  children: "Model and detection settings are managed per agent — open the Pipeline page for this camera's agent to edit them."
13357
13362
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
13358
13363
  className: "space-y-3",
13359
- children: [
13360
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigSelect, {
13361
- label: "Model",
13362
- value: step.modelId,
13363
- disabled: readOnly,
13364
- options: models.map((m) => ({
13365
- value: m.id,
13366
- label: m.name
13367
- })),
13368
- onChange: (v) => onChange({
13369
- ...step,
13370
- modelId: v
13371
- })
13372
- }),
13373
- step.slot === "audio-classifier" && step.engine && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigSelect, {
13374
- label: "Runtime",
13375
- value: `${step.engine.runtime}/${step.engine.backend}`,
13376
- disabled: readOnly,
13377
- options: [
13378
- {
13379
- value: "node/cpu",
13380
- label: "Node.js — ONNX CPU"
13381
- },
13382
- {
13383
- value: "node/coreml",
13384
- label: "Node.js — Apple SoundAnalysis (macOS)"
13385
- },
13386
- {
13387
- value: "python/cpu",
13388
- label: "Python — ONNX CPU"
13389
- }
13390
- ],
13391
- onChange: (v) => {
13392
- const [runtime, backend] = v.split("/");
13393
- const format = backend === "coreml" ? "coreml" : "onnx";
13394
- onChange({
13395
- ...step,
13396
- engine: {
13397
- runtime,
13398
- backend,
13399
- format
13400
- }
13401
- });
13402
- }
13403
- }),
13404
- schema?.configSchema?.map((field) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigSchemaField, {
13405
- field,
13406
- allFields: schema.configSchema ?? [],
13407
- step,
13408
- disabled: readOnly,
13409
- onChange
13410
- }, field.key))
13411
- ]
13364
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigSelect, {
13365
+ label: "Model",
13366
+ value: step.modelId,
13367
+ disabled: readOnly,
13368
+ options: [...allowAutoModel ? [{
13369
+ value: "",
13370
+ label: "Auto (node default)"
13371
+ }] : [], ...models.map((m) => ({
13372
+ value: m.id,
13373
+ label: m.name
13374
+ }))],
13375
+ onChange: (v) => onChange({
13376
+ ...step,
13377
+ modelId: v
13378
+ })
13379
+ }), schema?.configSchema?.map((field) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigSchemaField, {
13380
+ field,
13381
+ allFields: schema.configSchema ?? [],
13382
+ step,
13383
+ disabled: readOnly,
13384
+ onChange
13385
+ }, field.key))]
13412
13386
  })
13413
13387
  });
13414
13388
  }
@@ -13607,7 +13581,200 @@ function ThreeStateButton({ label, active, variant, subtext, onClick }) {
13607
13581
  });
13608
13582
  }
13609
13583
  //#endregion
13584
+ //#region src/composites/grouped-model-selector.tsx
13585
+ /**
13586
+ * GroupedModelSelector — the shared Family → Tier → Variant model picker.
13587
+ *
13588
+ * The catalog is a FLAT list of models (ids like `yolo26s`, `yolo26s-int8`);
13589
+ * this folds it into a `family → tier → variant` tree (see
13590
+ * `buildModelVariantGroups` in `@camstack/types`) so the operator picks
13591
+ * "YOLO26 → Small → Int8" instead of scanning a flat dropdown of every
13592
+ * size×quantization. The selected value stays the flat model id.
13593
+ *
13594
+ * Parameterised on the minimal `ModelVariantSource` shape so BOTH the config-UI
13595
+ * catalog (`ModelCatalogEntry`) and the pipeline/device steppers
13596
+ * (`PipelineModelOption`) drive the same component. Legacy / ungrouped models
13597
+ * never appear here (the grouping helpers skip them).
13598
+ */
13599
+ function Chip({ active, onClick, disabled, children, title }) {
13600
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
13601
+ type: "button",
13602
+ onClick,
13603
+ disabled,
13604
+ title,
13605
+ className: cn("rounded-full px-3 py-1 text-[11px] font-medium border transition-colors", active ? "border-primary bg-primary/10 text-primary" : "border-border bg-background text-foreground-subtle hover:text-foreground hover:border-foreground-subtle/40", disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"),
13606
+ children
13607
+ });
13608
+ }
13609
+ function GroupedModelSelector({ catalog, value, onChange, disabled }) {
13610
+ const families = (0, _camstack_types.buildModelVariantGroups)(catalog);
13611
+ const current = (0, _camstack_types.describeModelVariant)(catalog, value);
13612
+ const activeFamily = families.find((f) => f.family === current?.family)?.family ?? families[0]?.family ?? "";
13613
+ const family = families.find((f) => f.family === activeFamily) ?? families[0];
13614
+ if (!family) return null;
13615
+ const activeTier = family.tiers.find((t) => t.tier === current?.tier)?.tier ?? family.tiers[0]?.tier ?? "";
13616
+ const tier = family.tiers.find((t) => t.tier === activeTier) ?? family.tiers[0];
13617
+ if (!tier) return null;
13618
+ const resolutions = [...new Set(tier.options.map((o) => o.resolution))].sort((a, b) => (b ?? Infinity) - (a ?? Infinity));
13619
+ const selectedResolution = resolutions.includes(current?.resolution) ? current?.resolution : resolutions[0];
13620
+ const variantOptions = tier.options.filter((o) => o.resolution === selectedResolution);
13621
+ const resLabel = (r) => r === void 0 ? "640 · native" : `${r}`;
13622
+ const selectTier = (tierId) => {
13623
+ const t = family.tiers.find((x) => x.tier === tierId);
13624
+ if (!t) return;
13625
+ onChange((t.options.find((o) => o.precision === (current?.precision ?? "fp32") && o.optimization === (current?.optimization ?? "standard") && o.resolution === current?.resolution) ?? t.options[0]).modelId);
13626
+ };
13627
+ const selectResolution = (resolution) => {
13628
+ const opts = tier.options.filter((o) => o.resolution === resolution);
13629
+ const pick = opts.find((o) => o.precision === (current?.precision ?? "fp32") && o.optimization === (current?.optimization ?? "standard")) ?? opts[0];
13630
+ if (pick) onChange(pick.modelId);
13631
+ };
13632
+ const selectVariant = (opt) => {
13633
+ const id = (0, _camstack_types.resolveVariantModelId)(catalog, {
13634
+ family: family.family,
13635
+ tier: tier.tier,
13636
+ precision: opt.precision,
13637
+ optimization: opt.optimization,
13638
+ resolution: opt.resolution
13639
+ });
13640
+ if (id) onChange(id);
13641
+ };
13642
+ const selectedOption = tier.options.find((o) => o.modelId === value) ?? null;
13643
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
13644
+ className: "space-y-3",
13645
+ children: [
13646
+ families.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
13647
+ className: "text-[10px] uppercase tracking-wide text-foreground-subtle mb-1.5",
13648
+ children: "Family"
13649
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
13650
+ className: "flex flex-wrap gap-1.5",
13651
+ children: families.map((f) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chip, {
13652
+ active: f.family === family.family,
13653
+ disabled,
13654
+ onClick: () => onChange(f.tiers[0]?.baseModelId ?? ""),
13655
+ children: f.label
13656
+ }, f.family))
13657
+ })] }),
13658
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
13659
+ className: "text-[10px] uppercase tracking-wide text-foreground-subtle mb-1.5",
13660
+ children: [family.label, " — size"]
13661
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
13662
+ className: "grid grid-cols-2 gap-1.5 sm:grid-cols-4",
13663
+ children: family.tiers.map((t) => {
13664
+ const active = t.tier === tier.tier;
13665
+ const base = t.options.find((o) => o.modelId === t.baseModelId) ?? t.options[0];
13666
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
13667
+ type: "button",
13668
+ disabled,
13669
+ onClick: () => selectTier(t.tier),
13670
+ className: cn("rounded-lg border px-2 py-2 text-left transition-all", active ? "border-primary bg-primary/5 ring-1 ring-primary/30" : "border-border bg-background hover:border-foreground-subtle/40", disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"),
13671
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
13672
+ className: "flex items-center gap-1",
13673
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13674
+ className: "text-xs font-semibold text-foreground",
13675
+ children: t.label
13676
+ }), active && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Check, { className: "h-3 w-3 text-primary" })]
13677
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
13678
+ className: "text-[10px] text-foreground-subtle",
13679
+ children: [
13680
+ "~",
13681
+ base?.sizeMB ?? 0,
13682
+ " MB"
13683
+ ]
13684
+ })]
13685
+ }, t.tier);
13686
+ })
13687
+ })] }),
13688
+ resolutions.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
13689
+ className: "text-[10px] uppercase tracking-wide text-foreground-subtle mb-1.5",
13690
+ children: "Resolution"
13691
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
13692
+ className: "flex flex-wrap gap-1.5",
13693
+ children: resolutions.map((r) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chip, {
13694
+ active: r === selectedResolution,
13695
+ disabled,
13696
+ title: r === void 0 ? "native (best accuracy)" : `${r}×${r} (faster)`,
13697
+ onClick: () => selectResolution(r),
13698
+ children: resLabel(r)
13699
+ }, r ?? "native"))
13700
+ })] }),
13701
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
13702
+ className: "text-[10px] uppercase tracking-wide text-foreground-subtle mb-1.5",
13703
+ children: "Variant"
13704
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
13705
+ className: "flex flex-wrap gap-1.5",
13706
+ children: variantOptions.map((opt) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chip, {
13707
+ active: opt.modelId === value,
13708
+ disabled,
13709
+ title: `${opt.formats.join(", ")} · ~${opt.sizeMB} MB`,
13710
+ onClick: () => selectVariant(opt),
13711
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
13712
+ className: "inline-flex items-center gap-1",
13713
+ children: [opt.optimization === "fast" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Zap, { className: "h-3 w-3" }), opt.label]
13714
+ })
13715
+ }, opt.modelId))
13716
+ })] }),
13717
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
13718
+ className: "flex items-center gap-2 text-[10px] text-foreground-subtle pt-0.5",
13719
+ children: [
13720
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Cpu, { className: "h-3 w-3" }),
13721
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13722
+ className: "font-mono",
13723
+ children: value || "—"
13724
+ }),
13725
+ selectedOption && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
13726
+ "· ",
13727
+ selectedOption.formats.join(", "),
13728
+ " · ~",
13729
+ selectedOption.sizeMB,
13730
+ " MB"
13731
+ ] })
13732
+ ]
13733
+ })
13734
+ ]
13735
+ });
13736
+ }
13737
+ //#endregion
13610
13738
  //#region src/composites/agent-step-editor.tsx
13739
+ /**
13740
+ * Shared model picker for the step editor — renders the grouped
13741
+ * Family→Tier→Variant selector when the step's models declare variant groups
13742
+ * (yolo26 …), else a flat `<select>` (face / plate / classifier catalogs and
13743
+ * custom models). Same component both the agent-default and per-device-override
13744
+ * modes use, so the picker looks identical across the pipeline stepper, the
13745
+ * device stepper and the cluster matrix.
13746
+ */
13747
+ function ModelPicker({ models, value, onChange, disabled }) {
13748
+ const hasGroups = (0, react$1.useMemo)(() => (0, _camstack_types.buildModelVariantGroups)(models).length > 0, [models]);
13749
+ const ungrouped = (0, react$1.useMemo)(() => models.filter((m) => m.group === void 0), [models]);
13750
+ const flatSelect = (opts, selectPlaceholder) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
13751
+ disabled,
13752
+ className: "w-full bg-surface border border-border rounded px-2 py-1 text-xs disabled:opacity-50",
13753
+ value: opts.some((m) => m.id === value) ? value : "",
13754
+ onChange: (e) => onChange(e.target.value),
13755
+ children: [selectPlaceholder !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
13756
+ value: "",
13757
+ disabled: true,
13758
+ children: selectPlaceholder
13759
+ }), opts.map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
13760
+ value: m.id,
13761
+ children: m.name
13762
+ }, m.id))]
13763
+ });
13764
+ if (!hasGroups) return flatSelect(models);
13765
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
13766
+ className: "space-y-3",
13767
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupedModelSelector, {
13768
+ catalog: models,
13769
+ value,
13770
+ onChange,
13771
+ disabled
13772
+ }), ungrouped.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
13773
+ className: "text-[10px] uppercase tracking-widest text-foreground-subtle mb-1",
13774
+ children: "Other models"
13775
+ }), flatSelect(ungrouped, "— custom / ungrouped model —")] })]
13776
+ });
13777
+ }
13611
13778
  function buildDisplayStep(addon, cfg) {
13612
13779
  return {
13613
13780
  addonId: addon.id,
@@ -13616,7 +13783,7 @@ function buildDisplayStep(addon, cfg) {
13616
13783
  inputClasses: [...addon.inputClasses],
13617
13784
  outputClasses: [...addon.outputClasses],
13618
13785
  enabled: cfg.enabled,
13619
- modelId: cfg.modelId,
13786
+ modelId: cfg.modelId ?? addon.defaultModelId,
13620
13787
  children: [],
13621
13788
  settings: { ...cfg.settings }
13622
13789
  };
@@ -13654,14 +13821,10 @@ function AgentModeEditor({ addon, agentDefault, modelsForFormat, onChangeAgentCo
13654
13821
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
13655
13822
  className: "text-[10px] uppercase tracking-widest text-foreground-subtle mb-1",
13656
13823
  children: "Model"
13657
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
13658
- className: "w-full bg-surface border border-border rounded px-2 py-1 text-xs",
13659
- value: agentDefault.modelId,
13660
- onChange: (e) => update({ modelId: e.target.value }),
13661
- children: modelsForFormat.map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
13662
- value: m.id,
13663
- children: m.name
13664
- }, m.id))
13824
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelPicker, {
13825
+ models: modelsForFormat,
13826
+ value: agentDefault.modelId ?? "",
13827
+ onChange: (modelId) => update({ modelId })
13665
13828
  })] }),
13666
13829
  (addon.configSchema?.length ?? 0) > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
13667
13830
  className: "pt-2 border-t border-border/50 space-y-3",
@@ -13752,15 +13915,11 @@ function DeviceModeEditor({ addon, agentDefault, agentNodeId, currentPatch, mode
13752
13915
  children: "Override"
13753
13916
  })]
13754
13917
  }),
13755
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
13918
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelPicker, {
13919
+ models: modelsForFormat,
13756
13920
  disabled: !modelOverridden,
13757
- className: "w-full bg-surface border border-border rounded px-2 py-1 text-xs disabled:opacity-50",
13758
- value: modelOverridden ? currentPatch?.modelId ?? agentDefault.modelId : agentDefault.modelId,
13759
- onChange: (e) => setModel(e.target.value),
13760
- children: modelsForFormat.map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
13761
- value: m.id,
13762
- children: m.name
13763
- }, m.id))
13921
+ value: (modelOverridden ? currentPatch?.modelId ?? agentDefault.modelId : agentDefault.modelId) ?? "",
13922
+ onChange: (modelId) => setModel(modelId)
13764
13923
  }),
13765
13924
  !modelOverridden && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
13766
13925
  className: "text-[10px] text-foreground-subtle mt-1",
@@ -13940,17 +14099,33 @@ function QuickToggle({ enabled, onChange, disabled }) {
13940
14099
  function renderCellContent(state) {
13941
14100
  if (state.kind === "enabled") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
13942
14101
  className: "flex min-w-0 items-center gap-1",
13943
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "h-1.5 w-1.5 rounded-full bg-emerald-500 shrink-0" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13944
- className: "font-mono text-foreground truncate",
13945
- children: state.modelId
13946
- })]
14102
+ title: state.overridden ? "override" : void 0,
14103
+ children: [
14104
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: cn("h-1.5 w-1.5 rounded-full shrink-0", state.overridden ? "bg-amber-500" : "bg-emerald-500") }),
14105
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14106
+ className: "font-mono text-foreground truncate",
14107
+ children: state.modelId
14108
+ }),
14109
+ state.overridden && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14110
+ className: "ml-auto shrink-0 text-[8px] font-semibold uppercase text-amber-500",
14111
+ children: "ovr"
14112
+ })
14113
+ ]
13947
14114
  });
13948
14115
  if (state.kind === "disabled") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
13949
14116
  className: "flex min-w-0 items-center gap-1 text-foreground-subtle",
13950
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "h-1.5 w-1.5 rounded-full border border-foreground-subtle/60 shrink-0" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13951
- className: "truncate",
13952
- children: "off"
13953
- })]
14117
+ title: state.overridden ? "override" : void 0,
14118
+ children: [
14119
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: cn("h-1.5 w-1.5 rounded-full shrink-0", state.overridden ? "bg-amber-500" : "border border-foreground-subtle/60") }),
14120
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14121
+ className: "truncate",
14122
+ children: "off"
14123
+ }),
14124
+ state.overridden && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14125
+ className: "ml-auto shrink-0 text-[8px] font-semibold uppercase text-amber-500",
14126
+ children: "ovr"
14127
+ })
14128
+ ]
13954
14129
  });
13955
14130
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
13956
14131
  className: "flex min-w-0 items-center gap-1 text-foreground-subtle/70",
@@ -15597,6 +15772,22 @@ function usePTZ(trpc, deviceId, hookOptions) {
15597
15772
  refreshPresets,
15598
15773
  wrap
15599
15774
  ]),
15775
+ updatePreset: (0, react$1.useCallback)(async (presetId) => {
15776
+ if (!ptz) return;
15777
+ await wrap(async () => {
15778
+ const existing = presets.find((p) => p.id === presetId);
15779
+ await ptz.savePreset({
15780
+ presetId,
15781
+ name: existing?.name ?? ""
15782
+ });
15783
+ await refreshPresets();
15784
+ });
15785
+ }, [
15786
+ ptz,
15787
+ presets,
15788
+ refreshPresets,
15789
+ wrap
15790
+ ]),
15600
15791
  deletePreset: (0, react$1.useCallback)(async (presetId) => {
15601
15792
  if (!ptz) return;
15602
15793
  await wrap(async () => {
@@ -15691,10 +15882,13 @@ function DPadButton({ direction, icon: Icon, disabled, className, variant, onMov
15691
15882
  });
15692
15883
  }
15693
15884
  function PTZOverlay({ controls, mode = "overlay", showPresets, showZoom = true, showHome = true, className }) {
15694
- const { move, startContinuous, stopContinuous, zoom, goHome, goToPreset, savePreset, deletePreset, presets, options, busy, error } = controls;
15885
+ const { move, startContinuous, stopContinuous, zoom, goHome, goToPreset, savePreset, updatePreset, deletePreset, presets, options, busy, error } = controls;
15695
15886
  const confirm = useConfirm();
15696
15887
  const [presetsOpen, setPresetsOpen] = (0, react$1.useState)(false);
15697
15888
  const [presetName, setPresetName] = (0, react$1.useState)("");
15889
+ const presetTriggerRef = (0, react$1.useRef)(null);
15890
+ const presetMenuRef = (0, react$1.useRef)(null);
15891
+ const [menuPos, setMenuPos] = (0, react$1.useState)(null);
15698
15892
  const isPanel = mode === "panel";
15699
15893
  const zoomVisible = showZoom && (options?.hasZoom ?? true);
15700
15894
  const supportsPresets = options?.supportsPresets ?? presets.length > 0;
@@ -15720,6 +15914,51 @@ function PTZOverlay({ controls, mode = "overlay", showPresets, showZoom = true,
15720
15914
  })) return;
15721
15915
  await deletePreset(presetId);
15722
15916
  }, [confirm, deletePreset]);
15917
+ const handleUpdatePreset = (0, react$1.useCallback)(async (presetId, label) => {
15918
+ if (!await confirm({
15919
+ title: "Update preset",
15920
+ message: `Overwrite preset "${label}" with the camera's current position?`,
15921
+ confirmLabel: "Update"
15922
+ })) return;
15923
+ await updatePreset(presetId);
15924
+ }, [confirm, updatePreset]);
15925
+ (0, react$1.useLayoutEffect)(() => {
15926
+ if (!presetsOpen) {
15927
+ setMenuPos(null);
15928
+ return;
15929
+ }
15930
+ const reposition = () => {
15931
+ const rect = presetTriggerRef.current?.getBoundingClientRect();
15932
+ if (rect) setMenuPos({
15933
+ top: rect.bottom + 4,
15934
+ right: window.innerWidth - rect.right
15935
+ });
15936
+ };
15937
+ reposition();
15938
+ window.addEventListener("resize", reposition);
15939
+ window.addEventListener("scroll", reposition, true);
15940
+ return () => {
15941
+ window.removeEventListener("resize", reposition);
15942
+ window.removeEventListener("scroll", reposition, true);
15943
+ };
15944
+ }, [presetsOpen]);
15945
+ (0, react$1.useEffect)(() => {
15946
+ if (!presetsOpen) return;
15947
+ const onPointerDown = (e) => {
15948
+ const target = e.target;
15949
+ if (presetMenuRef.current?.contains(target) || presetTriggerRef.current?.contains(target)) return;
15950
+ setPresetsOpen(false);
15951
+ };
15952
+ const onKey = (e) => {
15953
+ if (e.key === "Escape") setPresetsOpen(false);
15954
+ };
15955
+ document.addEventListener("mousedown", onPointerDown);
15956
+ document.addEventListener("keydown", onKey);
15957
+ return () => {
15958
+ document.removeEventListener("mousedown", onPointerDown);
15959
+ document.removeEventListener("keydown", onKey);
15960
+ };
15961
+ }, [presetsOpen]);
15723
15962
  const containerClass = isPanel ? "flex flex-col items-stretch gap-2 w-full h-full p-3" : "pointer-events-auto absolute top-3 right-3 z-10 flex flex-col items-end gap-2";
15724
15963
  const rowClass = isPanel ? cn("flex items-center gap-3 rounded-lg p-2", busy && "ring-1 ring-primary/40") : cn("flex items-center gap-2 rounded-lg border border-white/30 bg-zinc-900/90 backdrop-blur-md p-2 shadow-lg shadow-black/40", busy && "ring-1 ring-primary/40");
15725
15964
  const sideButtonSize = isPanel ? "h-9 w-9" : "h-7 w-7";
@@ -15820,14 +16059,22 @@ function PTZOverlay({ controls, mode = "overlay", showPresets, showZoom = true,
15820
16059
  presetsVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15821
16060
  className: "relative",
15822
16061
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
16062
+ ref: presetTriggerRef,
15823
16063
  type: "button",
15824
16064
  onClick: () => setPresetsOpen((v) => !v),
15825
16065
  disabled: busy,
15826
16066
  className: cn("flex items-center gap-1 rounded px-2 text-[10px] disabled:opacity-40", isPanel ? "h-9 text-foreground hover:bg-surface-hover" : "h-7 text-white hover:bg-white/15"),
15827
16067
  title: "Presets",
15828
16068
  children: ["Presets", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDown, { className: cn("h-3 w-3 transition-transform", presetsOpen && "rotate-180") })]
15829
- }), presetsOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15830
- className: cn("absolute right-0 top-full mt-1 rounded-lg shadow-xl py-1 z-20", presetManagementVisible ? "min-w-[220px]" : "min-w-[140px]", isPanel ? "bg-surface border border-border" : "border border-white/30 bg-zinc-900/95 backdrop-blur-md"),
16069
+ }), presetsOpen && menuPos && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16070
+ ref: presetMenuRef,
16071
+ style: {
16072
+ position: "fixed",
16073
+ top: menuPos.top,
16074
+ right: menuPos.right,
16075
+ zIndex: 60
16076
+ },
16077
+ className: cn("rounded-lg shadow-xl py-1", presetManagementVisible ? "min-w-[220px]" : "min-w-[140px]", isPanel ? "bg-surface border border-border" : "border border-white/30 bg-zinc-900/95 backdrop-blur-md"),
15831
16078
  children: [
15832
16079
  presets.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
15833
16080
  className: cn("px-3 py-1.5 text-[10px]", isPanel ? "text-foreground-subtle" : "text-white/60"),
@@ -15844,14 +16091,21 @@ function PTZOverlay({ controls, mode = "overlay", showPresets, showZoom = true,
15844
16091
  disabled: busy,
15845
16092
  className: cn("flex-1 px-3 py-1.5 text-left text-[10px] disabled:opacity-40", isPanel ? "text-foreground" : "text-white"),
15846
16093
  children: p.name || p.id
15847
- }), presetManagementVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
16094
+ }), presetManagementVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
16095
+ type: "button",
16096
+ onClick: () => void handleUpdatePreset(p.id, p.name || p.id),
16097
+ disabled: busy,
16098
+ title: `Overwrite "${p.name || p.id}" with current position`,
16099
+ className: cn("flex h-5 w-5 shrink-0 items-center justify-center rounded", "text-foreground-subtle hover:bg-primary/15 hover:text-primary disabled:opacity-40"),
16100
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Crosshair, { className: "h-3 w-3" })
16101
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
15848
16102
  type: "button",
15849
16103
  onClick: () => void handleDeletePreset(p.id, p.name || p.id),
15850
16104
  disabled: busy,
15851
16105
  title: `Delete preset ${p.name || p.id}`,
15852
16106
  className: cn("mr-1 flex h-5 w-5 shrink-0 items-center justify-center rounded", "text-foreground-subtle hover:bg-danger/15 hover:text-danger disabled:opacity-40"),
15853
16107
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(X, { className: "h-3 w-3" })
15854
- })]
16108
+ })] })]
15855
16109
  }, p.id)),
15856
16110
  presetManagementVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
15857
16111
  presets.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: cn("my-1 h-px", isPanel ? "bg-border" : "bg-white/15") }),
@@ -15887,7 +16141,7 @@ function PTZOverlay({ controls, mode = "overlay", showPresets, showZoom = true,
15887
16141
  })
15888
16142
  ] })
15889
16143
  ]
15890
- })]
16144
+ }), document.body)]
15891
16145
  })
15892
16146
  ]
15893
16147
  })]
@@ -17704,6 +17958,8 @@ var usePipelineExecutorGetEngineProvisioning = trpc.pipelineExecutor.getEnginePr
17704
17958
  var usePipelineExecutorGetVideoPipelineSteps = trpc.pipelineExecutor.getVideoPipelineSteps.useQuery;
17705
17959
  /** Generated alias around `trpc.pipelineExecutor.setVideoPipelineSteps.useMutation`. */
17706
17960
  var usePipelineExecutorSetVideoPipelineSteps = trpc.pipelineExecutor.setVideoPipelineSteps.useMutation;
17961
+ /** Generated alias around `trpc.pipelineExecutor.resetToDefault.useMutation`. */
17962
+ var usePipelineExecutorResetToDefault = trpc.pipelineExecutor.resetToDefault.useMutation;
17707
17963
  /** Generated alias around `trpc.pipelineExecutor.getSchema.useQuery`. */
17708
17964
  var usePipelineExecutorGetSchema = trpc.pipelineExecutor.getSchema.useQuery;
17709
17965
  /** Generated alias around `trpc.pipelineExecutor.getGlobalSteps.useQuery`. */
@@ -17712,6 +17968,8 @@ var usePipelineExecutorGetGlobalSteps = trpc.pipelineExecutor.getGlobalSteps.use
17712
17968
  var usePipelineExecutorGetGlobalPipelineConfig = trpc.pipelineExecutor.getGlobalPipelineConfig.useQuery;
17713
17969
  /** Generated alias around `trpc.pipelineExecutor.getOrchestratorConfigSchema.useQuery`. */
17714
17970
  var usePipelineExecutorGetOrchestratorConfigSchema = trpc.pipelineExecutor.getOrchestratorConfigSchema.useQuery;
17971
+ /** Generated alias around `trpc.pipelineExecutor.validatePipeline.useQuery`. */
17972
+ var usePipelineExecutorValidatePipeline = trpc.pipelineExecutor.validatePipeline.useQuery;
17715
17973
  /** Generated alias around `trpc.pipelineExecutor.listTemplates.useQuery`. */
17716
17974
  var usePipelineExecutorListTemplates = trpc.pipelineExecutor.listTemplates.useQuery;
17717
17975
  /** Generated alias around `trpc.pipelineExecutor.saveTemplate.useMutation`. */
@@ -17782,6 +18040,8 @@ var usePipelineOrchestratorGetCameraMetrics = trpc.pipelineOrchestrator.getCamer
17782
18040
  var usePipelineOrchestratorGetCapabilityBindings = trpc.pipelineOrchestrator.getCapabilityBindings.useQuery;
17783
18041
  /** Generated alias around `trpc.pipelineOrchestrator.setCapabilityBinding.useMutation`. */
17784
18042
  var usePipelineOrchestratorSetCapabilityBinding = trpc.pipelineOrchestrator.setCapabilityBinding.useMutation;
18043
+ /** Generated alias around `trpc.pipelineOrchestrator.getIngestOwner.useQuery`. */
18044
+ var usePipelineOrchestratorGetIngestOwner = trpc.pipelineOrchestrator.getIngestOwner.useQuery;
17785
18045
  /** Generated alias around `trpc.pipelineOrchestrator.assignDecoder.useMutation`. */
17786
18046
  var usePipelineOrchestratorAssignDecoder = trpc.pipelineOrchestrator.assignDecoder.useMutation;
17787
18047
  /** Generated alias around `trpc.pipelineOrchestrator.unassignDecoder.useMutation`. */
@@ -17814,6 +18074,8 @@ var usePipelineOrchestratorSetAgentMaxCameras = trpc.pipelineOrchestrator.setAge
17814
18074
  var usePipelineOrchestratorSetAgentDetectWeight = trpc.pipelineOrchestrator.setAgentDetectWeight.useMutation;
17815
18075
  /** Generated alias around `trpc.pipelineOrchestrator.setAgentCapabilities.useMutation`. */
17816
18076
  var usePipelineOrchestratorSetAgentCapabilities = trpc.pipelineOrchestrator.setAgentCapabilities.useMutation;
18077
+ /** Generated alias around `trpc.pipelineOrchestrator.setAgentReachableHost.useMutation`. */
18078
+ var usePipelineOrchestratorSetAgentReachableHost = trpc.pipelineOrchestrator.setAgentReachableHost.useMutation;
17817
18079
  /** Generated alias around `trpc.pipelineOrchestrator.getCameraSettings.useQuery`. */
17818
18080
  var usePipelineOrchestratorGetCameraSettings = trpc.pipelineOrchestrator.getCameraSettings.useQuery;
17819
18081
  /** Generated alias around `trpc.pipelineOrchestrator.setCameraStepToggle.useMutation`. */
@@ -17988,10 +18250,6 @@ var useSnapshotGetDeviceSettingsContribution = trpc.snapshot.getDeviceSettingsCo
17988
18250
  var useSnapshotGetDeviceLiveContribution = trpc.snapshot.getDeviceLiveContribution.useQuery;
17989
18251
  /** Generated alias around `trpc.snapshot.applyDeviceSettingsPatch.useMutation`. */
17990
18252
  var useSnapshotApplyDeviceSettingsPatch = trpc.snapshot.applyDeviceSettingsPatch.useMutation;
17991
- /** Generated alias around `trpc.snapshotProvider.supportsDevice.useQuery`. */
17992
- var useSnapshotProviderSupportsDevice = trpc.snapshotProvider.supportsDevice.useQuery;
17993
- /** Generated alias around `trpc.snapshotProvider.getSnapshot.useQuery`. */
17994
- var useSnapshotProviderGetSnapshot = trpc.snapshotProvider.getSnapshot.useQuery;
17995
18253
  /** Generated alias around `trpc.storage.resolve.useQuery`. */
17996
18254
  var useStorageResolve = trpc.storage.resolve.useQuery;
17997
18255
  /** Generated alias around `trpc.storage.write.useMutation`. */
@@ -30042,10 +30300,11 @@ function PlaceholderStep({ addon, onClick }) {
30042
30300
  })
30043
30301
  });
30044
30302
  }
30045
- function PipelineBuilder({ schema, steps, onChange, templates, selectedTemplateId, onSelectTemplate, onSaveTemplate, onUpdateTemplate, onDeleteTemplate, readOnly = false, excludeAddons = [], hideTemplates = false, showOnlyEnabled = false, showSlotLabels = false, toggleMode = "simple", overrides = {}, onOverrideChange, inheritedEnabledByAddon = {}, hideModelAndSettings = false }) {
30303
+ function PipelineBuilder({ schema, steps, onChange, templates, selectedTemplateId, onSelectTemplate, onSaveTemplate, onUpdateTemplate, onDeleteTemplate, readOnly = false, excludeAddons = [], hideTemplates = false, showOnlyEnabled = false, showSlotLabels = false, toggleMode = "simple", overrides = {}, onOverrideChange, inheritedEnabledByAddon = {}, hideModelAndSettings = false, allowAutoModel = false }) {
30046
30304
  const stepExtraProps = (addonId) => ({
30047
30305
  toggleMode,
30048
30306
  hideModelAndSettings,
30307
+ allowAutoModel,
30049
30308
  ...toggleMode === "threeState" ? {
30050
30309
  overrideState: overrides[addonId] !== void 0 ? overrides[addonId] : null,
30051
30310
  onOverrideChange: onOverrideChange ? (next) => onOverrideChange(addonId, next) : void 0,
@@ -33278,7 +33537,7 @@ function ScheduleBandsEditor({ schedules, onChange }) {
33278
33537
  className: "space-y-2",
33279
33538
  children: [schedules.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
33280
33539
  className: "text-[11px] text-foreground-subtle",
33281
- children: "Sempre (24/7) — aggiungi una fascia per limitare gli orari."
33540
+ children: "Always (24/7) — add a band to restrict hours."
33282
33541
  }) : schedules.map((band, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BandRow, {
33283
33542
  band,
33284
33543
  onChange: (b) => replaceAt(i, b),
@@ -33287,7 +33546,7 @@ function ScheduleBandsEditor({ schedules, onChange }) {
33287
33546
  type: "button",
33288
33547
  onClick: addBand,
33289
33548
  className: "flex items-center gap-1 rounded-md bg-surface-hover px-2 py-1 text-[11px] text-foreground-subtle hover:text-foreground",
33290
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Plus, { className: "h-3 w-3" }), " Aggiungi fascia"]
33549
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Plus, { className: "h-3 w-3" }), " Add band"]
33291
33550
  })]
33292
33551
  });
33293
33552
  }
@@ -33297,18 +33556,18 @@ function BandRow({ band, onChange, onRemove }) {
33297
33556
  children: [
33298
33557
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
33299
33558
  className: "flex-1",
33300
- children: "Sempre"
33559
+ children: "Always"
33301
33560
  }),
33302
33561
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
33303
33562
  type: "button",
33304
33563
  onClick: () => onChange(newBand()),
33305
33564
  className: "text-foreground-subtle hover:text-foreground underline",
33306
- children: "imposta fascia"
33565
+ children: "Set band"
33307
33566
  }),
33308
33567
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
33309
33568
  type: "button",
33310
33569
  onClick: onRemove,
33311
- "aria-label": "Rimuovi fascia",
33570
+ "aria-label": "Remove band",
33312
33571
  className: "text-foreground-subtle hover:text-red-500",
33313
33572
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Trash2, { className: "h-3.5 w-3.5" })
33314
33573
  })
@@ -33353,7 +33612,7 @@ function BandRow({ band, onChange, onRemove }) {
33353
33612
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
33354
33613
  type: "button",
33355
33614
  onClick: onRemove,
33356
- "aria-label": "Rimuovi fascia",
33615
+ "aria-label": "Remove band",
33357
33616
  className: "text-foreground-subtle hover:text-red-500",
33358
33617
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Trash2, { className: "h-3.5 w-3.5" })
33359
33618
  })
@@ -33369,7 +33628,7 @@ function BandRow({ band, onChange, onRemove }) {
33369
33628
  }, d.value);
33370
33629
  }), days.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
33371
33630
  className: "self-center text-[10px] text-foreground-subtle",
33372
- children: "tutti i giorni"
33631
+ children: "every day"
33373
33632
  }) : null]
33374
33633
  })]
33375
33634
  });
@@ -33415,7 +33674,7 @@ function RecordingSettings({ initial, saving, onSave }) {
33415
33674
  });
33416
33675
  const numOrUndef = (v) => v === "" ? void 0 : Number(v);
33417
33676
  const toggleProfile = (p) => {
33418
- const cur = common.profiles ?? [];
33677
+ const cur = common.profiles ?? [...PROFILES];
33419
33678
  const next = cur.includes(p) ? cur.filter((x) => x !== p) : [...cur, p];
33420
33679
  setCommon({
33421
33680
  ...common,
@@ -33593,7 +33852,7 @@ function RecordingSettings({ initial, saving, onSave }) {
33593
33852
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
33594
33853
  type: "button",
33595
33854
  onClick: () => toggleProfile(p),
33596
- className: `rounded px-2 py-1 ${(common.profiles ?? []).includes(p) ? "bg-primary text-primary-foreground" : "bg-surface-hover text-foreground-subtle"}`,
33855
+ className: `rounded px-2 py-1 ${common.profiles == null || common.profiles.includes(p) ? "bg-primary text-primary-foreground" : "bg-surface-hover text-foreground-subtle"}`,
33597
33856
  children: p
33598
33857
  }, p);
33599
33858
  })]
@@ -34136,7 +34395,7 @@ function CoverageTrack({ windowFrom, windowTo, spans, playheadMs, onSeek, onScru
34136
34395
  const left = pctForMs(s.startMs, windowFrom, windowTo);
34137
34396
  const right = pctForMs(s.endMs, windowFrom, windowTo);
34138
34397
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
34139
- "data-testid": "coverage-fascia",
34398
+ "data-testid": "coverage-band",
34140
34399
  className: "absolute inset-y-0 bg-gradient-to-b from-primary to-primary/80",
34141
34400
  style: {
34142
34401
  left: `${left}%`,
@@ -45158,6 +45417,7 @@ exports.GRID_GAP = GRID_GAP;
45158
45417
  exports.GRID_PAIRED = GRID_PAIRED;
45159
45418
  exports.GRID_QUICK_STATS = GRID_QUICK_STATS;
45160
45419
  exports.GripTrack = GripTrack;
45420
+ exports.GroupedModelSelector = GroupedModelSelector;
45161
45421
  exports.HOST_WIDGETS = HOST_WIDGETS;
45162
45422
  exports.HlsVideo = HlsVideo;
45163
45423
  exports.HoverZoomImage = HoverZoomImage;
@@ -45886,6 +46146,7 @@ exports.usePipelineExecutorListLoadedEngines = usePipelineExecutorListLoadedEngi
45886
46146
  exports.usePipelineExecutorListReferenceImages = usePipelineExecutorListReferenceImages;
45887
46147
  exports.usePipelineExecutorListTemplates = usePipelineExecutorListTemplates;
45888
46148
  exports.usePipelineExecutorReprobeEngine = usePipelineExecutorReprobeEngine;
46149
+ exports.usePipelineExecutorResetToDefault = usePipelineExecutorResetToDefault;
45889
46150
  exports.usePipelineExecutorRunAudioTest = usePipelineExecutorRunAudioTest;
45890
46151
  exports.usePipelineExecutorRunPipeline = usePipelineExecutorRunPipeline;
45891
46152
  exports.usePipelineExecutorRunPipelineBatch = usePipelineExecutorRunPipelineBatch;
@@ -45894,6 +46155,7 @@ exports.usePipelineExecutorSetVideoPipelineSteps = usePipelineExecutorSetVideoPi
45894
46155
  exports.usePipelineExecutorSpinEngine = usePipelineExecutorSpinEngine;
45895
46156
  exports.usePipelineExecutorUncacheFrame = usePipelineExecutorUncacheFrame;
45896
46157
  exports.usePipelineExecutorUpdateTemplate = usePipelineExecutorUpdateTemplate;
46158
+ exports.usePipelineExecutorValidatePipeline = usePipelineExecutorValidatePipeline;
45897
46159
  exports.usePipelineOrchestratorApplyDeviceSettingsPatch = usePipelineOrchestratorApplyDeviceSettingsPatch;
45898
46160
  exports.usePipelineOrchestratorAssignAudio = usePipelineOrchestratorAssignAudio;
45899
46161
  exports.usePipelineOrchestratorAssignDecoder = usePipelineOrchestratorAssignDecoder;
@@ -45915,6 +46177,7 @@ exports.usePipelineOrchestratorGetDecoderAssignments = usePipelineOrchestratorGe
45915
46177
  exports.usePipelineOrchestratorGetDeviceLiveContribution = usePipelineOrchestratorGetDeviceLiveContribution;
45916
46178
  exports.usePipelineOrchestratorGetDeviceSettingsContribution = usePipelineOrchestratorGetDeviceSettingsContribution;
45917
46179
  exports.usePipelineOrchestratorGetGlobalMetrics = usePipelineOrchestratorGetGlobalMetrics;
46180
+ exports.usePipelineOrchestratorGetIngestOwner = usePipelineOrchestratorGetIngestOwner;
45918
46181
  exports.usePipelineOrchestratorGetPipelineAssignment = usePipelineOrchestratorGetPipelineAssignment;
45919
46182
  exports.usePipelineOrchestratorGetPipelineAssignments = usePipelineOrchestratorGetPipelineAssignments;
45920
46183
  exports.usePipelineOrchestratorListAgentSettings = usePipelineOrchestratorListAgentSettings;
@@ -45927,6 +46190,7 @@ exports.usePipelineOrchestratorSetAgentAddonDefaults = usePipelineOrchestratorSe
45927
46190
  exports.usePipelineOrchestratorSetAgentCapabilities = usePipelineOrchestratorSetAgentCapabilities;
45928
46191
  exports.usePipelineOrchestratorSetAgentDetectWeight = usePipelineOrchestratorSetAgentDetectWeight;
45929
46192
  exports.usePipelineOrchestratorSetAgentMaxCameras = usePipelineOrchestratorSetAgentMaxCameras;
46193
+ exports.usePipelineOrchestratorSetAgentReachableHost = usePipelineOrchestratorSetAgentReachableHost;
45930
46194
  exports.usePipelineOrchestratorSetCameraPipelineForAgent = usePipelineOrchestratorSetCameraPipelineForAgent;
45931
46195
  exports.usePipelineOrchestratorSetCameraStepOverride = usePipelineOrchestratorSetCameraStepOverride;
45932
46196
  exports.usePipelineOrchestratorSetCameraStepToggle = usePipelineOrchestratorSetCameraStepToggle;
@@ -46014,8 +46278,6 @@ exports.useSnapshotGetDeviceSettingsContribution = useSnapshotGetDeviceSettingsC
46014
46278
  exports.useSnapshotGetSnapshot = useSnapshotGetSnapshot;
46015
46279
  exports.useSnapshotGetStatus = useSnapshotGetStatus;
46016
46280
  exports.useSnapshotInvalidateCache = useSnapshotInvalidateCache;
46017
- exports.useSnapshotProviderGetSnapshot = useSnapshotProviderGetSnapshot;
46018
- exports.useSnapshotProviderSupportsDevice = useSnapshotProviderSupportsDevice;
46019
46281
  exports.useStorageAbortUpload = useStorageAbortUpload;
46020
46282
  exports.useStorageBeginDownload = useStorageBeginDownload;
46021
46283
  exports.useStorageBeginUpload = useStorageBeginUpload;