@camstack/ui-library 1.2.294 → 1.2.295

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.
@@ -86,8 +86,14 @@ export interface DeviceListGenericProps<T> {
86
86
  * may include `PAGE_SIZE_ALL`. When set, `pageSize` is ignored.
87
87
  */
88
88
  readonly pageSizeSelector?: GenericPageSizeSelector;
89
- /** Optional control rendered next to the search box (e.g. a Refresh button). */
90
- readonly toolbar?: ReactNode;
89
+ /**
90
+ * Optional control rendered next to the search box (e.g. a Refresh button).
91
+ * A function receives the rows the search and type filter currently leave
92
+ * (every page), for controls that act on "what is shown".
93
+ */
94
+ readonly toolbar?: ReactNode | ((ctx: {
95
+ readonly filtered: readonly T[];
96
+ }) => ReactNode);
91
97
  }
92
98
  /**
93
99
  * Generic render-prop list: search + pagination chrome shared with the device
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Bulk selection for the device-export table (D875): choose by role and by
3
+ * provider, then select or deselect everything the filters leave on screen.
4
+ *
5
+ * Pure functions, so the rules are pinned without a DOM. Nothing here hides a
6
+ * device by default: an empty filter keeps every row (the operator's table is
7
+ * the only filter, D869).
8
+ */
9
+ import type { MultiSelectOption } from "./device-list/multi-select";
10
+ /** The slice of a device row the bulk filters read. */
11
+ export interface ExportFilterable {
12
+ readonly id: number;
13
+ readonly addonId: string;
14
+ readonly role?: string | null;
15
+ }
16
+ export interface ExportBulkFilters {
17
+ /** Keep rows whose role is one of these; empty = no role filter. */
18
+ readonly roles: readonly string[];
19
+ /** Keep rows whose provider addon is one of these; empty = no provider filter. */
20
+ readonly providers: readonly string[];
21
+ }
22
+ /** The role filter value of a row that has no role. */
23
+ export declare const NO_ROLE_FILTER_ID = "(none)";
24
+ export declare const NO_EXPORT_FILTERS: ExportBulkFilters;
25
+ export declare function roleFilterId(device: ExportFilterable): string;
26
+ /** The rows the role / provider filters leave. */
27
+ export declare function applyExportFilters<T extends ExportFilterable>(devices: readonly T[], filters: ExportBulkFilters): readonly T[];
28
+ /** Distinct roles present among the rows (a roleless row counts as "(none)"). */
29
+ export declare function roleFilterOptions(devices: readonly ExportFilterable[]): readonly MultiSelectOption[];
30
+ /** Distinct provider addons present among the rows. */
31
+ export declare function providerFilterOptions(devices: readonly ExportFilterable[]): readonly MultiSelectOption[];
32
+ /** `current` plus every shown row. */
33
+ export declare function selectShown(current: ReadonlySet<string>, shown: readonly ExportFilterable[]): ReadonlySet<string>;
34
+ /** `current` minus every shown row; selections outside the filter are kept. */
35
+ export declare function deselectShown(current: ReadonlySet<string>, shown: readonly ExportFilterable[]): ReadonlySet<string>;
package/dist/index.cjs CHANGED
@@ -5368,6 +5368,11 @@ var DEVICE_ROLE_META = {
5368
5368
  labelKey: "uiLibrary.deviceMeta.role.binaryHelper",
5369
5369
  labelFallback: "Binary helper"
5370
5370
  },
5371
+ [_camstack_types.DeviceRole.Outlet]: {
5372
+ icon: Plug,
5373
+ labelKey: "uiLibrary.deviceMeta.role.outlet",
5374
+ labelFallback: "Outlet"
5375
+ },
5371
5376
  [_camstack_types.DeviceRole.MotionSensor]: {
5372
5377
  icon: Footprints,
5373
5378
  labelKey: "uiLibrary.deviceMeta.role.motionSensor",
@@ -55003,7 +55008,7 @@ function GenericModeList(props) {
55003
55008
  "aria-label": searchPlaceholder,
55004
55009
  className: "h-7 pl-7 pr-2.5 rounded-md border border-border bg-surface text-[11px] text-foreground placeholder:text-foreground-subtle/60 focus:outline-none focus:ring-1 focus:ring-primary/40 w-56"
55005
55010
  })]
55006
- }), toolbar]
55011
+ }), typeof toolbar === "function" ? toolbar({ filtered }) : toolbar]
55007
55012
  })]
55008
55013
  }),
55009
55014
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -55135,6 +55140,47 @@ function DeviceList(props) {
55135
55140
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceModeList, { ...props });
55136
55141
  }
55137
55142
  //#endregion
55143
+ //#region src/composites/export-bulk-selection.ts
55144
+ /** The role filter value of a row that has no role. */
55145
+ var NO_ROLE_FILTER_ID = "(none)";
55146
+ var NO_EXPORT_FILTERS = {
55147
+ roles: [],
55148
+ providers: []
55149
+ };
55150
+ function roleFilterId(device) {
55151
+ const role = device.role;
55152
+ return role === null || role === void 0 || role === "" ? NO_ROLE_FILTER_ID : role;
55153
+ }
55154
+ /** The rows the role / provider filters leave. */
55155
+ function applyExportFilters(devices, filters) {
55156
+ const roles = new Set(filters.roles);
55157
+ const providers = new Set(filters.providers);
55158
+ return devices.filter((d) => (roles.size === 0 || roles.has(roleFilterId(d))) && (providers.size === 0 || providers.has(d.addonId)));
55159
+ }
55160
+ function distinctOptions(values) {
55161
+ return [...new Set(values)].toSorted().map((id) => ({
55162
+ id,
55163
+ label: id
55164
+ }));
55165
+ }
55166
+ /** Distinct roles present among the rows (a roleless row counts as "(none)"). */
55167
+ function roleFilterOptions(devices) {
55168
+ return distinctOptions(devices.map(roleFilterId));
55169
+ }
55170
+ /** Distinct provider addons present among the rows. */
55171
+ function providerFilterOptions(devices) {
55172
+ return distinctOptions(devices.map((d) => d.addonId));
55173
+ }
55174
+ /** `current` plus every shown row. */
55175
+ function selectShown(current, shown) {
55176
+ return new Set([...current, ...shown.map((d) => String(d.id))]);
55177
+ }
55178
+ /** `current` minus every shown row; selections outside the filter are kept. */
55179
+ function deselectShown(current, shown) {
55180
+ const drop = new Set(shown.map((d) => String(d.id)));
55181
+ return new Set([...current].filter((id) => !drop.has(id)));
55182
+ }
55183
+ //#endregion
55138
55184
  //#region src/composites/device-export-panel.tsx
55139
55185
  /**
55140
55186
  * DeviceExportPanel — generic, addon-agnostic surface for the
@@ -55541,6 +55587,18 @@ function DeviceExportPanel({ addonId, onOpenDevice, showSetup = true }) {
55541
55587
  labelFor,
55542
55588
  running
55543
55589
  ]);
55590
+ const [bulkFilters, setBulkFilters] = (0, react$1.useState)(NO_EXPORT_FILTERS);
55591
+ const roleOptions = (0, react$1.useMemo)(() => roleFilterOptions(candidateDevices), [candidateDevices]);
55592
+ const providerOptions = (0, react$1.useMemo)(() => providerFilterOptions(candidateDevices), [candidateDevices]);
55593
+ const shownDevices = (0, react$1.useMemo)(() => applyExportFilters(candidateDevices, bulkFilters), [candidateDevices, bulkFilters]);
55594
+ const setRoleFilter = (0, react$1.useCallback)((roles) => setBulkFilters((f) => ({
55595
+ ...f,
55596
+ roles
55597
+ })), []);
55598
+ const setProviderFilter = (0, react$1.useCallback)((providers) => setBulkFilters((f) => ({
55599
+ ...f,
55600
+ providers
55601
+ })), []);
55544
55602
  const selectedList = (0, react$1.useMemo)(() => [...selectedIds], [selectedIds]);
55545
55603
  const exposeSelected = (0, react$1.useCallback)(() => {
55546
55604
  runExport("expose", selectedList);
@@ -55611,36 +55669,75 @@ function DeviceExportPanel({ addonId, onOpenDevice, showSetup = true }) {
55611
55669
  toggleSelection,
55612
55670
  t
55613
55671
  ]);
55614
- const selectionToolbar = selectedIds.size === 0 ? void 0 : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
55615
- className: "inline-flex items-center gap-1.5",
55672
+ const renderToolbar = (0, react$1.useCallback)(({ filtered }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
55673
+ className: "inline-flex flex-wrap items-center gap-1.5",
55616
55674
  children: [
55617
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
55618
- "data-testid": "export-selection-count",
55619
- className: "text-[11px] text-foreground-subtle",
55620
- children: t("uiLibrary.deviceExport.selected", "{{count}} selected", { count: selectedIds.size })
55621
- }),
55622
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
55623
- size: "sm",
55624
- variant: "primary",
55625
- disabled: busy,
55626
- onClick: exposeSelected,
55627
- children: t("uiLibrary.deviceExport.exposeN", "Expose {{count}}", { count: selectedIds.size })
55675
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MultiSelectDropdown, {
55676
+ label: t("uiLibrary.deviceExport.filterRole", "Role"),
55677
+ options: roleOptions,
55678
+ selected: bulkFilters.roles,
55679
+ onChange: setRoleFilter
55680
+ }),
55681
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MultiSelectDropdown, {
55682
+ label: t("uiLibrary.deviceExport.filterProvider", "Provider"),
55683
+ options: providerOptions,
55684
+ selected: bulkFilters.providers,
55685
+ onChange: setProviderFilter
55628
55686
  }),
55629
55687
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
55630
55688
  size: "sm",
55631
55689
  variant: "secondary",
55632
- disabled: busy,
55633
- onClick: unexposeSelected,
55634
- children: t("uiLibrary.deviceExport.unexposeN", "Unexpose {{count}}", { count: selectedIds.size })
55690
+ disabled: filtered.length === 0,
55691
+ onClick: () => setSelectedIds((current) => selectShown(current, filtered)),
55692
+ children: t("uiLibrary.deviceExport.selectShown", "Select {{count}} shown", { count: filtered.length })
55635
55693
  }),
55636
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
55637
- size: "sm",
55638
- variant: "ghost",
55639
- onClick: clearSelection,
55640
- children: t("uiLibrary.deviceExport.clear", "Clear")
55641
- })
55694
+ selectedIds.size > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
55695
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
55696
+ size: "sm",
55697
+ variant: "ghost",
55698
+ onClick: () => setSelectedIds((current) => deselectShown(current, filtered)),
55699
+ children: t("uiLibrary.deviceExport.deselectShown", "Deselect shown")
55700
+ }),
55701
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
55702
+ "data-testid": "export-selection-count",
55703
+ className: "text-[11px] text-foreground-subtle",
55704
+ children: t("uiLibrary.deviceExport.selected", "{{count}} selected", { count: selectedIds.size })
55705
+ }),
55706
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
55707
+ size: "sm",
55708
+ variant: "primary",
55709
+ disabled: busy,
55710
+ onClick: exposeSelected,
55711
+ children: t("uiLibrary.deviceExport.exposeN", "Expose {{count}}", { count: selectedIds.size })
55712
+ }),
55713
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
55714
+ size: "sm",
55715
+ variant: "secondary",
55716
+ disabled: busy,
55717
+ onClick: unexposeSelected,
55718
+ children: t("uiLibrary.deviceExport.unexposeN", "Unexpose {{count}}", { count: selectedIds.size })
55719
+ }),
55720
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
55721
+ size: "sm",
55722
+ variant: "ghost",
55723
+ onClick: clearSelection,
55724
+ children: t("uiLibrary.deviceExport.clear", "Clear")
55725
+ })
55726
+ ] })
55642
55727
  ]
55643
- });
55728
+ }), [
55729
+ t,
55730
+ roleOptions,
55731
+ providerOptions,
55732
+ bulkFilters,
55733
+ setRoleFilter,
55734
+ setProviderFilter,
55735
+ selectedIds.size,
55736
+ busy,
55737
+ exposeSelected,
55738
+ unexposeSelected,
55739
+ clearSelection
55740
+ ]);
55644
55741
  const hasSupportedKinds = supportedKindList.length > 0;
55645
55742
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
55646
55743
  className: "rounded-lg border border-border bg-surface overflow-hidden",
@@ -55682,14 +55779,14 @@ function DeviceExportPanel({ addonId, onOpenDevice, showSetup = true }) {
55682
55779
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin" }), t("uiLibrary.deviceExport.loading", "Loading exportable devices…")]
55683
55780
  }) : hasSupportedKinds && candidateDevices.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceList, {
55684
55781
  mode: "generic",
55685
- items: candidateDevices,
55782
+ items: shownDevices,
55686
55783
  getKey,
55687
55784
  getSearchText,
55688
55785
  getFilterType,
55689
55786
  filterOptions: supportedTypeOptions,
55690
55787
  columns,
55691
55788
  onRowClick: onOpenDevice ? onRowClick : void 0,
55692
- toolbar: selectionToolbar,
55789
+ toolbar: renderToolbar,
55693
55790
  pageSizeSelector: DEVICE_EXPORT_PAGE_SIZE,
55694
55791
  searchPlaceholder: t("uiLibrary.deviceExport.search", "Search by name or stableId"),
55695
55792
  emptyLabel: t("uiLibrary.deviceExport.noMatch", "No device matches this search.")
package/dist/index.js CHANGED
@@ -5344,6 +5344,11 @@ var DEVICE_ROLE_META = {
5344
5344
  labelKey: "uiLibrary.deviceMeta.role.binaryHelper",
5345
5345
  labelFallback: "Binary helper"
5346
5346
  },
5347
+ [DeviceRole.Outlet]: {
5348
+ icon: Plug,
5349
+ labelKey: "uiLibrary.deviceMeta.role.outlet",
5350
+ labelFallback: "Outlet"
5351
+ },
5347
5352
  [DeviceRole.MotionSensor]: {
5348
5353
  icon: Footprints,
5349
5354
  labelKey: "uiLibrary.deviceMeta.role.motionSensor",
@@ -54979,7 +54984,7 @@ function GenericModeList(props) {
54979
54984
  "aria-label": searchPlaceholder,
54980
54985
  className: "h-7 pl-7 pr-2.5 rounded-md border border-border bg-surface text-[11px] text-foreground placeholder:text-foreground-subtle/60 focus:outline-none focus:ring-1 focus:ring-primary/40 w-56"
54981
54986
  })]
54982
- }), toolbar]
54987
+ }), typeof toolbar === "function" ? toolbar({ filtered }) : toolbar]
54983
54988
  })]
54984
54989
  }),
54985
54990
  /* @__PURE__ */ jsx("div", {
@@ -55111,6 +55116,47 @@ function DeviceList(props) {
55111
55116
  return /* @__PURE__ */ jsx(DeviceModeList, { ...props });
55112
55117
  }
55113
55118
  //#endregion
55119
+ //#region src/composites/export-bulk-selection.ts
55120
+ /** The role filter value of a row that has no role. */
55121
+ var NO_ROLE_FILTER_ID = "(none)";
55122
+ var NO_EXPORT_FILTERS = {
55123
+ roles: [],
55124
+ providers: []
55125
+ };
55126
+ function roleFilterId(device) {
55127
+ const role = device.role;
55128
+ return role === null || role === void 0 || role === "" ? NO_ROLE_FILTER_ID : role;
55129
+ }
55130
+ /** The rows the role / provider filters leave. */
55131
+ function applyExportFilters(devices, filters) {
55132
+ const roles = new Set(filters.roles);
55133
+ const providers = new Set(filters.providers);
55134
+ return devices.filter((d) => (roles.size === 0 || roles.has(roleFilterId(d))) && (providers.size === 0 || providers.has(d.addonId)));
55135
+ }
55136
+ function distinctOptions(values) {
55137
+ return [...new Set(values)].toSorted().map((id) => ({
55138
+ id,
55139
+ label: id
55140
+ }));
55141
+ }
55142
+ /** Distinct roles present among the rows (a roleless row counts as "(none)"). */
55143
+ function roleFilterOptions(devices) {
55144
+ return distinctOptions(devices.map(roleFilterId));
55145
+ }
55146
+ /** Distinct provider addons present among the rows. */
55147
+ function providerFilterOptions(devices) {
55148
+ return distinctOptions(devices.map((d) => d.addonId));
55149
+ }
55150
+ /** `current` plus every shown row. */
55151
+ function selectShown(current, shown) {
55152
+ return new Set([...current, ...shown.map((d) => String(d.id))]);
55153
+ }
55154
+ /** `current` minus every shown row; selections outside the filter are kept. */
55155
+ function deselectShown(current, shown) {
55156
+ const drop = new Set(shown.map((d) => String(d.id)));
55157
+ return new Set([...current].filter((id) => !drop.has(id)));
55158
+ }
55159
+ //#endregion
55114
55160
  //#region src/composites/device-export-panel.tsx
55115
55161
  /**
55116
55162
  * DeviceExportPanel — generic, addon-agnostic surface for the
@@ -55517,6 +55563,18 @@ function DeviceExportPanel({ addonId, onOpenDevice, showSetup = true }) {
55517
55563
  labelFor,
55518
55564
  running
55519
55565
  ]);
55566
+ const [bulkFilters, setBulkFilters] = useState(NO_EXPORT_FILTERS);
55567
+ const roleOptions = useMemo(() => roleFilterOptions(candidateDevices), [candidateDevices]);
55568
+ const providerOptions = useMemo(() => providerFilterOptions(candidateDevices), [candidateDevices]);
55569
+ const shownDevices = useMemo(() => applyExportFilters(candidateDevices, bulkFilters), [candidateDevices, bulkFilters]);
55570
+ const setRoleFilter = useCallback((roles) => setBulkFilters((f) => ({
55571
+ ...f,
55572
+ roles
55573
+ })), []);
55574
+ const setProviderFilter = useCallback((providers) => setBulkFilters((f) => ({
55575
+ ...f,
55576
+ providers
55577
+ })), []);
55520
55578
  const selectedList = useMemo(() => [...selectedIds], [selectedIds]);
55521
55579
  const exposeSelected = useCallback(() => {
55522
55580
  runExport("expose", selectedList);
@@ -55587,36 +55645,75 @@ function DeviceExportPanel({ addonId, onOpenDevice, showSetup = true }) {
55587
55645
  toggleSelection,
55588
55646
  t
55589
55647
  ]);
55590
- const selectionToolbar = selectedIds.size === 0 ? void 0 : /* @__PURE__ */ jsxs("span", {
55591
- className: "inline-flex items-center gap-1.5",
55648
+ const renderToolbar = useCallback(({ filtered }) => /* @__PURE__ */ jsxs("span", {
55649
+ className: "inline-flex flex-wrap items-center gap-1.5",
55592
55650
  children: [
55593
- /* @__PURE__ */ jsx("span", {
55594
- "data-testid": "export-selection-count",
55595
- className: "text-[11px] text-foreground-subtle",
55596
- children: t("uiLibrary.deviceExport.selected", "{{count}} selected", { count: selectedIds.size })
55597
- }),
55598
- /* @__PURE__ */ jsx(Button, {
55599
- size: "sm",
55600
- variant: "primary",
55601
- disabled: busy,
55602
- onClick: exposeSelected,
55603
- children: t("uiLibrary.deviceExport.exposeN", "Expose {{count}}", { count: selectedIds.size })
55651
+ /* @__PURE__ */ jsx(MultiSelectDropdown, {
55652
+ label: t("uiLibrary.deviceExport.filterRole", "Role"),
55653
+ options: roleOptions,
55654
+ selected: bulkFilters.roles,
55655
+ onChange: setRoleFilter
55656
+ }),
55657
+ /* @__PURE__ */ jsx(MultiSelectDropdown, {
55658
+ label: t("uiLibrary.deviceExport.filterProvider", "Provider"),
55659
+ options: providerOptions,
55660
+ selected: bulkFilters.providers,
55661
+ onChange: setProviderFilter
55604
55662
  }),
55605
55663
  /* @__PURE__ */ jsx(Button, {
55606
55664
  size: "sm",
55607
55665
  variant: "secondary",
55608
- disabled: busy,
55609
- onClick: unexposeSelected,
55610
- children: t("uiLibrary.deviceExport.unexposeN", "Unexpose {{count}}", { count: selectedIds.size })
55666
+ disabled: filtered.length === 0,
55667
+ onClick: () => setSelectedIds((current) => selectShown(current, filtered)),
55668
+ children: t("uiLibrary.deviceExport.selectShown", "Select {{count}} shown", { count: filtered.length })
55611
55669
  }),
55612
- /* @__PURE__ */ jsx(Button, {
55613
- size: "sm",
55614
- variant: "ghost",
55615
- onClick: clearSelection,
55616
- children: t("uiLibrary.deviceExport.clear", "Clear")
55617
- })
55670
+ selectedIds.size > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [
55671
+ /* @__PURE__ */ jsx(Button, {
55672
+ size: "sm",
55673
+ variant: "ghost",
55674
+ onClick: () => setSelectedIds((current) => deselectShown(current, filtered)),
55675
+ children: t("uiLibrary.deviceExport.deselectShown", "Deselect shown")
55676
+ }),
55677
+ /* @__PURE__ */ jsx("span", {
55678
+ "data-testid": "export-selection-count",
55679
+ className: "text-[11px] text-foreground-subtle",
55680
+ children: t("uiLibrary.deviceExport.selected", "{{count}} selected", { count: selectedIds.size })
55681
+ }),
55682
+ /* @__PURE__ */ jsx(Button, {
55683
+ size: "sm",
55684
+ variant: "primary",
55685
+ disabled: busy,
55686
+ onClick: exposeSelected,
55687
+ children: t("uiLibrary.deviceExport.exposeN", "Expose {{count}}", { count: selectedIds.size })
55688
+ }),
55689
+ /* @__PURE__ */ jsx(Button, {
55690
+ size: "sm",
55691
+ variant: "secondary",
55692
+ disabled: busy,
55693
+ onClick: unexposeSelected,
55694
+ children: t("uiLibrary.deviceExport.unexposeN", "Unexpose {{count}}", { count: selectedIds.size })
55695
+ }),
55696
+ /* @__PURE__ */ jsx(Button, {
55697
+ size: "sm",
55698
+ variant: "ghost",
55699
+ onClick: clearSelection,
55700
+ children: t("uiLibrary.deviceExport.clear", "Clear")
55701
+ })
55702
+ ] })
55618
55703
  ]
55619
- });
55704
+ }), [
55705
+ t,
55706
+ roleOptions,
55707
+ providerOptions,
55708
+ bulkFilters,
55709
+ setRoleFilter,
55710
+ setProviderFilter,
55711
+ selectedIds.size,
55712
+ busy,
55713
+ exposeSelected,
55714
+ unexposeSelected,
55715
+ clearSelection
55716
+ ]);
55620
55717
  const hasSupportedKinds = supportedKindList.length > 0;
55621
55718
  return /* @__PURE__ */ jsxs("div", {
55622
55719
  className: "rounded-lg border border-border bg-surface overflow-hidden",
@@ -55658,14 +55755,14 @@ function DeviceExportPanel({ addonId, onOpenDevice, showSetup = true }) {
55658
55755
  children: [/* @__PURE__ */ jsx(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin" }), t("uiLibrary.deviceExport.loading", "Loading exportable devices…")]
55659
55756
  }) : hasSupportedKinds && candidateDevices.length > 0 ? /* @__PURE__ */ jsx(DeviceList, {
55660
55757
  mode: "generic",
55661
- items: candidateDevices,
55758
+ items: shownDevices,
55662
55759
  getKey,
55663
55760
  getSearchText,
55664
55761
  getFilterType,
55665
55762
  filterOptions: supportedTypeOptions,
55666
55763
  columns,
55667
55764
  onRowClick: onOpenDevice ? onRowClick : void 0,
55668
- toolbar: selectionToolbar,
55765
+ toolbar: renderToolbar,
55669
55766
  pageSizeSelector: DEVICE_EXPORT_PAGE_SIZE,
55670
55767
  searchPlaceholder: t("uiLibrary.deviceExport.search", "Search by name or stableId"),
55671
55768
  emptyLabel: t("uiLibrary.deviceExport.noMatch", "No device matches this search.")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/ui-library",
3
- "version": "1.2.294",
3
+ "version": "1.2.295",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",