@proveanything/smartlinks-utils-ui 0.12.22 → 0.12.24

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.
@@ -154,6 +154,13 @@ interface ResolvedRecord<TData = unknown> {
154
154
  * against.
155
155
  */
156
156
  facetRule?: FacetRule | null;
157
+ /**
158
+ * Lifecycle status (`active` / `archived` / `draft` / host custom) of
159
+ * the resolved record, when `source === 'self'` or `'inherited'`.
160
+ * Surfaced so the editor footer's lifecycle menu can render against
161
+ * pinned-anchor (singleton) records the rail does not list directly.
162
+ */
163
+ lifecycleStatus?: string;
157
164
  }
158
165
 
159
166
  interface EditorContext<TData = unknown> {
@@ -937,6 +944,22 @@ interface RecordsAdminShellProps<TData = unknown> {
937
944
  label: string;
938
945
  scopes: ScopeKind[];
939
946
  defaultScope?: ScopeKind;
947
+ /**
948
+ * Hard ceiling on inheritance-chain drill-down depth, regardless of what
949
+ * the collection has enabled.
950
+ *
951
+ * - `'product'` — never expose variant or batch tabs even if the collection
952
+ * has those rungs turned on. Use when an app deliberately wants its
953
+ * records to stay product-level (e.g. editorial content that must be
954
+ * consistent across all variants).
955
+ * - `'variant'` — allow variant drill-down but hide batches.
956
+ * - `'batch'` (default) — allow the full chain when the collection supports it.
957
+ *
958
+ * Note: this is intentionally framed as a depth ceiling rather than a
959
+ * per-dimension list, so future sub-product dimensions are covered
960
+ * automatically. The `scopes` prop continues to define top-level tabs only.
961
+ */
962
+ maxDrillDepth?: 'product' | 'variant' | 'batch';
940
963
  /**
941
964
  * Context from the host URL (productId/variantId/batchId).
942
965
  * When provided, the browser is constrained to that subtree:
@@ -1820,6 +1843,10 @@ interface Props$a {
1820
1843
  batches: ProductChildItem[];
1821
1844
  variantsLoading: boolean;
1822
1845
  batchesLoading: boolean;
1846
+ /** Variant ids that already have a record at this product. */
1847
+ variantsWithRecord?: Set<string>;
1848
+ /** Batch ids that already have a record at this product. */
1849
+ batchesWithRecord?: Set<string>;
1823
1850
  /** Editor body rendered to the right of the picker. */
1824
1851
  children: ReactNode;
1825
1852
  /**
@@ -1831,7 +1858,7 @@ interface Props$a {
1831
1858
  */
1832
1859
  hideSingleTab?: boolean;
1833
1860
  }
1834
- declare const ProductDrillDown: ({ productLabel, showVariants, showBatches, active, onChange, selectedChildId, onSelectChild, variants, batches, variantsLoading, batchesLoading, children, hideSingleTab, }: Props$a) => react_jsx_runtime.JSX.Element;
1861
+ declare const ProductDrillDown: ({ productLabel, showVariants, showBatches, active, onChange, selectedChildId, onSelectChild, variants, batches, variantsLoading, batchesLoading, variantsWithRecord, batchesWithRecord, children, hideSingleTab, }: Props$a) => react_jsx_runtime.JSX.Element;
1835
1862
 
1836
1863
  type PreviewMode = 'inline' | 'side' | 'tab' | 'drawer';
1837
1864
  interface CommonProps {
@@ -2219,6 +2246,7 @@ declare function useResolvedRecord<T = unknown>(args: UseResolvedRecordArgs): {
2219
2246
  matchedAt?: _proveanything_smartlinks.MatchedAt;
2220
2247
  matchedRule?: _proveanything_smartlinks.FacetRule;
2221
2248
  facetRule?: _proveanything_smartlinks.FacetRule | null;
2249
+ lifecycleStatus?: string;
2222
2250
  };
2223
2251
 
2224
2252
  interface UseCollectionItemsArgs {
@@ -16,6 +16,7 @@ import { createPortal } from 'react-dom';
16
16
  var RECORD_LIST_QK = ["records-admin", "list"];
17
17
  var COLLECTION_ITEMS_QK = ["records-admin", "collection-items"];
18
18
  var SCOPE_COUNTS_QK = ["records-admin", "scope-counts"];
19
+ var RESOLVED_RECORD_QK = ["records-admin", "resolved"];
19
20
  var matchesCtx = (queryKey, prefix, ctx) => {
20
21
  if (queryKey.length < prefix.length + 3) return false;
21
22
  for (let i = 0; i < prefix.length; i += 1) {
@@ -178,6 +179,13 @@ function patchRecordStatusInCaches(queryClient, ctx, recordId, status) {
178
179
  return touched ? { ...prev, records } : prev;
179
180
  });
180
181
  }
182
+ const resolved = queryClient.getQueriesData({
183
+ queryKey: RESOLVED_RECORD_QK
184
+ });
185
+ for (const [key, cache] of resolved) {
186
+ if (!cache || cache.recordId !== recordId) continue;
187
+ queryClient.setQueryData(key, { ...cache, lifecycleStatus: status });
188
+ }
181
189
  }
182
190
  function markScopeCountsStale(queryClient, ctx) {
183
191
  const all = queryClient.getQueriesData({
@@ -547,7 +555,8 @@ var resolveRecord = async (args) => {
547
555
  recordId: winner.id,
548
556
  parentValue: args.withParent && parent ? parent.data : void 0,
549
557
  matchedAt: winner.matchedAt,
550
- matchedRule: winner.matchedRule
558
+ matchedRule: winner.matchedRule,
559
+ lifecycleStatus: winner.status
551
560
  };
552
561
  }
553
562
  return {
@@ -557,7 +566,8 @@ var resolveRecord = async (args) => {
557
566
  recordId: winner.id,
558
567
  parentValue: args.withParent ? winner.data : void 0,
559
568
  matchedAt: winner.matchedAt,
560
- matchedRule: winner.matchedRule
569
+ matchedRule: winner.matchedRule,
570
+ lifecycleStatus: winner.status
561
571
  };
562
572
  };
563
573
 
@@ -621,7 +631,8 @@ function useResolvedRecord(args) {
621
631
  source: "self",
622
632
  sourceRef: rec.ref ?? void 0,
623
633
  recordId: rec.id,
624
- facetRule: recFacetRule
634
+ facetRule: recFacetRule,
635
+ lifecycleStatus: rec.status
625
636
  };
626
637
  }
627
638
  const target = {
@@ -676,6 +687,60 @@ var useScopeProbe = ({ SL, collectionId, admin = true, enabled = true }) => {
676
687
  error: query.error ?? null
677
688
  };
678
689
  };
690
+ var QK = ["records-admin", "product-sub-records"];
691
+ var useProductSubRecords = (args) => {
692
+ const { SL, collectionId, appId, recordType, productId, enabled = true } = args;
693
+ const queryClient = useQueryClient();
694
+ const queryKey = useMemo(
695
+ () => [...QK, collectionId, appId, recordType ?? null, productId ?? null],
696
+ [collectionId, appId, recordType, productId]
697
+ );
698
+ const query = useQuery({
699
+ queryKey,
700
+ enabled: enabled && !!collectionId && !!appId && !!productId,
701
+ staleTime: 15e3,
702
+ queryFn: async () => {
703
+ if (!productId) return { variantIds: [], batchIds: [] };
704
+ const variantIds = /* @__PURE__ */ new Set();
705
+ const batchIds = /* @__PURE__ */ new Set();
706
+ let offset = 0;
707
+ const limit = 200;
708
+ for (let i = 0; i < 20; i++) {
709
+ const res = await SL.app.records.list(
710
+ collectionId,
711
+ appId,
712
+ {
713
+ ...recordType ? { recordType } : {},
714
+ limit,
715
+ offset
716
+ },
717
+ true
718
+ ).catch(() => null);
719
+ const data = res?.data ?? [];
720
+ for (const rec of data) {
721
+ const pId = rec.productId;
722
+ if (pId !== productId) continue;
723
+ const vId = rec.variantId;
724
+ const bId = rec.batchId;
725
+ if (vId) variantIds.add(vId);
726
+ if (bId) batchIds.add(bId);
727
+ }
728
+ if (!res?.pagination?.hasMore || data.length === 0) break;
729
+ offset += data.length;
730
+ }
731
+ return { variantIds: [...variantIds], batchIds: [...batchIds] };
732
+ }
733
+ });
734
+ const refetch = () => queryClient.invalidateQueries({
735
+ queryKey: [...QK, collectionId, appId, recordType ?? null, productId ?? null]
736
+ });
737
+ return {
738
+ variantIds: new Set(query.data?.variantIds ?? []),
739
+ batchIds: new Set(query.data?.batchIds ?? []),
740
+ isLoading: query.isLoading,
741
+ refetch
742
+ };
743
+ };
679
744
  var QK_BASE = ["records-admin", "scope-counts"];
680
745
  var classify = (rec) => {
681
746
  const hasRule = !!rec.facetRule;
@@ -1037,7 +1102,7 @@ var useRecordList = (args) => {
1037
1102
  };
1038
1103
  };
1039
1104
  var LOG = "[RecordsAdmin/useFacetBrowse]";
1040
- var QK = ["records-admin", "facet-browse"];
1105
+ var QK2 = ["records-admin", "facet-browse"];
1041
1106
  var toScaffoldSummary = (facet, value) => {
1042
1107
  const facetKey = facet.key ?? "";
1043
1108
  const valueKey = value.key ?? "";
@@ -1066,7 +1131,7 @@ var useFacetBrowse = ({
1066
1131
  const hasAnyList = hasAdminList || hasPublicList;
1067
1132
  const queryEnabled = enabled && !!collectionId && hasAnyList;
1068
1133
  const query = useQuery({
1069
- queryKey: [...QK, collectionId],
1134
+ queryKey: [...QK2, collectionId],
1070
1135
  enabled: queryEnabled,
1071
1136
  staleTime: 3e4,
1072
1137
  queryFn: async () => {
@@ -1140,7 +1205,7 @@ var useFacetBrowse = ({
1140
1205
  empty: mergedItems.filter((item) => item.status === "empty").length
1141
1206
  }), [mergedItems]);
1142
1207
  const refetch = () => {
1143
- queryClient.invalidateQueries({ queryKey: [...QK, collectionId] });
1208
+ queryClient.invalidateQueries({ queryKey: [...QK2, collectionId] });
1144
1209
  };
1145
1210
  return {
1146
1211
  items: filteredItems,
@@ -1157,7 +1222,7 @@ var useFacetBrowse = ({
1157
1222
  vocabulary: query.data ?? []
1158
1223
  };
1159
1224
  };
1160
- var QK2 = ["records-admin", "product-browse"];
1225
+ var QK3 = ["records-admin", "product-browse"];
1161
1226
  var toBrowseItem = (p) => ({
1162
1227
  id: p.id ?? p.productId ?? "",
1163
1228
  name: p.name ?? p.id ?? "Untitled",
@@ -1168,7 +1233,7 @@ var useProductBrowse = (args) => {
1168
1233
  const { SL, collectionId, search = "", pageSize = 50, enabled = true, admin = true } = args;
1169
1234
  const queryClient = useQueryClient();
1170
1235
  const queryKey = useMemo(
1171
- () => [...QK2, collectionId, search.trim(), pageSize, admin],
1236
+ () => [...QK3, collectionId, search.trim(), pageSize, admin],
1172
1237
  [collectionId, search, pageSize, admin]
1173
1238
  );
1174
1239
  const query = useInfiniteQuery({
@@ -1219,7 +1284,7 @@ var useProductBrowse = (args) => {
1219
1284
  () => query.data?.pages.flatMap((p) => p.items) ?? [],
1220
1285
  [query.data]
1221
1286
  );
1222
- const refetch = () => queryClient.invalidateQueries({ queryKey: [...QK2, collectionId] });
1287
+ const refetch = () => queryClient.invalidateQueries({ queryKey: [...QK3, collectionId] });
1223
1288
  return {
1224
1289
  items,
1225
1290
  total: query.data?.pages[query.data.pages.length - 1]?.total,
@@ -1231,7 +1296,7 @@ var useProductBrowse = (args) => {
1231
1296
  refetch
1232
1297
  };
1233
1298
  };
1234
- var QK3 = ["records-admin", "product-children"];
1299
+ var QK4 = ["records-admin", "product-children"];
1235
1300
  var variantToItem = (v) => ({
1236
1301
  id: v.id ?? v.variantId ?? "",
1237
1302
  name: v.name ?? v.label ?? v.id ?? "Untitled variant",
@@ -1246,7 +1311,7 @@ var useProductChildren = (args) => {
1246
1311
  const { SL, collectionId, productId, kind, enabled = true } = args;
1247
1312
  const queryClient = useQueryClient();
1248
1313
  const queryKey = useMemo(
1249
- () => [...QK3, collectionId, productId ?? null, kind],
1314
+ () => [...QK4, collectionId, productId ?? null, kind],
1250
1315
  [collectionId, productId, kind]
1251
1316
  );
1252
1317
  const query = useQuery({
@@ -1264,7 +1329,7 @@ var useProductChildren = (args) => {
1264
1329
  }
1265
1330
  });
1266
1331
  const refetch = () => queryClient.invalidateQueries({
1267
- queryKey: [...QK3, collectionId, productId ?? null]
1332
+ queryKey: [...QK4, collectionId, productId ?? null]
1268
1333
  });
1269
1334
  return {
1270
1335
  items: query.data ?? [],
@@ -1376,7 +1441,7 @@ function useShellBrowser(opts) {
1376
1441
  refetchAll
1377
1442
  };
1378
1443
  }
1379
- var QK4 = ["records-admin", "single-product"];
1444
+ var QK5 = ["records-admin", "single-product"];
1380
1445
  var toBrowseItem2 = (p, fallbackId) => ({
1381
1446
  id: p?.id ?? p?.productId ?? fallbackId,
1382
1447
  name: p?.name ?? fallbackId,
@@ -1386,7 +1451,7 @@ var toBrowseItem2 = (p, fallbackId) => ({
1386
1451
  var useSingleProduct = (args) => {
1387
1452
  const { SL, collectionId, productId, enabled = true, admin = true } = args;
1388
1453
  const query = useQuery({
1389
- queryKey: [...QK4, collectionId, productId, admin],
1454
+ queryKey: [...QK5, collectionId, productId, admin],
1390
1455
  enabled: enabled && !!collectionId && !!productId,
1391
1456
  staleTime: 6e4,
1392
1457
  queryFn: async () => {
@@ -6221,6 +6286,8 @@ var ProductDrillDown = ({
6221
6286
  batches,
6222
6287
  variantsLoading,
6223
6288
  batchesLoading,
6289
+ variantsWithRecord,
6290
+ batchesWithRecord,
6224
6291
  children,
6225
6292
  hideSingleTab
6226
6293
  }) => {
@@ -6231,6 +6298,7 @@ var ProductDrillDown = ({
6231
6298
  const childList = active === "variant" ? variants : active === "batch" ? batches : [];
6232
6299
  const childLoading = active === "variant" ? variantsLoading : active === "batch" ? batchesLoading : false;
6233
6300
  const childEmptyLabel = active === "variant" ? "No variants" : "No batches";
6301
+ const childHasRecord = active === "variant" ? variantsWithRecord : active === "batch" ? batchesWithRecord : void 0;
6234
6302
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
6235
6303
  showTabStrip && /* @__PURE__ */ jsx(
6236
6304
  "div",
@@ -6280,7 +6348,8 @@ var ProductDrillDown = ({
6280
6348
  !childLoading && childList.length === 0 && /* @__PURE__ */ jsx("div", { className: "p-4 text-xs", style: { color: "hsl(var(--ra-muted-text))" }, children: childEmptyLabel }),
6281
6349
  !childLoading && childList.length > 0 && /* @__PURE__ */ jsx("ul", { className: "divide-y", style: { borderColor: "hsl(var(--ra-border))" }, children: childList.map((c) => {
6282
6350
  const isActive2 = c.id === selectedChildId;
6283
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
6351
+ const hasRecord = childHasRecord?.has(c.id) ?? false;
6352
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
6284
6353
  "button",
6285
6354
  {
6286
6355
  type: "button",
@@ -6289,10 +6358,20 @@ var ProductDrillDown = ({
6289
6358
  "w-full text-left px-3 py-2 transition-colors hover:bg-[hsl(var(--ra-muted))]",
6290
6359
  isActive2 && "ra-row-active"
6291
6360
  ),
6292
- children: [
6293
- /* @__PURE__ */ jsx("div", { className: "text-sm truncate", style: { color: "hsl(var(--ra-text))" }, children: c.name }),
6294
- c.subtitle && /* @__PURE__ */ jsx("div", { className: "text-xs truncate", style: { color: "hsl(var(--ra-muted-text))" }, children: c.subtitle })
6295
- ]
6361
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 min-w-0", children: [
6362
+ hasRecord ? /* @__PURE__ */ jsx(
6363
+ CheckCircle2,
6364
+ {
6365
+ "aria-label": "Has record",
6366
+ className: "w-3.5 h-3.5 shrink-0 ra-status-own-icon",
6367
+ style: { color: "hsl(var(--ra-status-own, 142 71% 45%))" }
6368
+ }
6369
+ ) : /* @__PURE__ */ jsx("span", { className: "w-3.5 h-3.5 shrink-0", "aria-hidden": "true" }),
6370
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
6371
+ /* @__PURE__ */ jsx("div", { className: "text-sm truncate", style: { color: "hsl(var(--ra-text))" }, children: c.name }),
6372
+ c.subtitle && /* @__PURE__ */ jsx("div", { className: "text-xs truncate", style: { color: "hsl(var(--ra-muted-text))" }, children: c.subtitle })
6373
+ ] })
6374
+ ] })
6296
6375
  }
6297
6376
  ) }, c.id);
6298
6377
  }) })
@@ -9234,6 +9313,7 @@ function RecordsAdminShellInner(props) {
9234
9313
  defaultScope,
9235
9314
  contextScope,
9236
9315
  contextScopeMode = "strict",
9316
+ maxDrillDepth = "batch",
9237
9317
  renderEditor,
9238
9318
  intro,
9239
9319
  csvSchema,
@@ -9427,13 +9507,15 @@ function RecordsAdminShellInner(props) {
9427
9507
  if (!productPinnedFromContext || contextScopeMode !== "strict") return topLevelScopes;
9428
9508
  return topLevelScopes.filter((s) => s !== "collection" && s !== "rule" && s !== "all");
9429
9509
  }, [productPinnedFromContext, contextScopeMode, topLevelScopes]);
9510
+ const allowVariantDepth = maxDrillDepth === "variant" || maxDrillDepth === "batch";
9511
+ const allowBatchDepth = maxDrillDepth === "batch";
9430
9512
  const drillVariantsAllowed = useMemo(
9431
- () => requestedScopes.includes("variant") && (probe.isLoading || probe.hasVariants),
9432
- [requestedScopes, probe.isLoading, probe.hasVariants]
9513
+ () => allowVariantDepth && (probe.isLoading || probe.hasVariants),
9514
+ [allowVariantDepth, probe.isLoading, probe.hasVariants]
9433
9515
  );
9434
9516
  const drillBatchesAllowed = useMemo(
9435
- () => requestedScopes.includes("batch") && (probe.isLoading || probe.hasBatches),
9436
- [requestedScopes, probe.isLoading, probe.hasBatches]
9517
+ () => allowBatchDepth && (probe.isLoading || probe.hasBatches),
9518
+ [allowBatchDepth, probe.isLoading, probe.hasBatches]
9437
9519
  );
9438
9520
  const initialScope = useMemo(() => {
9439
9521
  if (contextScope?.productId && effectiveTopLevelScopes.includes("product")) return "product";
@@ -9552,6 +9634,14 @@ function RecordsAdminShellInner(props) {
9552
9634
  productId: contextScope?.productId,
9553
9635
  enabled: !!contextScope?.productId
9554
9636
  });
9637
+ const productSubRecords = useProductSubRecords({
9638
+ SL,
9639
+ collectionId,
9640
+ appId,
9641
+ recordType,
9642
+ productId: selectedProductId,
9643
+ enabled: !!selectedProductId
9644
+ });
9555
9645
  const productLookupItems = useMemo(() => {
9556
9646
  if (pinnedProduct.item) return [pinnedProduct.item];
9557
9647
  return productBrowse.items;
@@ -10232,7 +10322,18 @@ function RecordsAdminShellInner(props) {
10232
10322
  ]
10233
10323
  }
10234
10324
  ) : null;
10235
- const selectedSummary = isCollection && selectedItemId && !isDraftId3(selectedItemId) ? collectionItems.items.find((r) => r.id === selectedItemId || r.itemId === selectedItemId) : 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) : void 0;
10325
+ let selectedSummary = isCollection && selectedItemId && !isDraftId3(selectedItemId) ? collectionItems.items.find((r) => r.id === selectedItemId || r.itemId === selectedItemId) : 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) : void 0;
10326
+ if (!selectedSummary && !isCollection && resolved.source === "self" && resolved.recordId && editingTargetScope) {
10327
+ selectedSummary = {
10328
+ id: resolved.recordId,
10329
+ ref: resolved.sourceRef ?? editingTargetScope.raw,
10330
+ scope: editingTargetScope,
10331
+ data: resolved.data,
10332
+ status: "configured",
10333
+ label: "",
10334
+ lifecycleStatus: resolved.lifecycleStatus
10335
+ };
10336
+ }
10236
10337
  const editorLifecycleControl = selectedSummary?.id ? /* @__PURE__ */ jsx(
10237
10338
  LifecycleStatusControl,
10238
10339
  {
@@ -11590,61 +11691,70 @@ function RecordsAdminShellInner(props) {
11590
11691
  }
11591
11692
  ),
11592
11693
  ruleWizardStep === null && !isCollection && !editingScope && activeScope === "product" && !selectedProductId && /* @__PURE__ */ jsx(EmptyState, { title: i18n.emptyTitle, body: i18n.emptyBody }),
11593
- ruleWizardStep === null && isProductTab && selectedProductId && (!isCollection || selectedItemId) && !(!isCollection && editingTargetScope && resolved.source !== "self" && selectedRecordId !== DRAFT_ID3) && /* @__PURE__ */ jsx(
11594
- ProductDrillDown,
11595
- {
11596
- productLabel: productBrowse.items.find((p) => p.id === selectedProductId)?.name ?? selectedProductId,
11597
- showVariants: drillVariantsAllowed,
11598
- showBatches: drillBatchesAllowed,
11599
- hideSingleTab: editorTabs === "off" || editorTabs === "multi",
11600
- active: drillTab,
11601
- onChange: (t) => {
11602
- void runWithGuard(() => {
11603
- setDrillTab(t);
11604
- if (t === "product") {
11605
- setSelectedVariantId(void 0);
11606
- setSelectedBatchId(void 0);
11607
- }
11608
- });
11609
- },
11610
- selectedChildId: drillTab === "variant" ? selectedVariantId : drillTab === "batch" ? selectedBatchId : void 0,
11611
- onSelectChild: (id) => {
11612
- void runWithGuard(() => {
11613
- if (drillTab === "variant") setSelectedVariantId(id);
11614
- else if (drillTab === "batch") setSelectedBatchId(id);
11615
- });
11616
- },
11617
- variants: variantChildren.items,
11618
- batches: batchChildren.items,
11619
- variantsLoading: variantChildren.isLoading,
11620
- batchesLoading: batchChildren.isLoading,
11621
- children: editingTargetScope ? renderEditorWithPreview() : /* @__PURE__ */ jsx(
11622
- EmptyState,
11623
- {
11624
- title: drillTab === "variant" ? "Pick a variant" : "Pick a batch",
11625
- body: `Select a ${drillTab} on the left to edit its ${recordType ?? label.toLowerCase()}.`
11626
- }
11627
- )
11628
- }
11629
- ),
11630
- ruleWizardStep === null && isProductTab && selectedProductId && !isCollection && editingTargetScope && resolved.source !== "self" && selectedRecordId !== DRAFT_ID3 ? (() => {
11631
- const productName = productLookupItems.find((p) => p.id === selectedProductId)?.name ?? selectedProductId;
11694
+ ruleWizardStep === null && isProductTab && selectedProductId && (!isCollection || selectedItemId) && (() => {
11695
+ const productName = productLookupItems.find((p) => p.id === selectedProductId)?.name ?? productBrowse.items.find((p) => p.id === selectedProductId)?.name ?? selectedProductId;
11696
+ const variantName = drillTab === "variant" && selectedVariantId ? variantChildren.items.find((v) => v.id === selectedVariantId)?.name ?? selectedVariantId : void 0;
11697
+ const batchName = drillTab === "batch" && selectedBatchId ? batchChildren.items.find((b) => b.id === selectedBatchId)?.name ?? selectedBatchId : void 0;
11698
+ const targetKind = variantName ? "variant" : batchName ? "batch" : "product";
11699
+ const targetName = variantName ?? batchName ?? productName;
11632
11700
  const pasteEntry = wizardClipboard.entry;
11633
11701
  const pasteSourceLabel = pasteEntry?.sourceLabel ?? pasteEntry?.sourceScope.raw;
11702
+ const onlyNonActive = resolved.source === "self" && !!resolved.lifecycleStatus && !resolvedActiveStatuses.includes(resolved.lifecycleStatus);
11703
+ const needsChooser = !isCollection && editingTargetScope && selectedRecordId !== DRAFT_ID3 && (resolved.source !== "self" || onlyNonActive);
11704
+ const chooserTitle = onlyNonActive ? `No active ${itemNoun} for ${targetKind}: ${targetName}` : `No ${itemNoun} set for ${targetKind}: ${targetName}`;
11705
+ const chooserBody = onlyNonActive ? `The existing ${itemNoun} for this ${targetKind} is ${resolved.lifecycleStatus}. Start a fresh ${itemNoun} to replace it, or copy from the global default.` : `Choose whether to create a fresh ${itemNoun} for this ${targetKind} or start from the global default.`;
11634
11706
  return /* @__PURE__ */ jsx(
11635
- CreateRecordChooser,
11707
+ ProductDrillDown,
11636
11708
  {
11637
- title: `No ${itemNoun} set for product: ${productName}`,
11638
- body: `Choose whether to create a fresh ${itemNoun} for this product or start from the global default.`,
11639
- primaryLabel: "Start blank",
11640
- onPrimary: () => onCreateProductRecord("blank"),
11641
- secondaryLabel: singletonGlobalSeedAvailable ? "Copy from global" : void 0,
11642
- onSecondary: singletonGlobalSeedAvailable ? () => onCreateProductRecord("global") : void 0,
11643
- tertiaryLabel: pasteEntry ? pasteSourceLabel ? `Paste from ${pasteSourceLabel}` : "Paste from clipboard" : void 0,
11644
- onTertiary: pasteEntry ? () => onCreateProductRecord("paste") : void 0
11709
+ productLabel: productName,
11710
+ showVariants: drillVariantsAllowed,
11711
+ showBatches: drillBatchesAllowed,
11712
+ hideSingleTab: editorTabs === "off" || editorTabs === "multi",
11713
+ active: drillTab,
11714
+ onChange: (t) => {
11715
+ void runWithGuard(() => {
11716
+ setDrillTab(t);
11717
+ if (t === "product") {
11718
+ setSelectedVariantId(void 0);
11719
+ setSelectedBatchId(void 0);
11720
+ }
11721
+ });
11722
+ },
11723
+ selectedChildId: drillTab === "variant" ? selectedVariantId : drillTab === "batch" ? selectedBatchId : void 0,
11724
+ onSelectChild: (id) => {
11725
+ void runWithGuard(() => {
11726
+ if (drillTab === "variant") setSelectedVariantId(id);
11727
+ else if (drillTab === "batch") setSelectedBatchId(id);
11728
+ });
11729
+ },
11730
+ variants: variantChildren.items,
11731
+ batches: batchChildren.items,
11732
+ variantsLoading: variantChildren.isLoading,
11733
+ batchesLoading: batchChildren.isLoading,
11734
+ variantsWithRecord: productSubRecords.variantIds,
11735
+ batchesWithRecord: productSubRecords.batchIds,
11736
+ children: needsChooser ? /* @__PURE__ */ jsx(
11737
+ CreateRecordChooser,
11738
+ {
11739
+ title: chooserTitle,
11740
+ body: chooserBody,
11741
+ primaryLabel: "Start blank",
11742
+ onPrimary: () => onCreateProductRecord("blank"),
11743
+ secondaryLabel: singletonGlobalSeedAvailable ? "Copy from global" : void 0,
11744
+ onSecondary: singletonGlobalSeedAvailable ? () => onCreateProductRecord("global") : void 0,
11745
+ tertiaryLabel: pasteEntry ? pasteSourceLabel ? `Paste from ${pasteSourceLabel}` : "Paste from clipboard" : void 0,
11746
+ onTertiary: pasteEntry ? () => onCreateProductRecord("paste") : void 0
11747
+ }
11748
+ ) : editingTargetScope ? renderEditorWithPreview() : /* @__PURE__ */ jsx(
11749
+ EmptyState,
11750
+ {
11751
+ title: drillTab === "variant" ? "Pick a variant" : "Pick a batch",
11752
+ body: `Select a ${drillTab} on the left to edit its ${recordType ?? label.toLowerCase()}.`
11753
+ }
11754
+ )
11645
11755
  }
11646
11756
  );
11647
- })() : null,
11757
+ })(),
11648
11758
  ruleWizardStep === null && !isProductTab && editingTargetScope && (!isCollection || selectedItemId) && renderEditorWithPreview()
11649
11759
  ] })
11650
11760
  ]