@proveanything/smartlinks-utils-ui 0.12.10 → 0.12.12

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.
@@ -842,6 +842,25 @@ interface RecordSlotContext {
842
842
  * to populate this directly.
843
843
  */
844
844
  actions?: RecordAction[];
845
+ /**
846
+ * Facet keys carried by the row's enclosing group header, when the rail
847
+ * is grouped by facet identity (Rules tab default). The default row
848
+ * renderer uses this to drop the facet prefix from chips whose facet is
849
+ * already named in the group header (so under "BREAD TYPE" you see
850
+ * "Slice" instead of "Bread Type: Slice"). Empty when ungrouped.
851
+ */
852
+ groupFacetKeys?: readonly string[];
853
+ /**
854
+ * Number of archived (history) records collapsed under this row's
855
+ * lifecycle slot. The default row renderer surfaces this as an inline
856
+ * pill the admin can click to expand/collapse the archived rows
857
+ * underneath. Undefined when there is no history block.
858
+ */
859
+ historyCount?: number;
860
+ /** Whether the history block for this row is currently expanded. */
861
+ historyExpanded?: boolean;
862
+ /** Toggle the history block. Only present when `historyCount > 0`. */
863
+ onToggleHistory?: () => void;
845
864
  }
846
865
  /**
847
866
  * Declarative column definition for the built-in default item table.
@@ -1110,6 +1129,12 @@ interface RailConfig<TData = unknown> {
1110
1129
  key: string;
1111
1130
  label: string;
1112
1131
  icon?: ReactNode;
1132
+ /**
1133
+ * Optional facet keys this group represents (Rules tab default
1134
+ * grouping populates this). Forwarded to row ctx so the default row
1135
+ * renderer can drop redundant facet prefixes from rule chips.
1136
+ */
1137
+ facetKeys?: readonly string[];
1113
1138
  /**
1114
1139
  * Whether this bucket should be expanded by default (records-driven
1115
1140
  * accordion mode). Last-write-wins per key. Has no effect in the
@@ -15,6 +15,7 @@ import { createPortal } from 'react-dom';
15
15
  // src/components/RecordsAdmin/data/recordCache.ts
16
16
  var RECORD_LIST_QK = ["records-admin", "list"];
17
17
  var COLLECTION_ITEMS_QK = ["records-admin", "collection-items"];
18
+ var SCOPE_COUNTS_QK = ["records-admin", "scope-counts"];
18
19
  var matchesCtx = (queryKey, prefix, ctx) => {
19
20
  if (queryKey.length < prefix.length + 3) return false;
20
21
  for (let i = 0; i < prefix.length; i += 1) {
@@ -87,6 +88,96 @@ function patchRecordIntoCaches(queryClient, ctx, record) {
87
88
  return replaceOrAppend(prev, record);
88
89
  });
89
90
  }
91
+ patchRecordIntoScopeCounts(queryClient, ctx, record);
92
+ }
93
+ var matchesScopeCountsCtx = (queryKey, ctx) => {
94
+ if (queryKey.length < 5) return false;
95
+ if (queryKey[0] !== SCOPE_COUNTS_QK[0]) return false;
96
+ if (queryKey[1] !== SCOPE_COUNTS_QK[1]) return false;
97
+ if (queryKey[2] !== ctx.collectionId) return false;
98
+ if (queryKey[3] !== ctx.appId) return false;
99
+ const slot = queryKey[4];
100
+ const expected = ctx.recordType ?? null;
101
+ if (slot !== expected && !(slot == null && expected == null)) return false;
102
+ return true;
103
+ };
104
+ function patchRecordIntoScopeCounts(queryClient, ctx, record) {
105
+ if (!record || !record.id) return;
106
+ const all = queryClient.getQueriesData({
107
+ queryKey: SCOPE_COUNTS_QK
108
+ });
109
+ for (const [key, cache] of all) {
110
+ if (!cache || !Array.isArray(cache.records)) continue;
111
+ if (!matchesScopeCountsCtx(key, ctx)) continue;
112
+ queryClient.setQueryData(key, (prev) => {
113
+ if (!prev || !Array.isArray(prev.records)) return prev;
114
+ const idx = prev.records.findIndex((r) => r.id === record.id);
115
+ if (idx === -1) {
116
+ return { ...prev, records: [...prev.records, record] };
117
+ }
118
+ const next = [...prev.records];
119
+ next[idx] = record;
120
+ return { ...prev, records: next };
121
+ });
122
+ }
123
+ }
124
+ function removeRecordFromScopeCounts(queryClient, ctx, recordId) {
125
+ if (!recordId) return;
126
+ const all = queryClient.getQueriesData({
127
+ queryKey: SCOPE_COUNTS_QK
128
+ });
129
+ for (const [key, cache] of all) {
130
+ if (!cache || !Array.isArray(cache.records)) continue;
131
+ if (!matchesScopeCountsCtx(key, ctx)) continue;
132
+ queryClient.setQueryData(key, (prev) => {
133
+ if (!prev || !Array.isArray(prev.records)) return prev;
134
+ const next = prev.records.filter((r) => r.id !== recordId);
135
+ if (next.length === prev.records.length) return prev;
136
+ return { ...prev, records: next };
137
+ });
138
+ }
139
+ }
140
+ function patchRecordStatusInCaches(queryClient, ctx, recordId, status) {
141
+ if (!recordId) return;
142
+ const lists = [
143
+ ...queryClient.getQueriesData({ queryKey: RECORD_LIST_QK }),
144
+ ...queryClient.getQueriesData({ queryKey: COLLECTION_ITEMS_QK })
145
+ ];
146
+ for (const [key, cache] of lists) {
147
+ if (!cache || !Array.isArray(cache.pages)) continue;
148
+ const prefix = key[0] === RECORD_LIST_QK[0] && key[1] === RECORD_LIST_QK[1] ? RECORD_LIST_QK : COLLECTION_ITEMS_QK;
149
+ if (!matchesCtx(key, prefix, ctx)) continue;
150
+ queryClient.setQueryData(key, (prev) => {
151
+ if (!prev || !Array.isArray(prev.pages)) return prev;
152
+ let touched = false;
153
+ const pages = prev.pages.map((p) => ({
154
+ ...p,
155
+ data: p.data.map((r) => {
156
+ if (r.id !== recordId) return r;
157
+ touched = true;
158
+ return { ...r, status };
159
+ })
160
+ }));
161
+ return touched ? { ...prev, pages } : prev;
162
+ });
163
+ }
164
+ const counts = queryClient.getQueriesData({
165
+ queryKey: SCOPE_COUNTS_QK
166
+ });
167
+ for (const [key, cache] of counts) {
168
+ if (!cache || !Array.isArray(cache.records)) continue;
169
+ if (!matchesScopeCountsCtx(key, ctx)) continue;
170
+ queryClient.setQueryData(key, (prev) => {
171
+ if (!prev || !Array.isArray(prev.records)) return prev;
172
+ let touched = false;
173
+ const records = prev.records.map((r) => {
174
+ if (r.id !== recordId) return r;
175
+ touched = true;
176
+ return { ...r, status };
177
+ });
178
+ return touched ? { ...prev, records } : prev;
179
+ });
180
+ }
90
181
  }
91
182
  function removeRecordFromCaches(queryClient, ctx, recordId) {
92
183
  if (!recordId) return;
@@ -104,6 +195,7 @@ function removeRecordFromCaches(queryClient, ctx, recordId) {
104
195
  return next ?? prev;
105
196
  });
106
197
  }
198
+ removeRecordFromScopeCounts(queryClient, ctx, recordId);
107
199
  }
108
200
  var DEFAULT_ICONS = {
109
201
  scope: {
@@ -4097,13 +4189,30 @@ var RuleLabelLookupProvider = ({
4097
4189
  return /* @__PURE__ */ jsx(RuleLabelLookupContext.Provider, { value: v, children });
4098
4190
  };
4099
4191
  var DefaultRecordRow = ({ record, ctx, compact = false }) => {
4100
- const { selected, onSelect, isDirty, hasError, onCopy, onDuplicate, onCopyAndNewRule, actions } = ctx;
4192
+ const {
4193
+ selected,
4194
+ onSelect,
4195
+ isDirty,
4196
+ hasError,
4197
+ onCopy,
4198
+ onDuplicate,
4199
+ onCopyAndNewRule,
4200
+ actions,
4201
+ historyCount,
4202
+ historyExpanded,
4203
+ onToggleHistory
4204
+ } = ctx;
4101
4205
  const ruleLabelLookup = useRuleLabelLookup();
4102
4206
  const ScopeIcon = record.scope.kind && record.scope.kind !== "collection" ? DEFAULT_ICONS.scope[record.scope.kind] : DEFAULT_ICONS.scope.product;
4103
4207
  const tone = resolveTone(void 0, record.status);
4104
4208
  const ruleSummary = formatFacetRule(record.facetRule, ruleLabelLookup);
4105
4209
  const ruleClauses = summarizeFacetRule(record.facetRule, ruleLabelLookup);
4106
4210
  const isRuleRecord = ruleClauses.length > 0;
4211
+ const groupKeys = ctx.groupFacetKeys;
4212
+ const singleGroupFacet = groupKeys && groupKeys.length === 1 ? groupKeys[0] : null;
4213
+ const displayClauses = singleGroupFacet ? ruleClauses.map(
4214
+ (c) => c.facetKey === singleGroupFacet ? { ...c, label: c.values.length <= 3 ? c.values.join(", ") : `${c.values.slice(0, 2).join(", ")} +${c.values.length - 2}` } : c
4215
+ ) : ruleClauses;
4107
4216
  const i18n = ctx.i18n ?? DEFAULT_I18N;
4108
4217
  const subtitle = record.subtitle ?? (isRuleRecord ? null : ruleSummary) ?? (tone === "missing" ? i18n.subtitleEmpty : tone === "own" ? i18n.subtitleConfigured : i18n.subtitleInherited);
4109
4218
  return /* @__PURE__ */ jsxs(
@@ -4111,7 +4220,7 @@ var DefaultRecordRow = ({ record, ctx, compact = false }) => {
4111
4220
  {
4112
4221
  "data-selected": selected ? "true" : "false",
4113
4222
  "data-tone": tone,
4114
- className: cn("ra-row", compact && "ra-row-compact"),
4223
+ className: cn("ra-row", compact && "ra-row-compact", isRuleRecord && !compact && "ra-row-rule"),
4115
4224
  style: compact ? { paddingTop: "0.4rem", paddingBottom: "0.4rem" } : void 0,
4116
4225
  children: [
4117
4226
  /* @__PURE__ */ jsxs("button", { type: "button", onClick: onSelect, className: "ra-row-hit", children: [
@@ -4125,7 +4234,7 @@ var DefaultRecordRow = ({ record, ctx, compact = false }) => {
4125
4234
  }
4126
4235
  ) }),
4127
4236
  /* @__PURE__ */ jsxs("div", { className: "ra-row-body", children: [
4128
- /* @__PURE__ */ jsx("div", { className: "ra-row-title", children: record.label }),
4237
+ !(isRuleRecord && !compact) && /* @__PURE__ */ jsx("div", { className: "ra-row-title", children: record.label }),
4129
4238
  !compact && isRuleRecord && /* @__PURE__ */ jsxs(
4130
4239
  "div",
4131
4240
  {
@@ -4133,10 +4242,10 @@ var DefaultRecordRow = ({ record, ctx, compact = false }) => {
4133
4242
  title: ruleSummary ?? void 0,
4134
4243
  "aria-label": ruleSummary ?? void 0,
4135
4244
  children: [
4136
- ruleClauses.slice(0, 4).map((clause, i) => /* @__PURE__ */ jsx("span", { className: "ra-rule-chip", children: clause.label }, `${clause.facetKey}-${i}`)),
4137
- ruleClauses.length > 4 && /* @__PURE__ */ jsxs("span", { className: "ra-rule-chip ra-rule-chip-more", children: [
4245
+ displayClauses.slice(0, 4).map((clause, i) => /* @__PURE__ */ jsx("span", { className: "ra-rule-chip", children: clause.label }, `${clause.facetKey}-${i}`)),
4246
+ displayClauses.length > 4 && /* @__PURE__ */ jsxs("span", { className: "ra-rule-chip ra-rule-chip-more", children: [
4138
4247
  "+",
4139
- ruleClauses.length - 4
4248
+ displayClauses.length - 4
4140
4249
  ] })
4141
4250
  ]
4142
4251
  }
@@ -4171,6 +4280,25 @@ var DefaultRecordRow = ({ record, ctx, compact = false }) => {
4171
4280
  }
4172
4281
  )
4173
4282
  ] }),
4283
+ historyCount && historyCount > 0 && onToggleHistory ? /* @__PURE__ */ jsxs(
4284
+ "button",
4285
+ {
4286
+ type: "button",
4287
+ className: "ra-row-history-pill",
4288
+ "data-expanded": historyExpanded ? "true" : "false",
4289
+ onClick: (e) => {
4290
+ e.stopPropagation();
4291
+ onToggleHistory();
4292
+ },
4293
+ "aria-expanded": historyExpanded,
4294
+ "aria-label": historyExpanded ? `Hide ${historyCount} archived` : `Show ${historyCount} archived`,
4295
+ title: historyExpanded ? `Hide ${historyCount} archived` : `Show ${historyCount} archived`,
4296
+ children: [
4297
+ /* @__PURE__ */ jsx("span", { className: "ra-row-history-pill-count", children: historyCount }),
4298
+ /* @__PURE__ */ jsx("span", { className: "ra-row-history-pill-label", children: "archived" })
4299
+ ]
4300
+ }
4301
+ ) : null,
4174
4302
  (onCopy || onDuplicate || onCopyAndNewRule || actions && actions.length > 0) && /* @__PURE__ */ jsx(
4175
4303
  RowContextMenu,
4176
4304
  {
@@ -4232,7 +4360,7 @@ var RecordList = ({
4232
4360
  buttons[nextIdx].scrollIntoView({ block: "nearest" });
4233
4361
  }
4234
4362
  }, []);
4235
- const buildCtx = (item) => {
4363
+ const buildCtx = (item, groupFacetKeys) => {
4236
4364
  const cb = rowClipboard ? rowClipboard(item) : null;
4237
4365
  const extraActions = rowActions ? rowActions(item) ?? void 0 : void 0;
4238
4366
  const itemAnchorKey = anchorKey(item.scope);
@@ -4249,6 +4377,7 @@ var RecordList = ({
4249
4377
  isDirty: dirtyIdMatch || dirtyAnchorMatch || idInStore || anchorInStore,
4250
4378
  hasError: errorInStore,
4251
4379
  i18n,
4380
+ groupFacetKeys,
4252
4381
  ...cb ?? {},
4253
4382
  actions: extraActions && extraActions.length > 0 ? extraActions : void 0
4254
4383
  };
@@ -4276,43 +4405,30 @@ var RecordList = ({
4276
4405
  return next;
4277
4406
  });
4278
4407
  }, []);
4279
- const renderItems = (rows) => {
4408
+ const renderItems = (rows, groupFacetKeys) => {
4280
4409
  const compact = presentation === "compact";
4281
4410
  return /* @__PURE__ */ jsx("ul", { children: rows.map((item, idx) => {
4282
- const ctx = buildCtx(item);
4411
+ const ctx = buildCtx(item, groupFacetKeys);
4283
4412
  const key = item.id ?? (anchorKey(item.scope) || `pos:${idx}`);
4284
4413
  const sKey = historyBySlot ? slotKey(item) : null;
4285
4414
  const history = sKey ? historyBySlot.get(sKey) : void 0;
4286
4415
  const expanded = sKey ? expandedSlots.has(sKey) : false;
4287
- const showLabel = i18n?.historyDisclosureShow ?? "Show {n} archived";
4288
- const hideLabel = i18n?.historyDisclosureHide ?? "Hide {n} archived";
4289
- const label = (expanded ? hideLabel : showLabel).replace("{n}", String(history?.length ?? 0));
4416
+ const historyCount = history?.length ?? 0;
4417
+ const ctxWithHistory = historyCount > 0 && sKey ? { ...ctx, historyCount, historyExpanded: expanded, onToggleHistory: () => toggleSlot(sKey) } : ctx;
4290
4418
  return /* @__PURE__ */ jsxs("li", { children: [
4291
- renderListRow ? renderListRow(item, ctx) : /* @__PURE__ */ jsx(DefaultRecordRow, { record: item, ctx, compact }),
4292
- history && history.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "ra-history-block", children: [
4293
- expanded ? /* @__PURE__ */ jsx("ul", { className: "ra-history-rows", "aria-label": "Archived records", children: history.map((h, hIdx) => {
4294
- const hCtx = buildCtx(h);
4295
- const hKey = h.id ?? `hist:${idx}:${hIdx}`;
4296
- const badged = {
4297
- ...h,
4298
- badges: [
4299
- ...h.badges ?? [],
4300
- { label: h.lifecycleStatus ?? "archived", tone: "warning" }
4301
- ]
4302
- };
4303
- return /* @__PURE__ */ jsx("li", { className: "ra-history-row", "data-history": "true", children: renderListRow ? renderListRow(badged, hCtx) : /* @__PURE__ */ jsx(DefaultRecordRow, { record: badged, ctx: hCtx, compact }) }, hKey);
4304
- }) }) : null,
4305
- /* @__PURE__ */ jsx(
4306
- "button",
4307
- {
4308
- type: "button",
4309
- className: "ra-history-disclosure",
4310
- onClick: () => sKey && toggleSlot(sKey),
4311
- "aria-expanded": expanded,
4312
- children: label
4313
- }
4314
- )
4315
- ] }) : null
4419
+ renderListRow ? renderListRow(item, ctxWithHistory) : /* @__PURE__ */ jsx(DefaultRecordRow, { record: item, ctx: ctxWithHistory, compact }),
4420
+ history && history.length > 0 ? /* @__PURE__ */ jsx("div", { className: "ra-history-block", children: expanded ? /* @__PURE__ */ jsx("ul", { className: "ra-history-rows", "aria-label": "Archived records", children: history.map((h, hIdx) => {
4421
+ const hCtx = buildCtx(h, groupFacetKeys);
4422
+ const hKey = h.id ?? `hist:${idx}:${hIdx}`;
4423
+ const badged = {
4424
+ ...h,
4425
+ badges: [
4426
+ ...h.badges ?? [],
4427
+ { label: h.lifecycleStatus ?? "archived", tone: "warning" }
4428
+ ]
4429
+ };
4430
+ return /* @__PURE__ */ jsx("li", { className: "ra-history-row", "data-history": "true", children: renderListRow ? renderListRow(badged, hCtx) : /* @__PURE__ */ jsx(DefaultRecordRow, { record: badged, ctx: hCtx, compact }) }, hKey);
4431
+ }) }) : null }) : null
4316
4432
  ] }, key);
4317
4433
  }) });
4318
4434
  };
@@ -4385,7 +4501,7 @@ var GroupedList = ({
4385
4501
  }
4386
4502
  ) : null
4387
4503
  ] }),
4388
- /* @__PURE__ */ jsx("div", { className: "ra-group-body", children: renderItems(g.items) })
4504
+ /* @__PURE__ */ jsx("div", { className: "ra-group-body", children: renderItems(g.items, g.facetKeys) })
4389
4505
  ] }, g.key);
4390
4506
  }) });
4391
4507
  };
@@ -7069,11 +7185,12 @@ function ItemListView({
7069
7185
  const def = resolveLifecycleStatus(item, lifecycle);
7070
7186
  const existing = map.get(def.value);
7071
7187
  if (existing) existing.items.push(item);
7072
- else map.set(def.value, { label: def.label, items: [item] });
7188
+ else map.set(def.value, { label: def.label, tone: def.tone ?? "default", items: [item] });
7073
7189
  }
7074
7190
  return Array.from(map.entries()).map(([key, v]) => ({
7075
7191
  key,
7076
7192
  label: v.label,
7193
+ tone: v.tone,
7077
7194
  items: v.items,
7078
7195
  isActive: activeValues.includes(key)
7079
7196
  })).sort((a, b) => compareLifecycleBuckets(a.key, b.key)).filter((b) => b.items.length > 0);
@@ -7241,11 +7358,13 @@ function ItemListView({
7241
7358
  } else if (buckets && buckets.length > 0) {
7242
7359
  body = /* @__PURE__ */ jsx("div", { className: "ra-item-buckets", children: buckets.map((bucket) => {
7243
7360
  const open = bucket.isActive || !collapsedBuckets.has(bucket.key);
7361
+ const toneVar = bucket.tone === "success" ? "var(--ra-success)" : bucket.tone === "warning" ? "var(--ra-warning)" : bucket.tone === "danger" ? "var(--ra-danger)" : bucket.tone === "info" ? "var(--ra-info)" : "var(--ra-status-missing)";
7244
7362
  return /* @__PURE__ */ jsxs(
7245
7363
  "section",
7246
7364
  {
7247
7365
  className: "ra-item-bucket",
7248
7366
  "data-bucket": bucket.key,
7367
+ style: { borderLeft: `3px solid hsl(${toneVar} / 0.55)` },
7249
7368
  children: [
7250
7369
  /* @__PURE__ */ jsxs(
7251
7370
  "button",
@@ -7261,7 +7380,7 @@ function ItemListView({
7261
7380
  gap: "6px",
7262
7381
  width: "100%",
7263
7382
  padding: "6px 12px",
7264
- background: "transparent",
7383
+ background: `hsl(${toneVar} / 0.06)`,
7265
7384
  border: 0,
7266
7385
  borderTop: "1px solid hsl(var(--ra-border))",
7267
7386
  font: "inherit",
@@ -7269,13 +7388,40 @@ function ItemListView({
7269
7388
  fontWeight: 600,
7270
7389
  textTransform: "uppercase",
7271
7390
  letterSpacing: "0.04em",
7272
- color: "hsl(var(--ra-muted-text))",
7391
+ color: `hsl(${toneVar})`,
7273
7392
  cursor: bucket.isActive ? "default" : "pointer"
7274
7393
  },
7275
7394
  children: [
7276
7395
  !bucket.isActive ? open ? /* @__PURE__ */ jsx(ChevronDown, { className: "w-3 h-3", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3", "aria-hidden": "true" }) : null,
7396
+ /* @__PURE__ */ jsx(
7397
+ "span",
7398
+ {
7399
+ "aria-hidden": "true",
7400
+ style: {
7401
+ width: 8,
7402
+ height: 8,
7403
+ borderRadius: 9999,
7404
+ background: `hsl(${toneVar})`,
7405
+ flexShrink: 0
7406
+ }
7407
+ }
7408
+ ),
7277
7409
  /* @__PURE__ */ jsx("span", { children: bucket.label }),
7278
- /* @__PURE__ */ jsx("span", { style: { marginLeft: "auto", fontWeight: 500 }, children: bucket.items.length })
7410
+ /* @__PURE__ */ jsx(
7411
+ "span",
7412
+ {
7413
+ style: {
7414
+ marginLeft: "auto",
7415
+ fontWeight: 600,
7416
+ fontSize: "10px",
7417
+ padding: "1px 7px",
7418
+ borderRadius: 9999,
7419
+ background: `hsl(${toneVar} / 0.12)`,
7420
+ color: `hsl(${toneVar})`
7421
+ },
7422
+ children: bucket.items.length
7423
+ }
7424
+ )
7279
7425
  ]
7280
7426
  }
7281
7427
  ),
@@ -8964,8 +9110,12 @@ var EditorPoolBody = ({
8964
9110
  }) => {
8965
9111
  const ctx = useEditorSlotContext(editorId);
8966
9112
  if (!ctx) return null;
8967
- return renderEditor(ctx);
9113
+ return /* @__PURE__ */ jsx(CallbackRenderer, { render: renderEditor, args: ctx });
8968
9114
  };
9115
+ var CallbackRenderer = ({
9116
+ render,
9117
+ args
9118
+ }) => /* @__PURE__ */ jsx(Fragment, { children: render(args) });
8969
9119
  var TOP_LEVEL_SCOPES = ["collection", "rule", "product"];
8970
9120
  var OPT_IN_TOP_LEVEL_SCOPES = ["all"];
8971
9121
  var DRAFT_ID3 = "__draft__";
@@ -9171,7 +9321,10 @@ function RecordsAdminShellInner(props) {
9171
9321
  labels: actionLabels,
9172
9322
  icons: actionIcons
9173
9323
  } = actions ?? {};
9174
- const i18n = { ...DEFAULT_I18N, ...i18nOverride ?? {} };
9324
+ const i18n = useMemo(
9325
+ () => ({ ...DEFAULT_I18N, ...i18nOverride ?? {} }),
9326
+ [i18nOverride]
9327
+ );
9175
9328
  const icons = useMemo(() => mergeIcons(iconsOverride), [iconsOverride]);
9176
9329
  const deepLinkState = useDeepLinkState(deepLink);
9177
9330
  const multiOpenWarnedRef = useRef(false);
@@ -9928,6 +10081,7 @@ function RecordsAdminShellInner(props) {
9928
10081
  onAction: async () => {
9929
10082
  try {
9930
10083
  const updated = await SL.app.records.update(collectionId, appId, record.id, { status: next }, true);
10084
+ patchRecordStatusInCaches(queryClient, ctx, record.id, next);
9931
10085
  if (updated) {
9932
10086
  patchRecordIntoCaches(queryClient, ctx, updated);
9933
10087
  queryClient.invalidateQueries({
@@ -9981,7 +10135,13 @@ function RecordsAdminShellInner(props) {
9981
10135
  ] });
9982
10136
  }
9983
10137
  const previewAnchorRef = previewReopenAnchorRef;
9984
- const previewBody = renderPreview && effectivePreviewScope ? renderPreview({ resolved: editorCtx.value, previewScope: effectivePreviewScope }) : null;
10138
+ const previewBody = renderPreview && effectivePreviewScope ? /* @__PURE__ */ jsx(
10139
+ CallbackRenderer,
10140
+ {
10141
+ render: renderPreview,
10142
+ args: { resolved: editorCtx.value, previewScope: effectivePreviewScope }
10143
+ }
10144
+ ) : null;
9985
10145
  const scopePicker = previewScopePicker && effectivePreviewScope ? /* @__PURE__ */ jsx(
9986
10146
  PreviewScopePicker,
9987
10147
  {
@@ -10042,6 +10202,7 @@ function RecordsAdminShellInner(props) {
10042
10202
  current: selectedSummary.lifecycleStatus,
10043
10203
  i18n,
10044
10204
  onChanged: (_next, updated) => {
10205
+ patchRecordStatusInCaches(queryClient, ctx, selectedSummary.id, _next);
10045
10206
  if (updated) {
10046
10207
  patchRecordIntoCaches(queryClient, ctx, updated);
10047
10208
  queryClient.invalidateQueries({
@@ -10071,6 +10232,7 @@ function RecordsAdminShellInner(props) {
10071
10232
  to: e.to
10072
10233
  }),
10073
10234
  onChanged: (_next, updated) => {
10235
+ patchRecordStatusInCaches(queryClient, ctx, selectedSummary.id, _next);
10074
10236
  if (updated) {
10075
10237
  patchRecordIntoCaches(queryClient, ctx, updated);
10076
10238
  queryClient.invalidateQueries({
@@ -10139,7 +10301,13 @@ function RecordsAdminShellInner(props) {
10139
10301
  renderEditor
10140
10302
  }
10141
10303
  ),
10142
- fallback: renderEditor(editorCtx)
10304
+ fallback: /* @__PURE__ */ jsx(
10305
+ CallbackRenderer,
10306
+ {
10307
+ render: renderEditor,
10308
+ args: editorCtx
10309
+ }
10310
+ )
10143
10311
  }
10144
10312
  )
10145
10313
  }
@@ -10327,7 +10495,7 @@ function RecordsAdminShellInner(props) {
10327
10495
  if (keys.length === 0) return null;
10328
10496
  const key = `facets:${keys.join("|")}`;
10329
10497
  const label2 = keys.map((k) => ruleLabelLookup?.facetLabel?.(k) ?? k).join(" \xB7 ");
10330
- return { key, label: label2 };
10498
+ return { key, label: label2, facetKeys: keys };
10331
10499
  };
10332
10500
  }, [groupBy, isRuleTab, isAllTab, isCollection, ruleLabelLookup]);
10333
10501
  const [bulkRuleEditTarget, setBulkRuleEditTarget] = useState(null);
@@ -10496,6 +10664,17 @@ function RecordsAdminShellInner(props) {
10496
10664
  label: i18n.lifecycleBadgeArchived.replace("{n}", String(lc.archived)),
10497
10665
  tone: "neutral"
10498
10666
  });
10667
+ let rowStatus = rep.status;
10668
+ let rowTone;
10669
+ if (lc.active > 0) {
10670
+ rowStatus = "configured";
10671
+ } else if (lc.draft === 0 && lc.archived > 0 && lc.other === 0) {
10672
+ rowStatus = "partial";
10673
+ rowTone = "muted";
10674
+ } else if (lc.draft > 0 || lc.other > 0 || lc.archived > 0) {
10675
+ rowStatus = "partial";
10676
+ rowTone = "warning";
10677
+ }
10499
10678
  return {
10500
10679
  ...rep,
10501
10680
  // Title carries the count + identity; the rule chips below render
@@ -10503,6 +10682,8 @@ function RecordsAdminShellInner(props) {
10503
10682
  // repeat the same information in two places.
10504
10683
  label: `${count} ${itemNoun}${count === 1 ? "" : "s"}`,
10505
10684
  subtitle: void 0,
10685
+ status: rowStatus,
10686
+ toneHint: rowTone,
10506
10687
  badges: [...rep.badges ?? [], ...lifecycleBadges],
10507
10688
  // Stash counts on the row for the sort comparator below.
10508
10689
  __lifecycleCounts: lc
@@ -11126,6 +11307,7 @@ function RecordsAdminShellInner(props) {
11126
11307
  for (const id of ids) {
11127
11308
  try {
11128
11309
  const updated = await SL.app.records.update(collectionId, appId, id, { status: archivedStatusValue }, true);
11310
+ patchRecordStatusInCaches(queryClient, ctx, id, archivedStatusValue);
11129
11311
  if (updated) patchRecordIntoCaches(queryClient, ctx, updated);
11130
11312
  onTelemetry?.({
11131
11313
  type: "recordAction.invoke",
@@ -11175,7 +11357,7 @@ function RecordsAdminShellInner(props) {
11175
11357
  isGlobalTab && !isCollection && !hasSingletonConflicts ? null : /* @__PURE__ */ jsxs(Fragment, { children: [
11176
11358
  leftLoading && /* @__PURE__ */ jsx(LoadingState, {}),
11177
11359
  !leftLoading && leftError && /* @__PURE__ */ jsx(ErrorState, { error: leftError }),
11178
- !leftLoading && !leftError && decoratedLeftItems.length === 0 && (renderEmptyState ? renderEmptyState({ scope: activeScope }) : /* @__PURE__ */ jsx(
11360
+ !leftLoading && !leftError && decoratedLeftItems.length === 0 && (renderEmptyState ? /* @__PURE__ */ jsx(CallbackRenderer, { render: renderEmptyState, args: { scope: activeScope } }) : /* @__PURE__ */ jsx(
11179
11361
  EmptyState,
11180
11362
  {
11181
11363
  icon: search ? icons.empty.search : icons.empty.default,