@proveanything/smartlinks-utils-ui 0.12.1 → 0.12.4

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.
@@ -1689,6 +1689,14 @@ interface Props$c<T> {
1689
1689
  onCopyAndNewRule?: () => void;
1690
1690
  /** Label for the "Copy and start new rule" button. */
1691
1691
  copyAndNewRuleLabel?: string;
1692
+ /**
1693
+ * Collection-cardinality affordance — clone the current editor value
1694
+ * into a fresh draft item under the same scope. Mirrors the row menu
1695
+ * Duplicate action.
1696
+ */
1697
+ onDuplicate?: () => void;
1698
+ /** Optional label override for the Duplicate button. */
1699
+ duplicateLabel?: string;
1692
1700
  };
1693
1701
  /** Host-provided labels for save / discard / delete (resting state only). */
1694
1702
  actionLabels?: Partial<Record<RecordsAdminActionKey, string>>;
@@ -2885,9 +2893,22 @@ interface Props$1<T> {
2885
2893
  hasNextPage?: boolean;
2886
2894
  isFetchingNextPage?: boolean;
2887
2895
  onLoadMore?: () => void;
2888
- i18n: Pick<RecordsAdminI18n, 'backToScopes' | 'siblingsHeading' | 'noItemsTitle' | 'noItemsBody' | 'backToList' | 'newItem'>;
2896
+ /**
2897
+ * Per-row clipboard actions (Copy / Duplicate / Copy and start new
2898
+ * rule). Mirrors the menu surfaced by `ItemListView` so the open-item
2899
+ * sibling rail offers the same affordances without bouncing back to
2900
+ * the list. Hidden when omitted.
2901
+ */
2902
+ rowClipboard?: (record: RecordSummary<T>) => {
2903
+ onCopy?: () => void;
2904
+ onDuplicate?: () => void;
2905
+ onCopyAndNewRule?: () => void;
2906
+ } | null | undefined;
2907
+ /** Host-defined extra row actions, surfaced below the built-ins. */
2908
+ rowActions?: (record: RecordSummary<T>) => RecordAction[] | null | undefined;
2909
+ i18n: Pick<RecordsAdminI18n, 'backToScopes' | 'siblingsHeading' | 'noItemsTitle' | 'noItemsBody' | 'backToList' | 'newItem' | 'copy' | 'duplicateAction' | 'copyAndNewRuleAction'>;
2889
2910
  }
2890
- declare function SiblingRail<T>({ items, selectedItemId, isLoading, error, onBack, onSelect, contextKind, contextSummary, onCreate, itemNoun, dirtyKeys, errorKeys, i18n, total, hasNextPage, isFetchingNextPage, onLoadMore, }: Props$1<T>): react_jsx_runtime.JSX.Element;
2911
+ declare function SiblingRail<T>({ items, selectedItemId, isLoading, error, onBack, onSelect, contextKind, contextSummary, onCreate, itemNoun, dirtyKeys, errorKeys, i18n, total, hasNextPage, isFetchingNextPage, onLoadMore, rowClipboard, rowActions, }: Props$1<T>): react_jsx_runtime.JSX.Element;
2891
2912
 
2892
2913
  interface ClipboardEntry<T = unknown> {
2893
2914
  value: T;
@@ -2974,7 +2995,7 @@ interface Props {
2974
2995
  /** Optional veto hook — return false / throw to abort the change. */
2975
2996
  beforeChange?: (ctx: LifecycleChangeCtx) => boolean | Promise<boolean>;
2976
2997
  /** Fires after a successful flip with the new value. */
2977
- onChanged?: (next: string) => void;
2998
+ onChanged?: (next: string, record?: AppRecord) => void;
2978
2999
  /** Telemetry hook — receives `{ from, to }`. */
2979
3000
  onTelemetry?: (event: {
2980
3001
  from: string | undefined;
@@ -7,7 +7,7 @@ import { cn } from '../../chunk-L7FQ52F5.js';
7
7
  import { parsedRefToTarget, parsedRefToScope, matchRecords, scopesEqual, getRecordById, listRecords, upsertRecord, updateRecord, createRecord, removeRecord } from '../../chunk-KA4MKRHL.js';
8
8
  export { bulkDelete, bulkUpsert, createRecord, getRecordById, listRecords, matchRecords, parsedRefToScope, parsedRefToTarget, removeRecord, restoreRecord, scopesEqual, upsertRecord } from '../../chunk-KA4MKRHL.js';
9
9
  import { createContext, useMemo, useState, useEffect, useCallback, useRef, isValidElement, useLayoutEffect, useContext, useSyncExternalStore, createElement } from 'react';
10
- import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, List, SlidersHorizontal, Globe, Tag, Boxes, Layers, Package, Target, Check, Rows3, ChevronRight, Eraser, FilePlus2, ClipboardPaste, Box, X, Search, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, CornerDownLeft, Circle, ArrowUpDown, ArrowUp, ArrowDown, MinusCircle, XCircle, CopyPlus, AlertCircle, Undo2, Save, Loader2, Archive, ArrowRight, Globe2, Settings2 } from 'lucide-react';
10
+ import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, List, SlidersHorizontal, Globe, Tag, Boxes, Layers, Package, Target, Check, Rows3, ChevronRight, Eraser, FilePlus2, CopyPlus, ClipboardPaste, Box, X, Search, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, CornerDownLeft, Circle, ArrowUpDown, ArrowUp, ArrowDown, MinusCircle, XCircle, AlertCircle, Undo2, Save, Loader2, Archive, ArrowRight, Globe2, Settings2 } from 'lucide-react';
11
11
  import { useQuery, useQueryClient, useInfiniteQuery } from '@tanstack/react-query';
12
12
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
13
13
  import { createPortal } from 'react-dom';
@@ -1765,6 +1765,19 @@ function useShellClipboard(args) {
1765
1765
  window.setTimeout(() => {
1766
1766
  onCreateRuleFromClipboardRef?.current?.();
1767
1767
  }, 0);
1768
+ } : void 0,
1769
+ // Collection-cardinality clone affordance — only shown when the host
1770
+ // wired item-draft creation. Pushes the editor value to the clipboard
1771
+ // (so the existing pendingPasteTarget effect lands it on the new
1772
+ // draft) and mints a fresh draft.
1773
+ onDuplicate: isCollection && !!onCreateItemDraftRef ? () => {
1774
+ copyCurrent();
1775
+ window.setTimeout(() => {
1776
+ const create = onCreateItemDraftRef?.current;
1777
+ if (!create) return;
1778
+ const newId = create();
1779
+ if (newId) setPendingPasteTarget({ kind: "record", recordId: newId });
1780
+ }, 0);
1768
1781
  } : void 0
1769
1782
  } : void 0;
1770
1783
  const [pendingPasteTarget, setPendingPasteTarget] = useState(null);
@@ -3981,8 +3994,8 @@ var LifecycleStatusControl = ({
3981
3994
  if (next === value) return;
3982
3995
  setBusy(true);
3983
3996
  try {
3984
- await SL.app.records.update(collectionId, appId, recordId, { status: next }, true);
3985
- onChanged?.(next);
3997
+ const updated = await SL.app.records.update(collectionId, appId, recordId, { status: next }, true);
3998
+ onChanged?.(next, updated);
3986
3999
  } catch (err) {
3987
4000
  console.warn("[LifecycleStatusControl] update failed", err);
3988
4001
  } finally {
@@ -4176,9 +4189,9 @@ var LifecycleStatusMenu = ({
4176
4189
  }
4177
4190
  setBusy(next.value);
4178
4191
  try {
4179
- await SL.app.records.update(collectionId, appId, recordId, { status: next.value }, true);
4192
+ const updated = await SL.app.records.update(collectionId, appId, recordId, { status: next.value }, true);
4180
4193
  onTelemetry?.({ from: current, to: next.value });
4181
- onChanged?.(next.value);
4194
+ onChanged?.(next.value, updated);
4182
4195
  } catch (err) {
4183
4196
  console.warn("[LifecycleStatusMenu] update failed", err);
4184
4197
  } finally {
@@ -4684,7 +4697,8 @@ function useCollectionItems(args) {
4684
4697
  label: stableItemId,
4685
4698
  updatedAt: rec.updatedAt,
4686
4699
  itemId: stableItemId,
4687
- facetRule: recFacetRule
4700
+ facetRule: recFacetRule,
4701
+ lifecycleStatus: rec.status ?? void 0
4688
4702
  };
4689
4703
  return toSummary2(rec, base);
4690
4704
  }).filter((x) => x !== null);
@@ -5159,6 +5173,22 @@ function RecordEditor({
5159
5173
  ]
5160
5174
  }
5161
5175
  ),
5176
+ clipboard.onDuplicate && /* @__PURE__ */ jsxs(
5177
+ "button",
5178
+ {
5179
+ type: "button",
5180
+ onClick: clipboard.onDuplicate,
5181
+ disabled: !clipboard.canCopy || !!ctx.isSaving,
5182
+ title: clipboard.duplicateLabel ?? i18n.duplicateAction ?? "Duplicate",
5183
+ "aria-label": clipboard.duplicateLabel ?? i18n.duplicateAction ?? "Duplicate",
5184
+ className: "text-xs px-2.5 py-1.5 rounded-md border transition-opacity disabled:opacity-40 hover:bg-[hsl(var(--ra-muted))] inline-flex items-center gap-1.5",
5185
+ style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" },
5186
+ children: [
5187
+ /* @__PURE__ */ jsx(CopyPlus, { className: "w-3 h-3" }),
5188
+ clipboard.duplicateLabel ?? i18n.duplicateAction ?? "Duplicate"
5189
+ ]
5190
+ }
5191
+ ),
5162
5192
  /* @__PURE__ */ jsxs(
5163
5193
  "button",
5164
5194
  {
@@ -6895,7 +6925,9 @@ function SiblingRail({
6895
6925
  total,
6896
6926
  hasNextPage,
6897
6927
  isFetchingNextPage,
6898
- onLoadMore
6928
+ onLoadMore,
6929
+ rowClipboard,
6930
+ rowActions
6899
6931
  }) {
6900
6932
  const ruleLabelLookup = useRuleLabelLookup();
6901
6933
  const newLabel = i18n.newItem.includes("{noun}") ? i18n.newItem.replace("{noun}", itemNoun ?? "item") : i18n.newItem;
@@ -6934,45 +6966,68 @@ function SiblingRail({
6934
6966
  const ruleClauses = item.facetRule ? summarizeFacetRule(item.facetRule, ruleLabelLookup) : [];
6935
6967
  const isTargeted = ruleClauses.length > 0;
6936
6968
  const ruleSummary = isTargeted ? ruleClauses.map((c) => c.label).join(" \xB7 ") : null;
6937
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
6938
- "button",
6939
- {
6940
- type: "button",
6941
- onClick: () => onSelect(id),
6942
- className: "ra-row",
6943
- "data-selected": selected,
6944
- children: [
6945
- /* @__PURE__ */ jsxs("div", { className: "ra-row-body", children: [
6946
- /* @__PURE__ */ jsx("div", { className: "ra-row-title", children: item.label }),
6947
- item.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-row-sub", children: item.subtitle })
6948
- ] }),
6949
- isTargeted && /* @__PURE__ */ jsx(
6950
- "span",
6951
- {
6952
- className: "ra-row-rule-pip",
6953
- title: ruleSummary ? `Targeted: ${ruleSummary}` : "This item has targeting rules",
6954
- "aria-label": ruleSummary ? `Targeted: ${ruleSummary}` : "This item has targeting rules",
6955
- children: /* @__PURE__ */ jsx(Target, { className: "w-3 h-3", "aria-hidden": "true" })
6956
- }
6957
- ),
6958
- hasError ? /* @__PURE__ */ jsx(
6959
- "span",
6960
- {
6961
- className: "ra-error-pip",
6962
- title: "Save failed",
6963
- "aria-label": "Save failed"
6964
- }
6965
- ) : isDirty ? /* @__PURE__ */ jsx(
6966
- "span",
6967
- {
6968
- className: "ra-dirty-pip",
6969
- title: "Unsaved changes",
6970
- "aria-label": "Unsaved changes"
6969
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("div", { className: "ra-row-shell", "data-selected": selected, children: [
6970
+ /* @__PURE__ */ jsxs(
6971
+ "button",
6972
+ {
6973
+ type: "button",
6974
+ onClick: () => onSelect(id),
6975
+ className: "ra-row",
6976
+ "data-selected": selected,
6977
+ children: [
6978
+ /* @__PURE__ */ jsxs("div", { className: "ra-row-body", children: [
6979
+ /* @__PURE__ */ jsx("div", { className: "ra-row-title", children: item.label }),
6980
+ item.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-row-sub", children: item.subtitle })
6981
+ ] }),
6982
+ isTargeted && /* @__PURE__ */ jsx(
6983
+ "span",
6984
+ {
6985
+ className: "ra-row-rule-pip",
6986
+ title: ruleSummary ? `Targeted: ${ruleSummary}` : "This item has targeting rules",
6987
+ "aria-label": ruleSummary ? `Targeted: ${ruleSummary}` : "This item has targeting rules",
6988
+ children: /* @__PURE__ */ jsx(Target, { className: "w-3 h-3", "aria-hidden": "true" })
6989
+ }
6990
+ ),
6991
+ hasError ? /* @__PURE__ */ jsx(
6992
+ "span",
6993
+ {
6994
+ className: "ra-error-pip",
6995
+ title: "Save failed",
6996
+ "aria-label": "Save failed"
6997
+ }
6998
+ ) : isDirty ? /* @__PURE__ */ jsx(
6999
+ "span",
7000
+ {
7001
+ className: "ra-dirty-pip",
7002
+ title: "Unsaved changes",
7003
+ "aria-label": "Unsaved changes"
7004
+ }
7005
+ ) : null
7006
+ ]
7007
+ }
7008
+ ),
7009
+ (() => {
7010
+ const cb = rowClipboard ? rowClipboard(item) : null;
7011
+ const extra = rowActions ? rowActions(item) ?? void 0 : void 0;
7012
+ if (!cb?.onCopy && !cb?.onDuplicate && !cb?.onCopyAndNewRule && !(extra && extra.length)) {
7013
+ return null;
7014
+ }
7015
+ return /* @__PURE__ */ jsx(
7016
+ RowContextMenu,
7017
+ {
7018
+ onCopy: cb?.onCopy,
7019
+ onDuplicate: cb?.onDuplicate,
7020
+ onCopyAndNewRule: cb?.onCopyAndNewRule,
7021
+ actions: extra,
7022
+ i18n: {
7023
+ copy: i18n.copy,
7024
+ duplicateAction: i18n.duplicateAction,
7025
+ copyAndNewRuleAction: i18n.copyAndNewRuleAction
6971
7026
  }
6972
- ) : null
6973
- ]
6974
- }
6975
- ) }, key);
7027
+ }
7028
+ );
7029
+ })()
7030
+ ] }) }, key);
6976
7031
  }) })
6977
7032
  ] }),
6978
7033
  onLoadMore && /* @__PURE__ */ jsx(
@@ -8327,14 +8382,14 @@ var coerceDraftItemId2 = (generateItemId) => {
8327
8382
  const candidate = generateItemId ? generateItemId() : mintDraftItemId2();
8328
8383
  return isDraftId3(candidate) ? candidate : `draft:${candidate}`;
8329
8384
  };
8330
- var productItemToSummary = (p) => {
8385
+ var productItemToSummary = (p, configured) => {
8331
8386
  const ref = buildRef({ productId: p.id });
8332
8387
  return {
8333
8388
  id: null,
8334
8389
  ref,
8335
8390
  scope: parseRef(ref),
8336
8391
  data: null,
8337
- status: "empty",
8392
+ status: configured?.has(p.id) ? "configured" : "empty",
8338
8393
  label: p.name,
8339
8394
  subtitle: p.sku ?? void 0
8340
8395
  };
@@ -8686,8 +8741,20 @@ function RecordsAdminShellInner(props) {
8686
8741
  return productBrowse.items;
8687
8742
  }, [pinnedProduct.item, productBrowse.items]);
8688
8743
  const singletonConflicts = useMemo(
8689
- () => cardinality === "singleton" ? groupSingletonConflicts(recordList.items, activeStatuses) : [],
8690
- [cardinality, recordList.items, activeStatuses]
8744
+ () => {
8745
+ if (cardinality !== "singleton") return [];
8746
+ if (recordList.isLoading) return [];
8747
+ if (recordList.isFetchingNextPage || recordList.hasNextPage) return [];
8748
+ return groupSingletonConflicts(recordList.items, activeStatuses);
8749
+ },
8750
+ [
8751
+ cardinality,
8752
+ recordList.items,
8753
+ recordList.isLoading,
8754
+ recordList.isFetchingNextPage,
8755
+ recordList.hasNextPage,
8756
+ activeStatuses
8757
+ ]
8691
8758
  );
8692
8759
  const hasSingletonConflicts = singletonConflicts.length > 0;
8693
8760
  const totalDuplicateCount = useMemo(
@@ -9207,11 +9274,12 @@ function RecordsAdminShellInner(props) {
9207
9274
  label: label2,
9208
9275
  onAction: async () => {
9209
9276
  try {
9210
- await SL.app.records.update(collectionId, appId, record.id, { status: next }, true);
9211
- recordList.refetch();
9212
- if (cardinality === "singleton") {
9213
- ruleScopedList.refetch();
9214
- globalScopedList.refetch();
9277
+ const updated = await SL.app.records.update(collectionId, appId, record.id, { status: next }, true);
9278
+ if (updated) {
9279
+ patchRecordIntoCaches(queryClient, ctx, updated);
9280
+ queryClient.invalidateQueries({
9281
+ queryKey: scopeCountsQueryKey(ctx.collectionId, ctx.appId, ctx.recordType)
9282
+ });
9215
9283
  }
9216
9284
  } catch (err) {
9217
9285
  console.warn("[RecordsAdminShell] lifecycle update failed", err);
@@ -9251,6 +9319,14 @@ function RecordsAdminShellInner(props) {
9251
9319
  const itemViewCtx = baseItemViewCtx;
9252
9320
  const renderEditorWithPreview = () => {
9253
9321
  if (!editingTargetScope) return null;
9322
+ const targetingSavedRecord = isCollection && selectedItemId && !isDraftId3(selectedItemId) || !!selectedRecordId && !isDraftId3(selectedRecordId);
9323
+ if (resolved.isLoading && targetingSavedRecord && resolved.source !== "self") {
9324
+ return /* @__PURE__ */ jsxs("div", { className: "p-4 space-y-3", "aria-busy": "true", "aria-live": "polite", children: [
9325
+ /* @__PURE__ */ jsx("div", { className: "h-6 rounded-md animate-pulse", style: { background: "hsl(var(--ra-muted))", width: "40%" } }),
9326
+ /* @__PURE__ */ jsx("div", { className: "h-24 rounded-md animate-pulse", style: { background: "hsl(var(--ra-muted))" } }),
9327
+ /* @__PURE__ */ jsx("div", { className: "h-24 rounded-md animate-pulse", style: { background: "hsl(var(--ra-muted))" } })
9328
+ ] });
9329
+ }
9254
9330
  const previewAnchorRef = previewReopenAnchorRef;
9255
9331
  const previewBody = renderPreview && effectivePreviewScope ? renderPreview({ resolved: editorCtx.value, previewScope: effectivePreviewScope }) : null;
9256
9332
  const scopePicker = previewScopePicker && effectivePreviewScope ? /* @__PURE__ */ jsx(
@@ -9302,7 +9378,7 @@ function RecordsAdminShellInner(props) {
9302
9378
  ]
9303
9379
  }
9304
9380
  ) : null;
9305
- const selectedSummary = selectedRecordId && selectedRecordId !== DRAFT_ID3 ? recordList.items.find((r) => r.id === selectedRecordId) ?? globalScopedList.items.find((r) => r.id === selectedRecordId) ?? ruleScopedList.items.find((r) => r.id === selectedRecordId) : void 0;
9381
+ const selectedSummary = selectedRecordId && selectedRecordId !== DRAFT_ID3 ? recordList.items.find((r) => r.id === selectedRecordId) ?? globalScopedList.items.find((r) => r.id === selectedRecordId) ?? ruleScopedList.items.find((r) => r.id === selectedRecordId) ?? collectionItems.items.find((r) => r.id === selectedRecordId) : isCollection && selectedItemId && !isDraftId3(selectedItemId) ? collectionItems.items.find((r) => r.id === selectedItemId) : void 0;
9306
9382
  const editorLifecycleControl = selectedSummary?.id ? /* @__PURE__ */ jsx(
9307
9383
  LifecycleStatusControl,
9308
9384
  {
@@ -9312,8 +9388,13 @@ function RecordsAdminShellInner(props) {
9312
9388
  recordId: selectedSummary.id,
9313
9389
  current: selectedSummary.lifecycleStatus,
9314
9390
  i18n,
9315
- onChanged: () => {
9316
- void recordList.refetch();
9391
+ onChanged: (_next, updated) => {
9392
+ if (updated) {
9393
+ patchRecordIntoCaches(queryClient, ctx, updated);
9394
+ queryClient.invalidateQueries({
9395
+ queryKey: scopeCountsQueryKey(ctx.collectionId, ctx.appId, ctx.recordType)
9396
+ });
9397
+ }
9317
9398
  }
9318
9399
  }
9319
9400
  ) : null;
@@ -9336,11 +9417,12 @@ function RecordsAdminShellInner(props) {
9336
9417
  from: e.from,
9337
9418
  to: e.to
9338
9419
  }),
9339
- onChanged: () => {
9340
- void recordList.refetch();
9341
- if (cardinality === "singleton") {
9342
- ruleScopedList.refetch();
9343
- globalScopedList.refetch();
9420
+ onChanged: (_next, updated) => {
9421
+ if (updated) {
9422
+ patchRecordIntoCaches(queryClient, ctx, updated);
9423
+ queryClient.invalidateQueries({
9424
+ queryKey: scopeCountsQueryKey(ctx.collectionId, ctx.appId, ctx.recordType)
9425
+ });
9344
9426
  }
9345
9427
  }
9346
9428
  }
@@ -9512,7 +9594,7 @@ function RecordsAdminShellInner(props) {
9512
9594
  }];
9513
9595
  }
9514
9596
  const configured = scopeCounts.productIds;
9515
- const all = productBrowse.items.map(productItemToSummary);
9597
+ const all = productBrowse.items.map((p) => productItemToSummary(p, configured));
9516
9598
  const isConfigured = (s) => {
9517
9599
  const pid = s.scope.productId;
9518
9600
  return !!pid && configured.has(pid);
@@ -9656,8 +9738,12 @@ function RecordsAdminShellInner(props) {
9656
9738
  setRuleWizardStep(2);
9657
9739
  } else {
9658
9740
  setRuleWizardStep(2);
9741
+ if (ruleWizardSeedMode) {
9742
+ setRuleWizardDraftKey(mintRuleWizardDraftKey());
9743
+ setSelectedRecordId(DRAFT_ID3);
9744
+ }
9659
9745
  }
9660
- }, [cardinality]);
9746
+ }, [cardinality, ruleWizardSeedMode, mintRuleWizardDraftKey]);
9661
9747
  const startRuleWizardDraft = useCallback((seed) => {
9662
9748
  setRuleWizardSeedMode(seed);
9663
9749
  setRuleWizardDraftKey(mintRuleWizardDraftKey());
@@ -10107,6 +10193,8 @@ function RecordsAdminShellInner(props) {
10107
10193
  onLoadMore: () => {
10108
10194
  void collectionItems.fetchNextPage();
10109
10195
  },
10196
+ rowClipboard,
10197
+ rowActions: wrappedRecordActions,
10110
10198
  contextKind: isLifecycleRailEarly && lifecycleBucketLabel ? lifecycleBucketLabel : activeScope === "rule" ? "Rule" : activeScope === "product" ? "Product" : activeScope === "collection" ? "Global" : activeScope === "all" ? "All records" : activeScope === "variant" ? "Variant" : activeScope === "batch" ? "Batch" : activeScope === "facet" ? "Facet" : void 0,
10111
10199
  contextSummary: isLifecycleRailEarly && lifecycleBucketLabel ? `${scopedCollectionItemsList.length} ${itemNounLabel}${scopedCollectionItemsList.length === 1 ? "" : "s"}` : activeScope === "rule" ? activeRuleSummary : activeScope === "product" ? editorHeaderLabel ?? null : null,
10112
10200
  i18n
@@ -10258,7 +10346,8 @@ function RecordsAdminShellInner(props) {
10258
10346
  const ids = singletonConflicts.flatMap((c) => c.duplicates.map((d) => d.id)).filter((id) => !!id);
10259
10347
  for (const id of ids) {
10260
10348
  try {
10261
- await SL.app.records.update(collectionId, appId, id, { status: archivedStatusValue }, true);
10349
+ const updated = await SL.app.records.update(collectionId, appId, id, { status: archivedStatusValue }, true);
10350
+ if (updated) patchRecordIntoCaches(queryClient, ctx, updated);
10262
10351
  onTelemetry?.({
10263
10352
  type: "recordAction.invoke",
10264
10353
  recordType,
@@ -10269,17 +10358,16 @@ function RecordsAdminShellInner(props) {
10269
10358
  console.warn("[RecordsAdminShell] archive-duplicate failed", id, err);
10270
10359
  }
10271
10360
  }
10272
- recordList.refetch();
10273
- if (cardinality === "singleton") {
10274
- ruleScopedList.refetch();
10275
- globalScopedList.refetch();
10276
- }
10361
+ queryClient.invalidateQueries({
10362
+ queryKey: scopeCountsQueryKey(ctx.collectionId, ctx.appId, ctx.recordType)
10363
+ });
10277
10364
  } : void 0,
10278
10365
  onDeleteDuplicates: enableDeleteDuplicates ? async () => {
10279
10366
  const ids = singletonConflicts.flatMap((c) => c.duplicates.map((d) => d.id)).filter((id) => !!id);
10280
10367
  for (const id of ids) {
10281
10368
  try {
10282
10369
  await SL.app.records.remove(collectionId, appId, id, true);
10370
+ removeRecordFromCaches(queryClient, ctx, id);
10283
10371
  onTelemetry?.({
10284
10372
  type: "recordAction.invoke",
10285
10373
  recordType,
@@ -10290,11 +10378,9 @@ function RecordsAdminShellInner(props) {
10290
10378
  console.warn("[RecordsAdminShell] delete-duplicate failed", id, err);
10291
10379
  }
10292
10380
  }
10293
- recordList.refetch();
10294
- if (cardinality === "singleton") {
10295
- ruleScopedList.refetch();
10296
- globalScopedList.refetch();
10297
- }
10381
+ queryClient.invalidateQueries({
10382
+ queryKey: scopeCountsQueryKey(ctx.collectionId, ctx.appId, ctx.recordType)
10383
+ });
10298
10384
  } : void 0,
10299
10385
  i18n: {
10300
10386
  title: i18n.conflictBannerTitle,