@camstack/ui-library 1.2.206 → 1.2.207
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/composites/extensions/AssociationSlotCard.d.ts +15 -0
- package/dist/composites/extensions/ExtensionsPanel.d.ts +4 -0
- package/dist/composites/extensions/extension-invalidation.d.ts +9 -0
- package/dist/composites/extensions/extensions-view-state.d.ts +40 -0
- package/dist/composites/index.d.ts +1 -0
- package/dist/generated/system-hooks.d.ts +10 -0
- package/dist/index.cjs +452 -1
- package/dist/index.js +446 -3
- package/package.json +1 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ExtensionSlotSource, ExtensionSlotState } from '@camstack/types';
|
|
2
|
+
export interface SlotSourceListProps {
|
|
3
|
+
readonly sources: readonly ExtensionSlotSource[];
|
|
4
|
+
}
|
|
5
|
+
/** The saved sources, each with its health — a bad one is shown, never hidden. */
|
|
6
|
+
export declare function SlotSourceList({ sources }: SlotSourceListProps): import("react").JSX.Element;
|
|
7
|
+
export interface AssociationSlotCardProps {
|
|
8
|
+
readonly deviceId: number;
|
|
9
|
+
readonly row: ExtensionSlotState;
|
|
10
|
+
readonly onSaved: () => void;
|
|
11
|
+
}
|
|
12
|
+
export interface ActivationLineProps {
|
|
13
|
+
readonly row: ExtensionSlotState;
|
|
14
|
+
}
|
|
15
|
+
export declare function AssociationSlotCard({ deviceId, row, onSaved }: AssociationSlotCardProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
2
|
+
/** tRPC v11 query-key prefix of `deviceManager.getDeviceAggregate`. */
|
|
3
|
+
export declare const DEVICE_AGGREGATE_QUERY_KEY: readonly [readonly ["deviceManager", "getDeviceAggregate"]];
|
|
4
|
+
/** tRPC v11 query-key prefix of `deviceExtension.listSlots`. */
|
|
5
|
+
export declare const EXTENSION_SLOTS_QUERY_KEY: readonly [readonly ["deviceExtension", "listSlots"]];
|
|
6
|
+
/** The one method of a query client these helpers use. */
|
|
7
|
+
export type QueryInvalidator = Pick<QueryClient, 'invalidateQueries'>;
|
|
8
|
+
/** Re-read both surfaces over the linked-devices / doorbell stores. */
|
|
9
|
+
export declare function invalidateExtensionSurfaces(client: QueryInvalidator): Promise<void>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ExtensionCandidate, ExtensionSlotCardinality, ExtensionSlotRow, ExtensionSlotState, ExtensionSlotUnreachable } from '@camstack/types';
|
|
2
|
+
/** The one field of a query error this module reads. */
|
|
3
|
+
export interface ExtensionsQueryError {
|
|
4
|
+
readonly message: string;
|
|
5
|
+
}
|
|
6
|
+
/** The fields of a query result this module reads — nothing else. */
|
|
7
|
+
export interface ExtensionsQueryView {
|
|
8
|
+
readonly status: 'pending' | 'error' | 'success';
|
|
9
|
+
readonly data?: readonly ExtensionSlotRow[] | undefined;
|
|
10
|
+
readonly error?: ExtensionsQueryError | null;
|
|
11
|
+
}
|
|
12
|
+
/** Nobody has answered yet. */
|
|
13
|
+
export interface ExtensionsPendingView {
|
|
14
|
+
readonly kind: 'pending';
|
|
15
|
+
}
|
|
16
|
+
/** The read FAILED — not an answer, so not absence either. */
|
|
17
|
+
export interface ExtensionsUnknownView {
|
|
18
|
+
readonly kind: 'unknown';
|
|
19
|
+
readonly reason: string;
|
|
20
|
+
}
|
|
21
|
+
/** Answered with nothing — the only state that may say "no extensions". */
|
|
22
|
+
export interface ExtensionsNoneView {
|
|
23
|
+
readonly kind: 'none';
|
|
24
|
+
}
|
|
25
|
+
/** Cards in table order, and every owner that could not answer. */
|
|
26
|
+
export interface ExtensionsRowsView {
|
|
27
|
+
readonly kind: 'rows';
|
|
28
|
+
readonly slots: readonly ExtensionSlotState[];
|
|
29
|
+
readonly unreachable: readonly ExtensionSlotUnreachable[];
|
|
30
|
+
}
|
|
31
|
+
export type ExtensionsView = ExtensionsPendingView | ExtensionsUnknownView | ExtensionsNoneView | ExtensionsRowsView;
|
|
32
|
+
export declare function resolveExtensionsView(query: ExtensionsQueryView): ExtensionsView;
|
|
33
|
+
/** Add or remove one pick. `one` replaces; `many` toggles. */
|
|
34
|
+
export declare function togglePick(draft: readonly number[], deviceId: number, cardinality: ExtensionSlotCardinality): readonly number[];
|
|
35
|
+
/** Suggested candidates the operator has NOT picked — shown to confirm, never saved on their own (D356). */
|
|
36
|
+
export declare function pendingSuggestions(candidates: readonly ExtensionCandidate[], draft: readonly number[]): readonly ExtensionCandidate[];
|
|
37
|
+
/** Candidates matching a free-text search, not already picked. */
|
|
38
|
+
export declare function searchCandidates(candidates: readonly ExtensionCandidate[], draft: readonly number[], query: string): readonly ExtensionCandidate[];
|
|
39
|
+
/** Whether the draft differs from what the owner's store holds. */
|
|
40
|
+
export declare function isDirty(saved: readonly number[], draft: readonly number[]): boolean;
|
|
@@ -169,3 +169,4 @@ export * from './version-badge';
|
|
|
169
169
|
export * from './widget-panel.js';
|
|
170
170
|
export type { WidgetSlotProps } from './widget-slot';
|
|
171
171
|
export { WidgetSlot } from './widget-slot';
|
|
172
|
+
export { DEVICE_AGGREGATE_QUERY_KEY, EXTENSION_SLOTS_QUERY_KEY, invalidateExtensionSurfaces, type QueryInvalidator, } from './extensions/extension-invalidation.js';
|
|
@@ -423,6 +423,14 @@ export declare const useDeviceExportGetDeviceSettingsContribution: typeof trpc.d
|
|
|
423
423
|
export declare const useDeviceExportGetDeviceLiveContribution: typeof trpc.deviceExport.getDeviceLiveContribution.useQuery;
|
|
424
424
|
/** Generated alias around `trpc.deviceExport.applyDeviceSettingsPatch.useMutation`. */
|
|
425
425
|
export declare const useDeviceExportApplyDeviceSettingsPatch: typeof trpc.deviceExport.applyDeviceSettingsPatch.useMutation;
|
|
426
|
+
/** Generated alias around `trpc.deviceExtension.listSources.useQuery`. */
|
|
427
|
+
export declare const useDeviceExtensionListSources: typeof trpc.deviceExtension.listSources.useQuery;
|
|
428
|
+
/** Generated alias around `trpc.deviceExtension.listSlots.useQuery`. */
|
|
429
|
+
export declare const useDeviceExtensionListSlots: typeof trpc.deviceExtension.listSlots.useQuery;
|
|
430
|
+
/** Generated alias around `trpc.deviceExtension.listCandidates.useQuery`. */
|
|
431
|
+
export declare const useDeviceExtensionListCandidates: typeof trpc.deviceExtension.listCandidates.useQuery;
|
|
432
|
+
/** Generated alias around `trpc.deviceExtension.setSlot.useMutation`. */
|
|
433
|
+
export declare const useDeviceExtensionSetSlot: typeof trpc.deviceExtension.setSlot.useMutation;
|
|
426
434
|
/** Generated alias around `trpc.deviceManager.allocateDeviceId.useMutation`. */
|
|
427
435
|
export declare const useDeviceManagerAllocateDeviceId: typeof trpc.deviceManager.allocateDeviceId.useMutation;
|
|
428
436
|
/** Generated alias around `trpc.deviceManager.migrateDevice.useMutation`. */
|
|
@@ -1385,6 +1393,8 @@ export declare const usePipelineOrchestratorGetPipelineAssignments: typeof trpc.
|
|
|
1385
1393
|
export declare const usePipelineOrchestratorGetPipelineAssignment: typeof trpc.pipelineOrchestrator.getPipelineAssignment.useQuery;
|
|
1386
1394
|
/** Generated alias around `trpc.pipelineOrchestrator.getAgentLoad.useQuery`. */
|
|
1387
1395
|
export declare const usePipelineOrchestratorGetAgentLoad: typeof trpc.pipelineOrchestrator.getAgentLoad.useQuery;
|
|
1396
|
+
/** Generated alias around `trpc.pipelineOrchestrator.getClusterModelChoice.useQuery`. */
|
|
1397
|
+
export declare const usePipelineOrchestratorGetClusterModelChoice: typeof trpc.pipelineOrchestrator.getClusterModelChoice.useQuery;
|
|
1388
1398
|
/** Generated alias around `trpc.pipelineOrchestrator.getGlobalMetrics.useQuery`. */
|
|
1389
1399
|
export declare const usePipelineOrchestratorGetGlobalMetrics: typeof trpc.pipelineOrchestrator.getGlobalMetrics.useQuery;
|
|
1390
1400
|
/** Generated alias around `trpc.pipelineOrchestrator.getCameraMetrics.useQuery`. */
|
package/dist/index.cjs
CHANGED
|
@@ -4100,6 +4100,16 @@ var Projector = createLucideIcon("projector", [
|
|
|
4100
4100
|
* This source code is licensed under the ISC license.
|
|
4101
4101
|
* See the LICENSE file in the root directory of this source tree.
|
|
4102
4102
|
*/
|
|
4103
|
+
var Puzzle = createLucideIcon("puzzle", [["path", {
|
|
4104
|
+
d: "M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z",
|
|
4105
|
+
key: "w46dr5"
|
|
4106
|
+
}]]);
|
|
4107
|
+
/**
|
|
4108
|
+
* @license lucide-react v0.576.0 - ISC
|
|
4109
|
+
*
|
|
4110
|
+
* This source code is licensed under the ISC license.
|
|
4111
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
4112
|
+
*/
|
|
4103
4113
|
var QrCode$1 = createLucideIcon("qr-code", [
|
|
4104
4114
|
["rect", {
|
|
4105
4115
|
width: "5",
|
|
@@ -6932,6 +6942,14 @@ var useDeviceExportGetDeviceSettingsContribution = trpc.deviceExport.getDeviceSe
|
|
|
6932
6942
|
var useDeviceExportGetDeviceLiveContribution = trpc.deviceExport.getDeviceLiveContribution.useQuery;
|
|
6933
6943
|
/** Generated alias around `trpc.deviceExport.applyDeviceSettingsPatch.useMutation`. */
|
|
6934
6944
|
var useDeviceExportApplyDeviceSettingsPatch = trpc.deviceExport.applyDeviceSettingsPatch.useMutation;
|
|
6945
|
+
/** Generated alias around `trpc.deviceExtension.listSources.useQuery`. */
|
|
6946
|
+
var useDeviceExtensionListSources = trpc.deviceExtension.listSources.useQuery;
|
|
6947
|
+
/** Generated alias around `trpc.deviceExtension.listSlots.useQuery`. */
|
|
6948
|
+
var useDeviceExtensionListSlots = trpc.deviceExtension.listSlots.useQuery;
|
|
6949
|
+
/** Generated alias around `trpc.deviceExtension.listCandidates.useQuery`. */
|
|
6950
|
+
var useDeviceExtensionListCandidates = trpc.deviceExtension.listCandidates.useQuery;
|
|
6951
|
+
/** Generated alias around `trpc.deviceExtension.setSlot.useMutation`. */
|
|
6952
|
+
var useDeviceExtensionSetSlot = trpc.deviceExtension.setSlot.useMutation;
|
|
6935
6953
|
/** Generated alias around `trpc.deviceManager.allocateDeviceId.useMutation`. */
|
|
6936
6954
|
var useDeviceManagerAllocateDeviceId = trpc.deviceManager.allocateDeviceId.useMutation;
|
|
6937
6955
|
/** Generated alias around `trpc.deviceManager.migrateDevice.useMutation`. */
|
|
@@ -7894,6 +7912,8 @@ var usePipelineOrchestratorGetPipelineAssignments = trpc.pipelineOrchestrator.ge
|
|
|
7894
7912
|
var usePipelineOrchestratorGetPipelineAssignment = trpc.pipelineOrchestrator.getPipelineAssignment.useQuery;
|
|
7895
7913
|
/** Generated alias around `trpc.pipelineOrchestrator.getAgentLoad.useQuery`. */
|
|
7896
7914
|
var usePipelineOrchestratorGetAgentLoad = trpc.pipelineOrchestrator.getAgentLoad.useQuery;
|
|
7915
|
+
/** Generated alias around `trpc.pipelineOrchestrator.getClusterModelChoice.useQuery`. */
|
|
7916
|
+
var usePipelineOrchestratorGetClusterModelChoice = trpc.pipelineOrchestrator.getClusterModelChoice.useQuery;
|
|
7897
7917
|
/** Generated alias around `trpc.pipelineOrchestrator.getGlobalMetrics.useQuery`. */
|
|
7898
7918
|
var usePipelineOrchestratorGetGlobalMetrics = trpc.pipelineOrchestrator.getGlobalMetrics.useQuery;
|
|
7899
7919
|
/** Generated alias around `trpc.pipelineOrchestrator.getCameraMetrics.useQuery`. */
|
|
@@ -20896,6 +20916,428 @@ function ClipsSection({ deviceId }) {
|
|
|
20896
20916
|
});
|
|
20897
20917
|
}
|
|
20898
20918
|
//#endregion
|
|
20919
|
+
//#region src/composites/extensions/extension-invalidation.ts
|
|
20920
|
+
/** tRPC v11 query-key prefix of `deviceManager.getDeviceAggregate`. */
|
|
20921
|
+
var DEVICE_AGGREGATE_QUERY_KEY = [["deviceManager", "getDeviceAggregate"]];
|
|
20922
|
+
/** tRPC v11 query-key prefix of `deviceExtension.listSlots`. */
|
|
20923
|
+
var EXTENSION_SLOTS_QUERY_KEY = [["deviceExtension", "listSlots"]];
|
|
20924
|
+
/** Re-read both surfaces over the linked-devices / doorbell stores. */
|
|
20925
|
+
async function invalidateExtensionSurfaces(client) {
|
|
20926
|
+
await Promise.all([client.invalidateQueries({ queryKey: DEVICE_AGGREGATE_QUERY_KEY }), client.invalidateQueries({ queryKey: EXTENSION_SLOTS_QUERY_KEY })]);
|
|
20927
|
+
}
|
|
20928
|
+
//#endregion
|
|
20929
|
+
//#region src/composites/extensions/extensions-view-state.ts
|
|
20930
|
+
/**
|
|
20931
|
+
* What the Extensions section may CLAIM, from what `listSlots` answered
|
|
20932
|
+
* (D648, D315).
|
|
20933
|
+
*
|
|
20934
|
+
* Four states, and the two a boolean would collapse are kept apart on purpose:
|
|
20935
|
+
*
|
|
20936
|
+
* - `pending` — nobody has answered yet. Never "no extensions".
|
|
20937
|
+
* - `unknown` — the query FAILED. It is not an answer, so it is not absence
|
|
20938
|
+
* either; the reason is shown verbatim.
|
|
20939
|
+
* - `none` — the query answered with nothing. The only state that may say
|
|
20940
|
+
* "no extensions".
|
|
20941
|
+
* - `rows` — cards, in the generated table's order, and every owner that
|
|
20942
|
+
* could not answer as its own row with its reason (D554.4). A device whose
|
|
20943
|
+
* ONLY owner failed is `rows` with no slots, not `none`.
|
|
20944
|
+
*
|
|
20945
|
+
* Also here, pure: the editor's draft rules, so the component holds no logic
|
|
20946
|
+
* a spec cannot reach.
|
|
20947
|
+
*/
|
|
20948
|
+
function tableOrder(slot) {
|
|
20949
|
+
return _camstack_types.EXTENSION_SLOT_IDS.indexOf(slot);
|
|
20950
|
+
}
|
|
20951
|
+
function resolveExtensionsView(query) {
|
|
20952
|
+
if (query.status === "pending") return { kind: "pending" };
|
|
20953
|
+
if (query.status === "error") return {
|
|
20954
|
+
kind: "unknown",
|
|
20955
|
+
reason: query.error?.message ?? "the request failed"
|
|
20956
|
+
};
|
|
20957
|
+
const rows = query.data ?? [];
|
|
20958
|
+
if (rows.length === 0) return { kind: "none" };
|
|
20959
|
+
const slots = [];
|
|
20960
|
+
const unreachable = [];
|
|
20961
|
+
for (const row of rows) if (row.state === "ok") slots.push(row);
|
|
20962
|
+
else unreachable.push(row);
|
|
20963
|
+
return {
|
|
20964
|
+
kind: "rows",
|
|
20965
|
+
slots: slots.toSorted((a, b) => tableOrder(a.slot) - tableOrder(b.slot)),
|
|
20966
|
+
unreachable
|
|
20967
|
+
};
|
|
20968
|
+
}
|
|
20969
|
+
/** Add or remove one pick. `one` replaces; `many` toggles. */
|
|
20970
|
+
function togglePick(draft, deviceId, cardinality) {
|
|
20971
|
+
if (draft.includes(deviceId)) return draft.filter((id) => id !== deviceId);
|
|
20972
|
+
return cardinality === "one" ? [deviceId] : [...draft, deviceId];
|
|
20973
|
+
}
|
|
20974
|
+
/** Suggested candidates the operator has NOT picked — shown to confirm, never saved on their own (D356). */
|
|
20975
|
+
function pendingSuggestions(candidates, draft) {
|
|
20976
|
+
return candidates.filter((c) => c.suggested && !draft.includes(c.deviceId));
|
|
20977
|
+
}
|
|
20978
|
+
/** Candidates matching a free-text search, not already picked. */
|
|
20979
|
+
function searchCandidates(candidates, draft, query) {
|
|
20980
|
+
const needle = query.trim().toLowerCase();
|
|
20981
|
+
if (needle.length === 0) return [];
|
|
20982
|
+
return candidates.filter((c) => !draft.includes(c.deviceId) && [
|
|
20983
|
+
c.name,
|
|
20984
|
+
c.location ?? "",
|
|
20985
|
+
c.parentName ?? "",
|
|
20986
|
+
c.type
|
|
20987
|
+
].some((v) => v.toLowerCase().includes(needle)));
|
|
20988
|
+
}
|
|
20989
|
+
/** Whether the draft differs from what the owner's store holds. */
|
|
20990
|
+
function isDirty(saved, draft) {
|
|
20991
|
+
return saved.length !== draft.length || saved.some((id, i) => draft[i] !== id);
|
|
20992
|
+
}
|
|
20993
|
+
//#endregion
|
|
20994
|
+
//#region src/composites/extensions/AssociationSlotCard.tsx
|
|
20995
|
+
/**
|
|
20996
|
+
* One ASSOCIATION slot (D648): the devices a host lists, edited as a device
|
|
20997
|
+
* multiselect.
|
|
20998
|
+
*
|
|
20999
|
+
* - The saved value is the owner's store, read by `listSlots`. The draft is
|
|
21000
|
+
* local until Save, and Save is `setSlot` — the owner validates and writes
|
|
21001
|
+
* through its existing path, so a refusal comes back BY NAME and is shown.
|
|
21002
|
+
* - Candidates (`listCandidates`) are fetched only while editing. Suggestions
|
|
21003
|
+
* are chips the operator must click to add; nothing is picked on its own
|
|
21004
|
+
* (D356).
|
|
21005
|
+
* - Every saved source shows its health; a missing or unavailable one is
|
|
21006
|
+
* shown with its reason and never silently dropped from the draft.
|
|
21007
|
+
* - A gate owned by ANOTHER authority (the doorbell wrapper's binding) is
|
|
21008
|
+
* shown read-only, naming that authority (D62).
|
|
21009
|
+
*/
|
|
21010
|
+
var HEALTH_LABEL = {
|
|
21011
|
+
ok: "OK",
|
|
21012
|
+
missing: "Missing",
|
|
21013
|
+
foreign: "Other owner",
|
|
21014
|
+
unavailable: "Not a valid source"
|
|
21015
|
+
};
|
|
21016
|
+
var HEALTH_VARIANT = {
|
|
21017
|
+
ok: "success",
|
|
21018
|
+
missing: "danger",
|
|
21019
|
+
foreign: "warning",
|
|
21020
|
+
unavailable: "warning"
|
|
21021
|
+
};
|
|
21022
|
+
/** The saved sources, each with its health — a bad one is shown, never hidden. */
|
|
21023
|
+
function SlotSourceList({ sources }) {
|
|
21024
|
+
if (sources.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
21025
|
+
className: "text-[11px] text-foreground-subtle italic",
|
|
21026
|
+
children: "No devices picked."
|
|
21027
|
+
});
|
|
21028
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
21029
|
+
className: "flex flex-col gap-1",
|
|
21030
|
+
children: sources.map((s) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
21031
|
+
className: "flex flex-wrap items-center gap-2 text-[11px]",
|
|
21032
|
+
children: [
|
|
21033
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
21034
|
+
className: "text-foreground",
|
|
21035
|
+
children: s.name ?? `Device ${s.deviceId}`
|
|
21036
|
+
}),
|
|
21037
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
21038
|
+
variant: HEALTH_VARIANT[s.health],
|
|
21039
|
+
children: HEALTH_LABEL[s.health]
|
|
21040
|
+
}),
|
|
21041
|
+
s.detail !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
21042
|
+
className: "text-[10px] text-foreground-subtle",
|
|
21043
|
+
children: s.detail
|
|
21044
|
+
})
|
|
21045
|
+
]
|
|
21046
|
+
}, s.deviceId))
|
|
21047
|
+
});
|
|
21048
|
+
}
|
|
21049
|
+
function ActivationLine({ row }) {
|
|
21050
|
+
const activation = row.activation;
|
|
21051
|
+
if (activation === null) return null;
|
|
21052
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
21053
|
+
className: "flex flex-wrap items-center gap-2 text-[10px] text-foreground-subtle",
|
|
21054
|
+
children: [
|
|
21055
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
21056
|
+
variant: activation.state === "active" ? "success" : activation.state === "inactive" ? "warning" : "default",
|
|
21057
|
+
children: activation.state === "active" ? "Active" : activation.state === "inactive" ? "Inactive" : "Unknown"
|
|
21058
|
+
}),
|
|
21059
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["set by ", activation.authority] }),
|
|
21060
|
+
activation.detail !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: activation.detail })
|
|
21061
|
+
]
|
|
21062
|
+
});
|
|
21063
|
+
}
|
|
21064
|
+
function AssociationSlotCard({ deviceId, row, onSaved }) {
|
|
21065
|
+
const descriptor = _camstack_types.EXTENSION_SLOTS[row.slot].descriptor;
|
|
21066
|
+
const saved = row.value.deviceIds;
|
|
21067
|
+
const [editing, setEditing] = (0, react$1.useState)(false);
|
|
21068
|
+
const [draft, setDraft] = (0, react$1.useState)(saved);
|
|
21069
|
+
const [search, setSearch] = (0, react$1.useState)("");
|
|
21070
|
+
const [refusal, setRefusal] = (0, react$1.useState)(null);
|
|
21071
|
+
const candidatesQuery = useDeviceExtensionListCandidates({
|
|
21072
|
+
deviceId,
|
|
21073
|
+
slotRef: row.slotRef
|
|
21074
|
+
}, { enabled: editing });
|
|
21075
|
+
const setSlot = useDeviceExtensionSetSlot();
|
|
21076
|
+
const queryClient = (0, _tanstack_react_query.useQueryClient)();
|
|
21077
|
+
const candidates = candidatesQuery.data?.candidates ?? [];
|
|
21078
|
+
const nameOf = (id) => candidates.find((c) => c.deviceId === id)?.name ?? row.sources.find((s) => s.deviceId === id)?.name ?? `Device ${id}`;
|
|
21079
|
+
const startEditing = () => {
|
|
21080
|
+
setDraft(saved);
|
|
21081
|
+
setRefusal(null);
|
|
21082
|
+
setEditing(true);
|
|
21083
|
+
};
|
|
21084
|
+
const save = async () => {
|
|
21085
|
+
setRefusal(null);
|
|
21086
|
+
try {
|
|
21087
|
+
await setSlot.mutateAsync({
|
|
21088
|
+
deviceId,
|
|
21089
|
+
slotRef: row.slotRef,
|
|
21090
|
+
value: {
|
|
21091
|
+
slot: row.value.slot,
|
|
21092
|
+
deviceIds: [...draft]
|
|
21093
|
+
}
|
|
21094
|
+
});
|
|
21095
|
+
setEditing(false);
|
|
21096
|
+
await invalidateExtensionSurfaces(queryClient);
|
|
21097
|
+
onSaved();
|
|
21098
|
+
} catch (err) {
|
|
21099
|
+
setRefusal(err instanceof Error ? err.message : String(err));
|
|
21100
|
+
}
|
|
21101
|
+
};
|
|
21102
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
21103
|
+
role: "group",
|
|
21104
|
+
"aria-label": descriptor.label,
|
|
21105
|
+
className: "flex flex-col gap-2 rounded-md border border-border/40 bg-surface-elevated/30 p-3",
|
|
21106
|
+
children: [
|
|
21107
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
21108
|
+
className: "flex items-start justify-between gap-2",
|
|
21109
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
21110
|
+
className: "flex flex-col gap-0.5",
|
|
21111
|
+
children: [
|
|
21112
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
21113
|
+
className: "text-xs font-semibold text-foreground",
|
|
21114
|
+
children: descriptor.label
|
|
21115
|
+
}),
|
|
21116
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
21117
|
+
className: "text-[10px] text-foreground-subtle",
|
|
21118
|
+
children: descriptor.description
|
|
21119
|
+
}),
|
|
21120
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
21121
|
+
className: "text-[10px] text-foreground-subtle",
|
|
21122
|
+
children: ["Stored in ", row.authority]
|
|
21123
|
+
})
|
|
21124
|
+
]
|
|
21125
|
+
}), !editing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
21126
|
+
variant: "outline",
|
|
21127
|
+
size: "sm",
|
|
21128
|
+
onClick: startEditing,
|
|
21129
|
+
children: "Edit"
|
|
21130
|
+
})]
|
|
21131
|
+
}),
|
|
21132
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActivationLine, { row }),
|
|
21133
|
+
!editing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SlotSourceList, { sources: row.sources }),
|
|
21134
|
+
editing && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
21135
|
+
className: "flex flex-col gap-2",
|
|
21136
|
+
children: [
|
|
21137
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
21138
|
+
"aria-label": "Picked devices",
|
|
21139
|
+
className: "flex flex-wrap gap-1.5",
|
|
21140
|
+
children: draft.map((id) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
21141
|
+
type: "button",
|
|
21142
|
+
"aria-label": `Remove ${nameOf(id)}`,
|
|
21143
|
+
onClick: () => setDraft(togglePick(draft, id, descriptor.cardinality)),
|
|
21144
|
+
className: "inline-flex items-center gap-1 rounded-full bg-primary/15 px-2 py-0.5 text-[11px] text-foreground",
|
|
21145
|
+
children: [nameOf(id), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(X, { className: "h-3 w-3" })]
|
|
21146
|
+
}) }, id))
|
|
21147
|
+
}),
|
|
21148
|
+
candidatesQuery.status === "pending" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
21149
|
+
role: "status",
|
|
21150
|
+
className: "text-[10px] text-foreground-subtle",
|
|
21151
|
+
children: "Loading candidates…"
|
|
21152
|
+
}),
|
|
21153
|
+
candidatesQuery.status === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
21154
|
+
role: "alert",
|
|
21155
|
+
className: "text-[10px] text-danger",
|
|
21156
|
+
children: ["Candidates could not be read: ", candidatesQuery.error.message]
|
|
21157
|
+
}),
|
|
21158
|
+
pendingSuggestions(candidates, draft).length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
21159
|
+
className: "flex flex-col gap-1",
|
|
21160
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
21161
|
+
className: "text-[10px] text-foreground-subtle",
|
|
21162
|
+
children: "Suggested — added only if you click them:"
|
|
21163
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
21164
|
+
"aria-label": "Suggestions",
|
|
21165
|
+
className: "flex flex-wrap gap-1.5",
|
|
21166
|
+
children: pendingSuggestions(candidates, draft).map((c) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
21167
|
+
type: "button",
|
|
21168
|
+
"aria-label": `Add ${c.name}`,
|
|
21169
|
+
onClick: () => setDraft(togglePick(draft, c.deviceId, descriptor.cardinality)),
|
|
21170
|
+
className: "inline-flex items-center gap-1 rounded-full border border-dashed border-border px-2 py-0.5 text-[11px] text-foreground-muted",
|
|
21171
|
+
children: [
|
|
21172
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Plus, { className: "h-3 w-3" }),
|
|
21173
|
+
c.name,
|
|
21174
|
+
c.reason !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
21175
|
+
className: "text-foreground-subtle",
|
|
21176
|
+
children: ["· ", c.reason]
|
|
21177
|
+
})
|
|
21178
|
+
]
|
|
21179
|
+
}) }, c.deviceId))
|
|
21180
|
+
})]
|
|
21181
|
+
}),
|
|
21182
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
21183
|
+
type: "search",
|
|
21184
|
+
"aria-label": "Search devices",
|
|
21185
|
+
value: search,
|
|
21186
|
+
onChange: (e) => setSearch(e.target.value),
|
|
21187
|
+
placeholder: "Search devices by name, location or type",
|
|
21188
|
+
className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs text-foreground outline-none focus:border-primary"
|
|
21189
|
+
}),
|
|
21190
|
+
searchCandidates(candidates, draft, search).length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
21191
|
+
"aria-label": "Search results",
|
|
21192
|
+
className: "flex max-h-40 flex-col gap-0.5 overflow-y-auto",
|
|
21193
|
+
children: searchCandidates(candidates, draft, search).map((c) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
21194
|
+
type: "button",
|
|
21195
|
+
onClick: () => {
|
|
21196
|
+
setDraft(togglePick(draft, c.deviceId, descriptor.cardinality));
|
|
21197
|
+
setSearch("");
|
|
21198
|
+
},
|
|
21199
|
+
className: "w-full rounded px-2 py-1 text-left text-[11px] text-foreground hover:bg-surface-hover",
|
|
21200
|
+
children: [
|
|
21201
|
+
c.name,
|
|
21202
|
+
c.parentName !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
21203
|
+
className: "text-foreground-subtle",
|
|
21204
|
+
children: [" in ", c.parentName]
|
|
21205
|
+
}),
|
|
21206
|
+
c.location !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
21207
|
+
className: "text-foreground-subtle",
|
|
21208
|
+
children: [" · ", c.location]
|
|
21209
|
+
})
|
|
21210
|
+
]
|
|
21211
|
+
}) }, c.deviceId))
|
|
21212
|
+
}),
|
|
21213
|
+
refusal !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
21214
|
+
role: "alert",
|
|
21215
|
+
className: "text-[11px] text-danger break-words",
|
|
21216
|
+
children: ["Not saved: ", refusal]
|
|
21217
|
+
}),
|
|
21218
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
21219
|
+
className: "flex justify-end gap-2",
|
|
21220
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
21221
|
+
variant: "ghost",
|
|
21222
|
+
size: "sm",
|
|
21223
|
+
onClick: () => setEditing(false),
|
|
21224
|
+
children: "Cancel"
|
|
21225
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
21226
|
+
size: "sm",
|
|
21227
|
+
disabled: !isDirty(saved, draft) || setSlot.isPending,
|
|
21228
|
+
onClick: () => void save(),
|
|
21229
|
+
children: "Save"
|
|
21230
|
+
})]
|
|
21231
|
+
})
|
|
21232
|
+
]
|
|
21233
|
+
})
|
|
21234
|
+
]
|
|
21235
|
+
});
|
|
21236
|
+
}
|
|
21237
|
+
//#endregion
|
|
21238
|
+
//#region src/composites/extensions/ExtensionsPanel.tsx
|
|
21239
|
+
/**
|
|
21240
|
+
* `host/extensions-panel` — what a device is extended with by OTHER devices,
|
|
21241
|
+
* in one place (D648).
|
|
21242
|
+
*
|
|
21243
|
+
* Mounted by the framework: `device-extension.cap.ts` declares
|
|
21244
|
+
* `deviceConfig.ui = { kind:'widget', widgetId:'host/extensions-panel',
|
|
21245
|
+
* tab:'general', order:72 }` and `deriveDeviceConfigContribution` emits the
|
|
21246
|
+
* section (D14). The panel STORES NOTHING: every card is one row of
|
|
21247
|
+
* `device-extension.listSlots`, read by the slot's owner from the store it
|
|
21248
|
+
* already has, and every save is `setSlot`, written by that owner through its
|
|
21249
|
+
* existing path. The hand-written "Linked devices" and "Virtual doorbell"
|
|
21250
|
+
* sections stay beside it until the live measurement says the two surfaces
|
|
21251
|
+
* agree for every camera (slice 1 of the design); both write the same store.
|
|
21252
|
+
*
|
|
21253
|
+
* Slice 1 renders ASSOCIATION cards only (a device multiselect). A `graft`
|
|
21254
|
+
* slot (slice 2) gets a read-only card here until its editor exists.
|
|
21255
|
+
*
|
|
21256
|
+
* Absence is claimed only from an answer (D315): pending, failed and empty
|
|
21257
|
+
* are three different sentences, and an owner that could not answer is shown
|
|
21258
|
+
* with its reason, verbatim — never dropped.
|
|
21259
|
+
*/
|
|
21260
|
+
function ExtensionsPanel({ deviceId }) {
|
|
21261
|
+
const query = useDeviceExtensionListSlots({ deviceId });
|
|
21262
|
+
const view = resolveExtensionsView({
|
|
21263
|
+
status: query.status,
|
|
21264
|
+
data: query.data,
|
|
21265
|
+
error: query.error
|
|
21266
|
+
});
|
|
21267
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WidgetPanel, {
|
|
21268
|
+
title: "Extensions",
|
|
21269
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Puzzle, { className: "h-3.5 w-3.5 text-foreground-subtle" }),
|
|
21270
|
+
bodyClassName: "p-3",
|
|
21271
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
21272
|
+
"aria-label": "Extensions",
|
|
21273
|
+
className: "flex flex-col gap-3",
|
|
21274
|
+
children: [
|
|
21275
|
+
view.kind === "pending" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
21276
|
+
role: "status",
|
|
21277
|
+
className: "text-[11px] text-foreground-subtle",
|
|
21278
|
+
children: "Loading this device’s extensions…"
|
|
21279
|
+
}),
|
|
21280
|
+
view.kind === "unknown" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorBox, {
|
|
21281
|
+
title: "Extensions could not be read",
|
|
21282
|
+
message: `Nothing is known about this device’s extensions yet: ${view.reason}`,
|
|
21283
|
+
onRetry: () => void query.refetch()
|
|
21284
|
+
}),
|
|
21285
|
+
view.kind === "none" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
21286
|
+
role: "status",
|
|
21287
|
+
className: "text-[11px] text-foreground-subtle italic",
|
|
21288
|
+
children: "No extensions are offered on this device."
|
|
21289
|
+
}),
|
|
21290
|
+
view.kind === "rows" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [view.slots.map((row) => _camstack_types.EXTENSION_SLOTS[row.slot].descriptor.shape === "association" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssociationSlotCard, {
|
|
21291
|
+
deviceId,
|
|
21292
|
+
row,
|
|
21293
|
+
onSaved: () => void query.refetch()
|
|
21294
|
+
}, row.slotRef) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
21295
|
+
className: "rounded-md border border-border/40 p-3",
|
|
21296
|
+
children: [
|
|
21297
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
21298
|
+
className: "text-xs font-semibold text-foreground",
|
|
21299
|
+
children: _camstack_types.EXTENSION_SLOTS[row.slot].descriptor.label
|
|
21300
|
+
}),
|
|
21301
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
21302
|
+
className: "text-[10px] text-foreground-subtle",
|
|
21303
|
+
children: [
|
|
21304
|
+
row.enabled === false ? "Off" : "On",
|
|
21305
|
+
" — ",
|
|
21306
|
+
row.authority,
|
|
21307
|
+
". Editing it needs a newer admin."
|
|
21308
|
+
]
|
|
21309
|
+
}),
|
|
21310
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SlotSourceList, { sources: row.sources })
|
|
21311
|
+
]
|
|
21312
|
+
}, row.slotRef)), view.unreachable.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
21313
|
+
role: "alert",
|
|
21314
|
+
className: "flex flex-col gap-1 rounded-md border border-warning/40 bg-warning/5 p-3",
|
|
21315
|
+
children: [
|
|
21316
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
21317
|
+
className: "flex items-center gap-2",
|
|
21318
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
21319
|
+
variant: "warning",
|
|
21320
|
+
children: "Unreachable"
|
|
21321
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
21322
|
+
className: "text-xs font-semibold text-foreground",
|
|
21323
|
+
children: row.addonId
|
|
21324
|
+
})]
|
|
21325
|
+
}),
|
|
21326
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
21327
|
+
className: "text-[11px] text-foreground-muted break-words",
|
|
21328
|
+
children: row.reason
|
|
21329
|
+
}),
|
|
21330
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
21331
|
+
className: "text-[10px] text-foreground-subtle",
|
|
21332
|
+
children: "The extensions this component owns are unknown until it answers."
|
|
21333
|
+
})
|
|
21334
|
+
]
|
|
21335
|
+
}, `unreachable:${row.addonId}`))] })
|
|
21336
|
+
]
|
|
21337
|
+
})
|
|
21338
|
+
});
|
|
21339
|
+
}
|
|
21340
|
+
//#endregion
|
|
20899
21341
|
//#region src/hooks/use-navigation.ts
|
|
20900
21342
|
/**
|
|
20901
21343
|
* useNavigation — drive a `navigation` robot camera from the UI.
|
|
@@ -23831,7 +24273,8 @@ var HOST_WIDGETS = {
|
|
|
23831
24273
|
"host/ptz-autotrack": AutotrackSection,
|
|
23832
24274
|
"host/recording-panel": RecordingPanel,
|
|
23833
24275
|
"host/camera-grid-layout": CameraGridLayoutEditor,
|
|
23834
|
-
"host/clips-browser": ClipsSection
|
|
24276
|
+
"host/clips-browser": ClipsSection,
|
|
24277
|
+
"host/extensions-panel": ExtensionsPanel
|
|
23835
24278
|
};
|
|
23836
24279
|
//#endregion
|
|
23837
24280
|
//#region src/composites/widget-slot.tsx
|
|
@@ -56050,6 +56493,7 @@ exports.CoverInlineControl = CoverInlineControl;
|
|
|
56050
56493
|
exports.CoverPanel = CoverPanel;
|
|
56051
56494
|
exports.CustomFieldRenderersProvider = CustomFieldRenderersProvider;
|
|
56052
56495
|
exports.DEFAULT_COLOR = DEFAULT_COLOR;
|
|
56496
|
+
exports.DEVICE_AGGREGATE_QUERY_KEY = DEVICE_AGGREGATE_QUERY_KEY;
|
|
56053
56497
|
exports.DEVICE_COLUMNS = DEVICE_COLUMNS;
|
|
56054
56498
|
exports.DEVICE_LIST_PAGE_SIZE_KEY = DEVICE_LIST_PAGE_SIZE_KEY;
|
|
56055
56499
|
exports.DEVICE_LIST_PAGE_SIZE_OPTIONS = DEVICE_LIST_PAGE_SIZE_OPTIONS;
|
|
@@ -56093,6 +56537,7 @@ exports.DummyHeroCard = DummyHeroCard;
|
|
|
56093
56537
|
exports.DummyInline = DummyInline;
|
|
56094
56538
|
exports.EMPTY_DATA_TABLE_FILTER = EMPTY_DATA_TABLE_FILTER;
|
|
56095
56539
|
exports.EVENT_KIND_ICONS = EVENT_KIND_ICONS;
|
|
56540
|
+
exports.EXTENSION_SLOTS_QUERY_KEY = EXTENSION_SLOTS_QUERY_KEY;
|
|
56096
56541
|
exports.EmptyState = EmptyState;
|
|
56097
56542
|
exports.ErrorBox = ErrorBox;
|
|
56098
56543
|
exports.EventKindGlyph = EventKindGlyph;
|
|
@@ -56335,6 +56780,7 @@ exports.hubWsUrl = hubWsUrl;
|
|
|
56335
56780
|
exports.humanDuration = humanDuration;
|
|
56336
56781
|
exports.humidifierTint = humidifierTint;
|
|
56337
56782
|
exports.initialScrubState = initialScrubState;
|
|
56783
|
+
exports.invalidateExtensionSurfaces = invalidateExtensionSurfaces;
|
|
56338
56784
|
exports.isAbsentProvider = isAbsentProvider;
|
|
56339
56785
|
exports.isAbsentProvider$1 = isAbsentProvider;
|
|
56340
56786
|
exports.isDataTableFilterActive = isDataTableFilterActive;
|
|
@@ -56622,6 +57068,10 @@ exports.useDeviceExportGetStatus = useDeviceExportGetStatus;
|
|
|
56622
57068
|
exports.useDeviceExportListExposedDevices = useDeviceExportListExposedDevices;
|
|
56623
57069
|
exports.useDeviceExportListSupportedDeviceKinds = useDeviceExportListSupportedDeviceKinds;
|
|
56624
57070
|
exports.useDeviceExportUnexposeDevice = useDeviceExportUnexposeDevice;
|
|
57071
|
+
exports.useDeviceExtensionListCandidates = useDeviceExtensionListCandidates;
|
|
57072
|
+
exports.useDeviceExtensionListSlots = useDeviceExtensionListSlots;
|
|
57073
|
+
exports.useDeviceExtensionListSources = useDeviceExtensionListSources;
|
|
57074
|
+
exports.useDeviceExtensionSetSlot = useDeviceExtensionSetSlot;
|
|
56625
57075
|
exports.useDeviceId = useDeviceId;
|
|
56626
57076
|
exports.useDeviceListPageSize = useDeviceListPageSize;
|
|
56627
57077
|
exports.useDeviceManagerAddLocation = useDeviceManagerAddLocation;
|
|
@@ -57135,6 +57585,7 @@ exports.usePipelineOrchestratorGetCameraStatuses = usePipelineOrchestratorGetCam
|
|
|
57135
57585
|
exports.usePipelineOrchestratorGetCameraStepOverrides = usePipelineOrchestratorGetCameraStepOverrides;
|
|
57136
57586
|
exports.usePipelineOrchestratorGetCameraSwitches = usePipelineOrchestratorGetCameraSwitches;
|
|
57137
57587
|
exports.usePipelineOrchestratorGetCapabilityBindings = usePipelineOrchestratorGetCapabilityBindings;
|
|
57588
|
+
exports.usePipelineOrchestratorGetClusterModelChoice = usePipelineOrchestratorGetClusterModelChoice;
|
|
57138
57589
|
exports.usePipelineOrchestratorGetDeviceLiveContribution = usePipelineOrchestratorGetDeviceLiveContribution;
|
|
57139
57590
|
exports.usePipelineOrchestratorGetDeviceSettingsContribution = usePipelineOrchestratorGetDeviceSettingsContribution;
|
|
57140
57591
|
exports.usePipelineOrchestratorGetGlobalMetrics = usePipelineOrchestratorGetGlobalMetrics;
|