@proveanything/smartlinks-utils-ui 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-76Y4UTYQ.js → chunk-WB775Z2I.js} +66 -60
- package/dist/chunk-WB775Z2I.js.map +1 -0
- package/dist/components/RecordsAdmin/index.d.ts +139 -86
- package/dist/components/RecordsAdmin/index.js +433 -266
- package/dist/components/RecordsAdmin/index.js.map +1 -1
- package/dist/records-JWS6LKJ2.js +3 -0
- package/dist/{records-AUJWCB7Q.js.map → records-JWS6LKJ2.js.map} +1 -1
- package/package.json +6 -6
- package/dist/chunk-76Y4UTYQ.js.map +0 -1
- package/dist/records-AUJWCB7Q.js +0 -3
|
@@ -2,8 +2,8 @@ import { styleInject } from '../../chunk-HXJLROC2.js';
|
|
|
2
2
|
import { FacetRuleEditor } from '../../chunk-JMCV6FOW.js';
|
|
3
3
|
import { useFacets } from '../../chunk-4LHF5JB7.js';
|
|
4
4
|
import { cn } from '../../chunk-L7FQ52F5.js';
|
|
5
|
-
import { listRecords,
|
|
6
|
-
export { bulkDelete, bulkUpsert,
|
|
5
|
+
import { listRecords, parsedRefToTarget, parsedRefToScope, matchRecords, scopesEqual, getRecordById, updateRecord, upsertRecord, removeRecord } from '../../chunk-WB775Z2I.js';
|
|
6
|
+
export { bulkDelete, bulkUpsert, getRecordById, listRecords, matchRecords, parsedRefToScope, parsedRefToTarget, removeRecord, restoreRecord, scopesEqual, upsertRecord } from '../../chunk-WB775Z2I.js';
|
|
7
7
|
import { createContext, useMemo, useState, useEffect, useCallback, useRef, useContext, createElement } from 'react';
|
|
8
8
|
import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, SlidersHorizontal, Globe, Tag, Boxes, Layers, Package, Rows3, List, ChevronRight, Eraser, ClipboardPaste, Box, X, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, Search, CornerDownLeft, Circle, AlertCircle, Undo2, Save, Target, Settings2 } from 'lucide-react';
|
|
9
9
|
import { useQueryClient, useInfiniteQuery, useQuery } from '@tanstack/react-query';
|
|
@@ -128,7 +128,8 @@ var DEFAULT_I18N = {
|
|
|
128
128
|
pasteConfirmReplace: "Replace",
|
|
129
129
|
pasteConfirmCancel: "Cancel",
|
|
130
130
|
pasteWarnTitle: "Cross-scope paste",
|
|
131
|
-
pasteWarnContinue: "Continue"
|
|
131
|
+
pasteWarnContinue: "Continue",
|
|
132
|
+
itemsAllLabel: "All items"
|
|
132
133
|
};
|
|
133
134
|
|
|
134
135
|
// src/components/RecordsAdmin/types/presentation.ts
|
|
@@ -137,7 +138,7 @@ var ALL_ITEM_VIEWS = ["table", "cards", "gallery"];
|
|
|
137
138
|
|
|
138
139
|
// src/components/RecordsAdmin/types/deepLink.ts
|
|
139
140
|
var DEFAULT_DEEP_LINK_PARAM_NAMES = {
|
|
140
|
-
|
|
141
|
+
recordId: "recordId",
|
|
141
142
|
scope: "scope",
|
|
142
143
|
view: "view"
|
|
143
144
|
};
|
|
@@ -149,11 +150,7 @@ var KIND_KEYS = {
|
|
|
149
150
|
variant: "variantId",
|
|
150
151
|
batch: "batchId",
|
|
151
152
|
proof: "proofId",
|
|
152
|
-
collection: "collectionId"
|
|
153
|
-
// `rule` records carry an opaque id under the `rule:` prefix; we expose
|
|
154
|
-
// the id via `productId`-equivalent slot to keep ParsedRef flat. Resolved
|
|
155
|
-
// refs use the `ruleId` field (added below) so callers can disambiguate.
|
|
156
|
-
rule: "ruleId"
|
|
153
|
+
collection: "collectionId"
|
|
157
154
|
};
|
|
158
155
|
var parseRef = (raw) => {
|
|
159
156
|
const parsed = { kind: "collection", raw };
|
|
@@ -173,11 +170,9 @@ var parseRef = (raw) => {
|
|
|
173
170
|
} else {
|
|
174
171
|
parsed.facetId = id;
|
|
175
172
|
}
|
|
176
|
-
} else if (k === "item") {
|
|
177
|
-
parsed.itemId = id;
|
|
178
|
-
continue;
|
|
179
173
|
} else if (k in KIND_KEYS) {
|
|
180
|
-
|
|
174
|
+
const slot = KIND_KEYS[k];
|
|
175
|
+
parsed[slot] = id;
|
|
181
176
|
}
|
|
182
177
|
if (k !== "collection") kind = k;
|
|
183
178
|
}
|
|
@@ -193,7 +188,6 @@ var buildRef = (a) => {
|
|
|
193
188
|
if (a.variantId) parts.push(`variant:${a.variantId}`);
|
|
194
189
|
if (a.batchId) parts.push(`batch:${a.batchId}`);
|
|
195
190
|
if (a.proofId) parts.push(`proof:${a.proofId}`);
|
|
196
|
-
if (a.itemId) parts.push(`item:${a.itemId}`);
|
|
197
191
|
return parts.join("/");
|
|
198
192
|
};
|
|
199
193
|
var resolutionChain = (target, supportedScopes) => {
|
|
@@ -215,35 +209,26 @@ var resolutionChain = (target, supportedScopes) => {
|
|
|
215
209
|
}
|
|
216
210
|
return Array.from(new Set(chain));
|
|
217
211
|
};
|
|
218
|
-
var splitItemRef = (raw) => {
|
|
219
|
-
if (!raw) return { scopeRef: "" };
|
|
220
|
-
const segs = raw.split("/").filter(Boolean);
|
|
221
|
-
const last = segs[segs.length - 1];
|
|
222
|
-
if (last && last.startsWith("item:")) {
|
|
223
|
-
return { scopeRef: segs.slice(0, -1).join("/"), itemId: last.slice("item:".length) };
|
|
224
|
-
}
|
|
225
|
-
return { scopeRef: raw };
|
|
226
|
-
};
|
|
227
|
-
var buildItemRef = (scopeRef, itemId) => {
|
|
228
|
-
return scopeRef ? `${scopeRef}/item:${itemId}` : `item:${itemId}`;
|
|
229
|
-
};
|
|
230
212
|
var defaultClassify = (r) => {
|
|
231
213
|
if (!r.data) return "empty";
|
|
232
214
|
const keys = Object.keys(r.data);
|
|
233
215
|
if (keys.length === 0) return "empty";
|
|
234
216
|
return "configured";
|
|
235
217
|
};
|
|
236
|
-
var matchesScope = (kind, rec,
|
|
237
|
-
const hasRule = !!rec.facetRule
|
|
218
|
+
var matchesScope = (kind, rec, _p) => {
|
|
219
|
+
const hasRule = !!rec.facetRule;
|
|
238
220
|
if (kind === "rule") return hasRule;
|
|
239
221
|
if (hasRule) return false;
|
|
222
|
+
const productId = rec.productId ?? void 0;
|
|
223
|
+
const variantId = rec.variantId ?? void 0;
|
|
224
|
+
const batchId = rec.batchId ?? void 0;
|
|
225
|
+
const proofId = rec.proofId ?? void 0;
|
|
240
226
|
if (kind === "collection") {
|
|
241
|
-
return !
|
|
227
|
+
return !productId && !variantId && !batchId && !proofId;
|
|
242
228
|
}
|
|
243
|
-
if (kind === "product") return !!
|
|
244
|
-
if (kind === "
|
|
245
|
-
if (kind === "
|
|
246
|
-
if (kind === "batch") return !!p.batchId;
|
|
229
|
+
if (kind === "product") return !!productId && !variantId && !batchId;
|
|
230
|
+
if (kind === "variant") return !!variantId;
|
|
231
|
+
if (kind === "batch") return !!batchId;
|
|
247
232
|
return false;
|
|
248
233
|
};
|
|
249
234
|
var matchesContext = (p, ctx) => {
|
|
@@ -255,10 +240,22 @@ var matchesContext = (p, ctx) => {
|
|
|
255
240
|
};
|
|
256
241
|
var toSummary = (rec) => {
|
|
257
242
|
const ref = rec.ref ?? "";
|
|
258
|
-
const
|
|
243
|
+
const productId = rec.productId ?? void 0;
|
|
244
|
+
const variantId = rec.variantId ?? void 0;
|
|
245
|
+
const batchId = rec.batchId ?? void 0;
|
|
246
|
+
const proofId = rec.proofId ?? void 0;
|
|
247
|
+
const scope = {
|
|
248
|
+
kind: batchId ? "batch" : variantId ? "variant" : productId ? "product" : "collection",
|
|
249
|
+
raw: ref,
|
|
250
|
+
productId,
|
|
251
|
+
variantId,
|
|
252
|
+
batchId,
|
|
253
|
+
proofId
|
|
254
|
+
};
|
|
259
255
|
const facetRule = rec.facetRule ?? null;
|
|
256
|
+
if (facetRule) scope.kind = "rule";
|
|
260
257
|
const ruleLabel = facetRule && facetRule.all && facetRule.all.length > 0 ? facetRule.all.length === 1 ? "Rule \xB7 1 facet" : `Rule \xB7 ${facetRule.all.length} facets` : null;
|
|
261
|
-
const fallbackLabel = scope.batchId ?? scope.variantId ?? scope.productId ??
|
|
258
|
+
const fallbackLabel = scope.batchId ?? scope.variantId ?? scope.productId ?? ruleLabel ?? (ref || "Global record");
|
|
262
259
|
return {
|
|
263
260
|
id: rec.id,
|
|
264
261
|
ref,
|
|
@@ -364,57 +361,65 @@ var useRecordList = (args) => {
|
|
|
364
361
|
|
|
365
362
|
// src/components/RecordsAdmin/data/resolveRecord.ts
|
|
366
363
|
var resolveRecord = async (args) => {
|
|
367
|
-
if (args.target.kind === "rule" && args.target.raw) {
|
|
368
|
-
const rec = await getRecordByRef(args.ctx, args.target.raw).catch(() => null);
|
|
369
|
-
if (!rec) return { data: null, source: "empty" };
|
|
370
|
-
const recFacetRule = rec.facetRule ?? null;
|
|
371
|
-
return {
|
|
372
|
-
data: rec.data,
|
|
373
|
-
source: "self",
|
|
374
|
-
sourceRef: rec.ref ?? args.target.raw,
|
|
375
|
-
facetRule: recFacetRule
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
364
|
const target = parsedRefToTarget(args.target);
|
|
379
365
|
const editingScope = parsedRefToScope(args.target);
|
|
380
366
|
const result = await matchRecords(args.ctx, target, { strategy: "all" }).catch(() => null);
|
|
381
|
-
const
|
|
367
|
+
const entries = result?.data ?? [];
|
|
382
368
|
console.info("[RecordsAdmin/resolveRecord]", {
|
|
383
369
|
editingScope,
|
|
384
370
|
target,
|
|
385
|
-
matchCount:
|
|
386
|
-
|
|
387
|
-
|
|
371
|
+
matchCount: entries.length,
|
|
372
|
+
winnerAnchors: entries[0] && {
|
|
373
|
+
productId: entries[0].productId,
|
|
374
|
+
variantId: entries[0].variantId,
|
|
375
|
+
batchId: entries[0].batchId,
|
|
376
|
+
proofId: entries[0].proofId
|
|
377
|
+
},
|
|
378
|
+
winnerRef: entries[0]?.ref
|
|
388
379
|
});
|
|
389
|
-
if (
|
|
380
|
+
if (entries.length === 0) {
|
|
390
381
|
return { data: null, source: "empty" };
|
|
391
382
|
}
|
|
392
|
-
const
|
|
393
|
-
const
|
|
394
|
-
|
|
383
|
+
const winner = entries[0];
|
|
384
|
+
const winnerIsSelf = scopesEqual(
|
|
385
|
+
{
|
|
386
|
+
productId: winner.productId,
|
|
387
|
+
variantId: winner.variantId,
|
|
388
|
+
batchId: winner.batchId,
|
|
389
|
+
proofId: winner.proofId
|
|
390
|
+
},
|
|
391
|
+
editingScope
|
|
392
|
+
);
|
|
395
393
|
console.info("[RecordsAdmin/resolveRecord] classification", {
|
|
396
394
|
winnerIsSelf,
|
|
397
|
-
|
|
395
|
+
winnerAnchors: {
|
|
396
|
+
productId: winner.productId,
|
|
397
|
+
variantId: winner.variantId,
|
|
398
|
+
batchId: winner.batchId,
|
|
399
|
+
proofId: winner.proofId
|
|
400
|
+
},
|
|
398
401
|
editingScope
|
|
399
402
|
});
|
|
400
403
|
if (winnerIsSelf) {
|
|
401
|
-
const parent =
|
|
404
|
+
const parent = entries[1];
|
|
402
405
|
return {
|
|
403
406
|
data: winner.data,
|
|
404
407
|
source: "self",
|
|
405
408
|
sourceRef: winner.ref ?? void 0,
|
|
409
|
+
recordId: winner.id,
|
|
406
410
|
parentValue: args.withParent && parent ? parent.data : void 0,
|
|
407
|
-
matchedAt:
|
|
408
|
-
matchedRule:
|
|
411
|
+
matchedAt: winner.matchedAt,
|
|
412
|
+
matchedRule: winner.matchedRule
|
|
409
413
|
};
|
|
410
414
|
}
|
|
411
415
|
return {
|
|
412
416
|
data: winner.data,
|
|
413
417
|
source: "inherited",
|
|
414
418
|
sourceRef: winner.ref ?? void 0,
|
|
419
|
+
recordId: winner.id,
|
|
415
420
|
parentValue: args.withParent ? winner.data : void 0,
|
|
416
|
-
matchedAt:
|
|
417
|
-
matchedRule:
|
|
421
|
+
matchedAt: winner.matchedAt,
|
|
422
|
+
matchedRule: winner.matchedRule
|
|
418
423
|
};
|
|
419
424
|
};
|
|
420
425
|
|
|
@@ -432,7 +437,7 @@ var resolvedRecordQueryKey = (args) => [
|
|
|
432
437
|
args.facetId ?? null,
|
|
433
438
|
args.facetValue ?? null,
|
|
434
439
|
args.proofId ?? null,
|
|
435
|
-
args.
|
|
440
|
+
args.recordId ?? null,
|
|
436
441
|
args.withParent ?? true
|
|
437
442
|
];
|
|
438
443
|
function useResolvedRecord(args) {
|
|
@@ -447,7 +452,7 @@ function useResolvedRecord(args) {
|
|
|
447
452
|
facetId,
|
|
448
453
|
facetValue,
|
|
449
454
|
proofId,
|
|
450
|
-
|
|
455
|
+
recordId,
|
|
451
456
|
supportedScopes = DEFAULT_SCOPES,
|
|
452
457
|
enabled = true,
|
|
453
458
|
withParent = true
|
|
@@ -463,19 +468,35 @@ function useResolvedRecord(args) {
|
|
|
463
468
|
facetId,
|
|
464
469
|
facetValue,
|
|
465
470
|
proofId,
|
|
466
|
-
|
|
471
|
+
recordId,
|
|
467
472
|
withParent
|
|
468
473
|
}),
|
|
469
474
|
enabled: enabled && !!collectionId && !!appId,
|
|
470
475
|
staleTime: 15e3,
|
|
471
476
|
queryFn: async () => {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
477
|
+
if (recordId) {
|
|
478
|
+
const rec = await getRecordById({ SL, collectionId, appId, recordType }, recordId);
|
|
479
|
+
if (!rec) return { data: null, source: "empty" };
|
|
480
|
+
const recFacetRule = rec.facetRule ?? null;
|
|
481
|
+
return {
|
|
482
|
+
data: rec.data,
|
|
483
|
+
source: "self",
|
|
484
|
+
sourceRef: rec.ref ?? void 0,
|
|
485
|
+
recordId: rec.id,
|
|
486
|
+
facetRule: recFacetRule
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
const target = {
|
|
490
|
+
kind: batchId ? "batch" : variantId ? "variant" : productId ? "product" : facetId ? "facet" : "collection",
|
|
491
|
+
raw: "",
|
|
492
|
+
collectionId,
|
|
493
|
+
productId,
|
|
494
|
+
variantId,
|
|
495
|
+
batchId,
|
|
496
|
+
facetId,
|
|
497
|
+
facetValue,
|
|
498
|
+
proofId
|
|
499
|
+
};
|
|
479
500
|
return resolveRecord({
|
|
480
501
|
ctx: { SL, collectionId, appId, recordType },
|
|
481
502
|
target,
|
|
@@ -526,8 +547,8 @@ function useRulePreview(args) {
|
|
|
526
547
|
})
|
|
527
548
|
});
|
|
528
549
|
return {
|
|
529
|
-
totalMatches: query.data?.
|
|
530
|
-
sampleProductIds: query.data?.
|
|
550
|
+
totalMatches: query.data?.total ?? null,
|
|
551
|
+
sampleProductIds: (query.data?.matchingProducts ?? []).map((p) => p.productId),
|
|
531
552
|
isLoading: query.isFetching,
|
|
532
553
|
isStale: rule !== debouncedRule,
|
|
533
554
|
error: query.error ?? null
|
|
@@ -593,7 +614,10 @@ function useRecordEditor(args) {
|
|
|
593
614
|
}, [scope.raw, resolved.source, resolved.sourceRef]);
|
|
594
615
|
const isDirty = !isEqual(value, savedSnapshot) || !isEqual(facetRule, savedFacetRule);
|
|
595
616
|
const save = useCallback(async () => {
|
|
596
|
-
|
|
617
|
+
const anchors = parsedRefToScope(scope);
|
|
618
|
+
const hasAnchors = !!(anchors.productId || anchors.variantId || anchors.batchId || anchors.proofId);
|
|
619
|
+
const hasRule = !!(facetRule && facetRule.all && facetRule.all.length > 0);
|
|
620
|
+
if (!hasAnchors && !hasRule && !scope.raw) return;
|
|
597
621
|
const previousSnapshot = savedSnapshot;
|
|
598
622
|
const previousRuleSnapshot = savedFacetRule;
|
|
599
623
|
resolved.source;
|
|
@@ -607,7 +631,7 @@ function useRecordEditor(args) {
|
|
|
607
631
|
facetId: scope.facetId,
|
|
608
632
|
facetValue: scope.facetValue,
|
|
609
633
|
proofId: scope.proofId,
|
|
610
|
-
|
|
634
|
+
recordId: resolved.recordId,
|
|
611
635
|
withParent: true
|
|
612
636
|
});
|
|
613
637
|
const previousCache = queryClient.getQueryData(cacheKey);
|
|
@@ -620,15 +644,26 @@ function useRecordEditor(args) {
|
|
|
620
644
|
data: value,
|
|
621
645
|
source: "self",
|
|
622
646
|
sourceRef: scope.raw,
|
|
647
|
+
recordId: resolved.recordId,
|
|
623
648
|
parentValue: previousCache?.parentValue ?? resolved.parentValue
|
|
624
649
|
});
|
|
625
650
|
try {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
}
|
|
651
|
+
if (resolved.recordId && resolved.source === "self") {
|
|
652
|
+
await updateRecord(ctx, resolved.recordId, {
|
|
653
|
+
data: value,
|
|
654
|
+
facetRule
|
|
655
|
+
});
|
|
656
|
+
} else {
|
|
657
|
+
await upsertRecord(ctx, {
|
|
658
|
+
// External ref only when the underlying scope already carries
|
|
659
|
+
// one (e.g. rule:{id} for an existing rule record). Empty for
|
|
660
|
+
// anchor-only writes — server addresses by anchors.
|
|
661
|
+
ref: scope.kind === "rule" && scope.raw ? scope.raw : void 0,
|
|
662
|
+
scope: anchors,
|
|
663
|
+
data: value,
|
|
664
|
+
facetRule
|
|
665
|
+
});
|
|
666
|
+
}
|
|
632
667
|
onSaved?.();
|
|
633
668
|
} catch (err) {
|
|
634
669
|
setSavedSnapshot(previousSnapshot);
|
|
@@ -645,16 +680,17 @@ function useRecordEditor(args) {
|
|
|
645
680
|
} finally {
|
|
646
681
|
setIsSaving(false);
|
|
647
682
|
}
|
|
648
|
-
}, [scope.raw, value, savedSnapshot, facetRule, savedFacetRule, resolved.source, resolved.parentValue]);
|
|
683
|
+
}, [scope.raw, value, savedSnapshot, facetRule, savedFacetRule, resolved.source, resolved.parentValue, resolved.recordId]);
|
|
649
684
|
const reset = useCallback(() => {
|
|
650
685
|
setValue(savedSnapshot);
|
|
651
686
|
setFacetRule(savedFacetRule);
|
|
652
687
|
}, [savedSnapshot, savedFacetRule]);
|
|
653
688
|
const remove = useCallback(async () => {
|
|
654
|
-
if (resolved.source !== "self"
|
|
655
|
-
|
|
689
|
+
if (resolved.source !== "self") return;
|
|
690
|
+
if (!resolved.recordId) return;
|
|
691
|
+
await removeRecord(ctx, resolved.recordId);
|
|
656
692
|
onDeleted?.();
|
|
657
|
-
}, [resolved.source,
|
|
693
|
+
}, [resolved.source, resolved.recordId]);
|
|
658
694
|
const effectiveSource = optimisticSource ?? resolved.source;
|
|
659
695
|
const isRuleScope = scope.kind === "rule";
|
|
660
696
|
const ruleValid = !isRuleScope || isFacetRuleValid(facetRule);
|
|
@@ -1648,9 +1684,11 @@ var DefaultRecordRow = ({ record, ctx, compact = false }) => {
|
|
|
1648
1684
|
};
|
|
1649
1685
|
var RecordList = ({
|
|
1650
1686
|
items,
|
|
1651
|
-
|
|
1687
|
+
selectedId,
|
|
1688
|
+
selectedAnchorKey,
|
|
1652
1689
|
onSelect,
|
|
1653
|
-
|
|
1690
|
+
dirtyId,
|
|
1691
|
+
dirtyAnchorKey,
|
|
1654
1692
|
presentation = "list",
|
|
1655
1693
|
renderListRow,
|
|
1656
1694
|
groupBy,
|
|
@@ -1658,10 +1696,14 @@ var RecordList = ({
|
|
|
1658
1696
|
}) => {
|
|
1659
1697
|
const buildCtx = (item) => {
|
|
1660
1698
|
const cb = rowClipboard ? rowClipboard(item) : null;
|
|
1699
|
+
const idMatch = selectedId != null && item.id != null && item.id === selectedId;
|
|
1700
|
+
const anchorMatch = selectedAnchorKey != null && item.ref === selectedAnchorKey;
|
|
1701
|
+
const dirtyIdMatch = dirtyId != null && item.id != null && item.id === dirtyId;
|
|
1702
|
+
const dirtyAnchorMatch = dirtyAnchorKey != null && item.ref === dirtyAnchorKey;
|
|
1661
1703
|
return {
|
|
1662
|
-
selected:
|
|
1704
|
+
selected: idMatch || anchorMatch,
|
|
1663
1705
|
onSelect: () => onSelect(item),
|
|
1664
|
-
isDirty:
|
|
1706
|
+
isDirty: dirtyIdMatch || dirtyAnchorMatch,
|
|
1665
1707
|
...cb ?? {}
|
|
1666
1708
|
};
|
|
1667
1709
|
};
|
|
@@ -1683,7 +1725,7 @@ var RecordList = ({
|
|
|
1683
1725
|
const compact = presentation === "compact";
|
|
1684
1726
|
return /* @__PURE__ */ jsx("ul", { children: rows.map((item) => {
|
|
1685
1727
|
const ctx = buildCtx(item);
|
|
1686
|
-
return /* @__PURE__ */ jsx("li", { children: renderListRow ? renderListRow(item, ctx) : /* @__PURE__ */ jsx(DefaultRecordRow, { record: item, ctx, compact }) }, item.ref);
|
|
1728
|
+
return /* @__PURE__ */ jsx("li", { children: renderListRow ? renderListRow(item, ctx) : /* @__PURE__ */ jsx(DefaultRecordRow, { record: item, ctx, compact }) }, item.id ?? item.ref);
|
|
1687
1729
|
}) });
|
|
1688
1730
|
};
|
|
1689
1731
|
if (groups) {
|
|
@@ -1823,6 +1865,90 @@ function applyRuleFilters(items, filters) {
|
|
|
1823
1865
|
return true;
|
|
1824
1866
|
});
|
|
1825
1867
|
}
|
|
1868
|
+
function FacetBrowseFilter({
|
|
1869
|
+
facets,
|
|
1870
|
+
value,
|
|
1871
|
+
onChange,
|
|
1872
|
+
isLoading = false,
|
|
1873
|
+
helpText = "Browse by facet \u2014 preview what would apply to a product."
|
|
1874
|
+
}) {
|
|
1875
|
+
const firstUsable = useMemo(
|
|
1876
|
+
() => facets.find((f) => f.values?.length)?.key,
|
|
1877
|
+
[facets]
|
|
1878
|
+
);
|
|
1879
|
+
const [openKey, setOpenKey] = useState(value?.facetKey ?? firstUsable ?? null);
|
|
1880
|
+
const effectiveOpen = value?.facetKey ?? openKey ?? firstUsable ?? null;
|
|
1881
|
+
if (isLoading) {
|
|
1882
|
+
return /* @__PURE__ */ jsx("div", { className: "ra-rule-filters", "aria-busy": "true", children: /* @__PURE__ */ jsx("div", { className: "ra-rule-filters-row", children: /* @__PURE__ */ jsx("span", { className: "ra-rule-filter-chip", "data-active": "false", children: "Loading facets\u2026" }) }) });
|
|
1883
|
+
}
|
|
1884
|
+
if (!facets.length) return null;
|
|
1885
|
+
const openFacet = facets.find((f) => f.key === effectiveOpen) ?? null;
|
|
1886
|
+
return /* @__PURE__ */ jsxs("div", { className: "ra-rule-filters", role: "group", "aria-label": "Browse by facet", children: [
|
|
1887
|
+
/* @__PURE__ */ jsx("div", { className: "ra-rule-filters-row", children: facets.map((f) => {
|
|
1888
|
+
const active = effectiveOpen === f.key;
|
|
1889
|
+
const isFiltered = value?.facetKey === f.key;
|
|
1890
|
+
return /* @__PURE__ */ jsxs(
|
|
1891
|
+
"button",
|
|
1892
|
+
{
|
|
1893
|
+
type: "button",
|
|
1894
|
+
className: "ra-rule-filter-chip",
|
|
1895
|
+
"data-active": isFiltered ? "true" : "false",
|
|
1896
|
+
"aria-pressed": active,
|
|
1897
|
+
onClick: () => {
|
|
1898
|
+
if (isFiltered) {
|
|
1899
|
+
onChange(null);
|
|
1900
|
+
return;
|
|
1901
|
+
}
|
|
1902
|
+
setOpenKey(f.key);
|
|
1903
|
+
},
|
|
1904
|
+
title: `Browse ${f.label ?? f.key} values`,
|
|
1905
|
+
children: [
|
|
1906
|
+
/* @__PURE__ */ jsx("span", { className: "ra-rule-filter-chip-label", children: f.label ?? f.key }),
|
|
1907
|
+
/* @__PURE__ */ jsx("span", { className: "ra-rule-filter-chip-count", children: f.values.length })
|
|
1908
|
+
]
|
|
1909
|
+
},
|
|
1910
|
+
f.key
|
|
1911
|
+
);
|
|
1912
|
+
}) }),
|
|
1913
|
+
openFacet && openFacet.values.length > 0 && /* @__PURE__ */ jsx(
|
|
1914
|
+
"div",
|
|
1915
|
+
{
|
|
1916
|
+
className: "ra-rule-filters-row",
|
|
1917
|
+
role: "group",
|
|
1918
|
+
"aria-label": `Pick a ${openFacet.label ?? openFacet.key} value`,
|
|
1919
|
+
style: { paddingLeft: "0.25rem" },
|
|
1920
|
+
children: openFacet.values.map((v) => {
|
|
1921
|
+
const active = value?.facetKey === openFacet.key && value?.facetValue === v.key;
|
|
1922
|
+
return /* @__PURE__ */ jsx(
|
|
1923
|
+
"button",
|
|
1924
|
+
{
|
|
1925
|
+
type: "button",
|
|
1926
|
+
className: "ra-rule-filter-chip",
|
|
1927
|
+
"data-tone": "complexity",
|
|
1928
|
+
"data-active": active ? "true" : "false",
|
|
1929
|
+
"aria-pressed": active,
|
|
1930
|
+
onClick: () => onChange(active ? null : { facetKey: openFacet.key, facetValue: v.key }),
|
|
1931
|
+
title: `Filter to ${openFacet.label ?? openFacet.key} = ${v.label ?? v.key}`,
|
|
1932
|
+
children: /* @__PURE__ */ jsx("span", { className: "ra-rule-filter-chip-label", children: v.label ?? v.key })
|
|
1933
|
+
},
|
|
1934
|
+
v.key
|
|
1935
|
+
);
|
|
1936
|
+
})
|
|
1937
|
+
}
|
|
1938
|
+
),
|
|
1939
|
+
value && /* @__PURE__ */ jsx(
|
|
1940
|
+
"button",
|
|
1941
|
+
{
|
|
1942
|
+
type: "button",
|
|
1943
|
+
onClick: () => onChange(null),
|
|
1944
|
+
className: "ra-rule-filter-clear",
|
|
1945
|
+
"aria-label": "Clear facet filter",
|
|
1946
|
+
children: "Clear facet filter"
|
|
1947
|
+
}
|
|
1948
|
+
),
|
|
1949
|
+
!value && /* @__PURE__ */ jsx("span", { className: "ra-rule-filter-clear", style: { cursor: "default", textDecoration: "none" }, children: helpText })
|
|
1950
|
+
] });
|
|
1951
|
+
}
|
|
1826
1952
|
var EmptyState = ({
|
|
1827
1953
|
title,
|
|
1828
1954
|
body,
|
|
@@ -1963,12 +2089,18 @@ function useItemViewPref(args) {
|
|
|
1963
2089
|
var QK_BASE2 = ["records-admin", "collection-items"];
|
|
1964
2090
|
var defaultToSummary = (rec, base) => {
|
|
1965
2091
|
const data = rec.data;
|
|
2092
|
+
const display = data?.display ?? void 0;
|
|
1966
2093
|
if (!data) return base;
|
|
1967
|
-
const label = data.title ?? data.name ?? data.label ?? data.question ?? base.label;
|
|
1968
|
-
const subtitle = data.subtitle ?? data.summary ?? data.description ?? base.subtitle;
|
|
1969
|
-
const thumbnail = data.thumbnail ?? data.image ?? data.cover ?? base.thumbnail;
|
|
2094
|
+
const label = data.title ?? display?.title ?? data.name ?? data.label ?? data.question ?? data.slug ?? base.label;
|
|
2095
|
+
const subtitle = data.subtitle ?? data.summary ?? display?.description ?? data.description ?? base.subtitle;
|
|
2096
|
+
const thumbnail = data.thumbnail ?? data.image ?? data.cover ?? data.home_image_url ?? base.thumbnail;
|
|
1970
2097
|
return { ...base, label, subtitle, thumbnail };
|
|
1971
2098
|
};
|
|
2099
|
+
var recordMatchesScope = (rec, scope) => {
|
|
2100
|
+
const facetRule = rec.facetRule ?? null;
|
|
2101
|
+
if (facetRule) return false;
|
|
2102
|
+
return (rec.productId ?? void 0) === scope.productId && (rec.variantId ?? void 0) === scope.variantId && (rec.batchId ?? void 0) === scope.batchId && (rec.proofId ?? void 0) === scope.proofId;
|
|
2103
|
+
};
|
|
1972
2104
|
function useCollectionItems(args) {
|
|
1973
2105
|
const {
|
|
1974
2106
|
ctx,
|
|
@@ -1979,7 +2111,6 @@ function useCollectionItems(args) {
|
|
|
1979
2111
|
} = args;
|
|
1980
2112
|
const queryClient = useQueryClient();
|
|
1981
2113
|
const scopeRef = scope?.raw ?? "";
|
|
1982
|
-
const refPrefix = scopeRef ? `${scopeRef}/item:` : "item:";
|
|
1983
2114
|
const queryKey = useMemo(
|
|
1984
2115
|
() => [...QK_BASE2, ctx.collectionId, ctx.appId, ctx.recordType, scopeRef],
|
|
1985
2116
|
[ctx.collectionId, ctx.appId, ctx.recordType, scopeRef]
|
|
@@ -1992,8 +2123,7 @@ function useCollectionItems(args) {
|
|
|
1992
2123
|
const offset = pageParam;
|
|
1993
2124
|
const { data, total, hasMore } = await listRecords(ctx, {
|
|
1994
2125
|
limit: pageSize,
|
|
1995
|
-
offset
|
|
1996
|
-
refPrefix
|
|
2126
|
+
offset
|
|
1997
2127
|
});
|
|
1998
2128
|
return { data, total, hasMore, nextOffset: offset + data.length };
|
|
1999
2129
|
},
|
|
@@ -2001,25 +2131,26 @@ function useCollectionItems(args) {
|
|
|
2001
2131
|
staleTime: 15e3
|
|
2002
2132
|
});
|
|
2003
2133
|
const items = useMemo(() => {
|
|
2134
|
+
if (!scope) return [];
|
|
2004
2135
|
const all = query.data?.pages.flatMap((p) => p.data) ?? [];
|
|
2005
|
-
|
|
2136
|
+
const relevant = all.filter((rec) => recordMatchesScope(rec, scope));
|
|
2137
|
+
return relevant.map((rec) => {
|
|
2006
2138
|
const ref = rec.ref ?? "";
|
|
2007
2139
|
const parsed = parseRef(ref);
|
|
2008
|
-
const
|
|
2009
|
-
if (!itemId) return null;
|
|
2140
|
+
const stableItemId = rec.id;
|
|
2010
2141
|
const base = {
|
|
2011
2142
|
id: rec.id,
|
|
2012
2143
|
ref,
|
|
2013
2144
|
scope: parsed,
|
|
2014
2145
|
data: rec.data ?? null,
|
|
2015
2146
|
status: rec.data ? "configured" : "empty",
|
|
2016
|
-
label:
|
|
2147
|
+
label: stableItemId,
|
|
2017
2148
|
updatedAt: rec.updatedAt,
|
|
2018
|
-
itemId
|
|
2149
|
+
itemId: stableItemId
|
|
2019
2150
|
};
|
|
2020
2151
|
return toSummary2(rec, base);
|
|
2021
2152
|
}).filter((x) => x !== null);
|
|
2022
|
-
}, [query.data, toSummary2]);
|
|
2153
|
+
}, [query.data, toSummary2, scope]);
|
|
2023
2154
|
const refetch = useCallback(() => {
|
|
2024
2155
|
queryClient.invalidateQueries({ queryKey });
|
|
2025
2156
|
}, [queryClient, queryKey]);
|
|
@@ -2061,7 +2192,7 @@ var createDefaultDeepLinkAdapter = (paramNames) => ({
|
|
|
2061
2192
|
if (typeof window === "undefined") return {};
|
|
2062
2193
|
const params = new URLSearchParams(getQueryString(window.location));
|
|
2063
2194
|
return {
|
|
2064
|
-
|
|
2195
|
+
recordId: params.get(paramNames.recordId),
|
|
2065
2196
|
scope: params.get(paramNames.scope),
|
|
2066
2197
|
view: params.get(paramNames.view)
|
|
2067
2198
|
};
|
|
@@ -2073,7 +2204,7 @@ var createDefaultDeepLinkAdapter = (paramNames) => ({
|
|
|
2073
2204
|
if (value == null || value === "") params.delete(key);
|
|
2074
2205
|
else params.set(key, value);
|
|
2075
2206
|
};
|
|
2076
|
-
if ("
|
|
2207
|
+
if ("recordId" in partial) apply(paramNames.recordId, partial.recordId);
|
|
2077
2208
|
if ("scope" in partial) apply(paramNames.scope, partial.scope);
|
|
2078
2209
|
if ("view" in partial) apply(paramNames.view, partial.view);
|
|
2079
2210
|
const nextUrl = buildUrl(window.location, params.toString());
|
|
@@ -2093,7 +2224,7 @@ var createDefaultDeepLinkAdapter = (paramNames) => ({
|
|
|
2093
2224
|
});
|
|
2094
2225
|
|
|
2095
2226
|
// src/components/RecordsAdmin/hooks/useDeepLinkState.ts
|
|
2096
|
-
var SMART_PUSH = ["
|
|
2227
|
+
var SMART_PUSH = ["record.open", "record.close", "scope"];
|
|
2097
2228
|
var classify = (mode, kind) => {
|
|
2098
2229
|
if (mode === "push") return "push";
|
|
2099
2230
|
if (mode === "replace") return "replace";
|
|
@@ -3746,18 +3877,10 @@ var downloadBlob = (blob, filename) => {
|
|
|
3746
3877
|
styleInject(':root {\n --ra-status-own: var(--ra-emerald, 142 71% 45%);\n --ra-status-shared: var(--ra-amber, 38 92% 50%);\n --ra-status-missing: var(--muted-foreground, 220 9% 46%);\n --ra-accent: var(--primary, 222 47% 11%);\n --ra-surface: var(--card, 0 0% 100%);\n --ra-border: var(--border, 220 13% 91%);\n --ra-text: var(--foreground, 222 47% 11%);\n --ra-muted: var(--muted, 220 14% 96%);\n --ra-muted-text: var(--muted-foreground, 220 9% 46%);\n --ra-radius: var(--radius, 0.625rem);\n --ra-dot-size: 0.5rem;\n --ra-page-bg: var(--background, 220 14% 98%);\n --ra-card-shadow: 0 1px 2px hsl(var(--ra-accent) / 0.04), 0 4px 12px hsl(var(--ra-accent) / 0.05);\n --ra-card-shadow-hover: 0 2px 4px hsl(var(--ra-accent) / 0.06), 0 8px 24px hsl(var(--ra-accent) / 0.08);\n --ra-row-hover: hsl(var(--ra-accent) / 0.05);\n --ra-row-active-bg: hsl(var(--ra-accent) / 0.10);\n --ra-row-active-bd: hsl(var(--ra-accent) / 0.45);\n --ra-focus-ring: hsl(var(--ra-accent) / 0.35);\n --ra-font-display: var(--font-display, var(--font-sans, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif));\n --ra-font-ui: var(--font-sans, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);\n --ra-title-weight: 600;\n --ra-display-weight: 700;\n --ra-info: var(--ra-blue, 214 95% 55%);\n --ra-success: var(--ra-emerald, 142 71% 45%);\n --ra-warning: var(--ra-amber, 38 92% 50%);\n --ra-danger: var(--destructive, 0 72% 51%);\n}\n:root {\n --sl-control-bg: var(--muted, 220 14% 96%);\n --sl-control-fg: var(--muted-foreground, 220 9% 40%);\n --sl-control-border: var(--border, 220 13% 88%);\n --sl-control-active-bg: var(--primary, 222 47% 11%);\n --sl-control-active-fg: var(--primary-foreground, 0 0% 100%);\n --sl-control-active-bd: var(--primary, 222 47% 11%);\n --sl-control-hover-bg: var(--sl-control-active-bg, 222 47% 11%);\n --sl-control-hover-fg: var(--foreground, 222 47% 11%);\n --sl-control-focus-ring: var(--sl-control-active-bg, 222 47% 11%);\n --sl-control-radius: var(--radius, 0.5rem);\n --sl-control-weight: 500;\n --sl-control-active-weight: 600;\n}\n.ra-status-dot {\n display: inline-block;\n width: var(--ra-dot-size);\n height: var(--ra-dot-size);\n border-radius: 9999px;\n flex-shrink: 0;\n}\n.ra-status-own {\n background: hsl(var(--ra-status-own));\n}\n.ra-status-shared {\n background: hsl(var(--ra-status-shared));\n}\n.ra-status-missing {\n background: hsl(var(--ra-status-missing) / 0.4);\n border: 1px solid hsl(var(--ra-status-missing) / 0.6);\n}\n.ra-row-active {\n background: var(--ra-row-active-bg);\n border-color: var(--ra-row-active-bd) !important;\n}\n');
|
|
3747
3878
|
|
|
3748
3879
|
// src/components/RecordsAdmin/shell/shell.css
|
|
3749
|
-
styleInject(".ra-shell {\n color: hsl(var(--ra-text));\n background: hsl(var(--ra-page-bg));\n font-family: var(--ra-font-ui);\n}\n.ra-shell *,\n.ra-shell *::before,\n.ra-shell *::after {\n box-sizing: border-box;\n}\n.ra-shell .ra-card {\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-card-hover {\n transition:\n box-shadow .18s ease,\n transform .18s ease,\n border-color .18s ease;\n}\n.ra-shell .ra-card-hover:hover {\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-display {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-title {\n font-weight: var(--ra-title-weight);\n}\n.ra-shell :where(button, [role=button], input, select, textarea, a):focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n border-radius: calc(var(--ra-radius) * 0.6);\n}\n.ra-shell .ra-header {\n position: relative;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.65rem 0.9rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-accent) / 0.12);\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.08),\n hsl(var(--ra-accent) / 0.02) 60%,\n hsl(var(--ra-surface)) 100%);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-header__main {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 0.625rem;\n}\n.ra-shell .ra-header-aside {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-header-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: calc(var(--ra-radius) * 0.9);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.18);\n}\n.ra-shell .ra-header-text {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-header-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n letter-spacing: -0.01em;\n margin: 0;\n}\n.ra-shell .ra-header-subtitle {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-header-stats {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n padding: 0.15rem 0.4rem;\n border-radius: calc(var(--ra-radius) * 0.75);\n background: hsl(var(--ra-surface) / 0.7);\n border: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-header-stats--titled {\n flex-direction: column;\n align-items: stretch;\n padding: 0.4rem 0.55rem;\n gap: 0.3rem;\n}\n.ra-shell .ra-header-stats .ra-stats-items {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n}\n.ra-shell .ra-header-stats .ra-stats-heading {\n display: flex;\n align-items: center;\n gap: 0.35rem;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon {\n display: inline-flex;\n align-items: center;\n color: hsl(var(--ra-text));\n opacity: 0.75;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon > svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-stat {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 0.15rem 0.45rem;\n min-width: 2.5rem;\n}\n.ra-shell .ra-stat-value {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n line-height: 1;\n}\n.ra-shell .ra-stat-label {\n font-size: 0.6rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-stat-divider {\n width: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-header-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n.ra-shell .ra-tabs {\n display: flex;\n gap: 0.25rem;\n padding: 0.25rem;\n background: hsl(var(--sl-control-bg));\n border-radius: var(--sl-control-radius);\n border: 1px solid hsl(var(--sl-control-border));\n}\n.ra-shell .ra-tab {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.4rem 0.7rem;\n border-radius: calc(var(--sl-control-radius) - 2px);\n font-size: 0.78rem;\n font-weight: var(--sl-control-weight);\n color: hsl(var(--sl-control-fg));\n background: transparent;\n border: 0;\n cursor: pointer;\n transition:\n background .15s ease,\n color .15s ease,\n transform .15s ease;\n white-space: nowrap;\n}\n.ra-shell .ra-tab:hover {\n background: hsl(var(--sl-control-hover-bg) / 0.10);\n color: hsl(var(--sl-control-hover-fg));\n}\n.ra-shell .ra-tab:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px hsl(var(--sl-control-focus-ring) / 0.45);\n}\n.ra-shell .ra-tab[aria-selected=true] {\n background: hsl(var(--sl-control-active-bg));\n color: hsl(var(--sl-control-active-fg));\n border-color: hsl(var(--sl-control-active-bd));\n font-weight: var(--sl-control-active-weight);\n box-shadow: 0 1px 2px hsl(var(--sl-control-active-bg) / 0.25);\n}\n.ra-shell .ra-tab[aria-selected=true]:hover {\n background: hsl(var(--sl-control-active-bg) / 0.92);\n color: hsl(var(--sl-control-active-fg));\n}\n.ra-shell .ra-tab[aria-selected=true] .ra-tab-icon {\n color: hsl(var(--sl-control-active-fg));\n}\n.ra-shell .ra-tab[disabled] {\n opacity: .5;\n cursor: not-allowed;\n}\n.ra-shell .ra-tab-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.25rem;\n padding: 0 0.35rem;\n height: 1.1rem;\n border-radius: 999px;\n background: hsl(var(--sl-control-active-fg) / 0.20);\n color: hsl(var(--sl-control-active-fg));\n font-size: 0.625rem;\n font-weight: 600;\n line-height: 1;\n}\n.ra-shell .ra-tab[aria-selected=false] .ra-tab-count {\n background: hsl(var(--sl-control-fg) / 0.15);\n color: hsl(var(--sl-control-fg));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.4rem;\n}\n.ra-shell[data-density=compact] .ra-header {\n padding: 0.75rem 1rem;\n}\n.ra-shell[data-density=compact] .ra-header-icon {\n width: 2.25rem;\n height: 2.25rem;\n}\n.ra-shell .ra-row {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n text-align: left;\n padding: 0.45rem 0.75rem;\n border-left: 3px solid transparent;\n background: transparent;\n border-bottom: 1px solid transparent;\n transition: background .12s ease, border-color .12s ease;\n cursor: pointer;\n color: hsl(var(--ra-text));\n font-family: inherit;\n}\n.ra-shell .ra-row + .ra-row {\n border-top: 1px solid hsl(var(--ra-border) / 0.6);\n}\n.ra-shell .ra-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n border-left-color: var(--ra-row-active-bd);\n}\n.ra-shell .ra-row-compact {\n padding-block: 0.3rem;\n}\n.ra-shell .ra-row-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-icon {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-row-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.8125rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-sub {\n font-size: 0.6875rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.05rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-rule-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.2rem;\n margin-top: 0.2rem;\n}\n.ra-shell .ra-rule-chip {\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n padding: 0.05rem 0.4rem;\n border-radius: 999px;\n font-size: 0.625rem;\n font-weight: 500;\n line-height: 1.4;\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.20);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-rule-chip-more {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell[data-density=compact] .ra-row-rule-chips {\n margin-top: 0.15rem;\n gap: 0.15rem;\n}\n.ra-shell[data-density=compact] .ra-rule-chip {\n font-size: 0.6rem;\n padding: 0.02rem 0.35rem;\n}\n.ra-shell .ra-rule-filters {\n display: flex;\n flex-direction: column;\n gap: 0.3rem;\n}\n.ra-shell .ra-rule-filters-row {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n}\n.ra-shell .ra-rule-filter-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.65rem;\n font-weight: 500;\n line-height: 1.4;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n transition:\n background .12s ease,\n color .12s ease,\n border-color .12s ease;\n max-width: 100%;\n}\n.ra-shell .ra-rule-filter-chip:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n border-color: hsl(var(--ra-accent) / 0.25);\n}\n.ra-shell .ra-rule-filter-chip[data-active=true] {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.40);\n}\n.ra-shell .ra-rule-filter-chip[data-tone=complexity][data-active=true] {\n background: hsl(var(--ra-info) / 0.15);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.40);\n}\n.ra-shell .ra-rule-filter-chip-label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 9rem;\n}\n.ra-shell .ra-rule-filter-chip-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.1rem;\n height: 1rem;\n padding: 0 0.3rem;\n border-radius: 999px;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n font-size: 0.6rem;\n font-weight: 600;\n}\n.ra-shell .ra-rule-filter-chip[data-active=true] .ra-rule-filter-chip-count {\n background: hsl(var(--ra-accent) / 0.18);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-rule-filter-clear {\n align-self: flex-start;\n background: transparent;\n border: 0;\n padding: 0;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n cursor: pointer;\n text-decoration: underline;\n text-decoration-style: dotted;\n}\n.ra-shell .ra-rule-filter-clear:hover {\n color: hsl(var(--ra-text));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.3rem;\n gap: 0.45rem;\n}\n.ra-shell[data-density=compact] .ra-row-title {\n font-size: 0.78125rem;\n}\n.ra-shell .ra-row-actions {\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n margin-left: auto;\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-row:hover .ra-row-actions,\n.ra-shell .ra-row:focus-within .ra-row-actions {\n opacity: 1;\n}\n.ra-shell .ra-row-action {\n width: 1.6rem;\n height: 1.6rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 999px;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .15s ease, color .15s ease;\n}\n.ra-shell .ra-row-action:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-action[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.12);\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.6875rem;\n font-weight: 500;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n white-space: nowrap;\n max-width: 14rem;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-chip[data-tone=success] {\n background: hsl(var(--ra-success) / 0.12);\n color: hsl(var(--ra-success));\n border-color: hsl(var(--ra-success) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=warning] {\n background: hsl(var(--ra-warning) / 0.14);\n color: hsl(var(--ra-warning));\n border-color: hsl(var(--ra-warning) / 0.35);\n}\n.ra-shell .ra-chip[data-tone=info] {\n background: hsl(var(--ra-info) / 0.10);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=danger] {\n background: hsl(var(--ra-danger) / 0.10);\n color: hsl(var(--ra-danger));\n border-color: hsl(var(--ra-danger) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=muted] {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-style: dashed;\n}\n.ra-shell .ra-group {\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-group:last-child {\n border-bottom: 0;\n}\n.ra-shell .ra-group-summary {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.5rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.6);\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-group-summary:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-group-summary .ra-group-chevron {\n transition: transform .15s ease;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-chevron {\n transform: rotate(-90deg);\n}\n.ra-shell .ra-group-name {\n flex: 1;\n text-align: left;\n}\n.ra-shell .ra-group-count {\n font-size: 0.65rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.4rem;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-body {\n display: none;\n}\n.ra-shell .ra-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 2.5rem 1.5rem;\n gap: 0.75rem;\n}\n.ra-shell .ra-empty-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 3.25rem;\n height: 3.25rem;\n border-radius: 999px;\n background: hsl(var(--ra-accent) / 0.08);\n color: hsl(var(--ra-accent));\n margin-bottom: 0.25rem;\n}\n.ra-shell .ra-empty-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n color: hsl(var(--ra-text));\n margin: 0;\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-empty-body {\n font-size: 0.8125rem;\n color: hsl(var(--ra-muted-text));\n max-width: 22rem;\n line-height: 1.45;\n}\n.ra-shell .ra-empty-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-top: 0.25rem;\n flex-wrap: wrap;\n justify-content: center;\n}\n.ra-shell .ra-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.45rem 0.85rem;\n border-radius: calc(var(--ra-radius) * 0.7);\n font-size: 0.8125rem;\n font-weight: 500;\n border: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n cursor: pointer;\n transition:\n background .15s ease,\n border-color .15s ease,\n box-shadow .15s ease,\n transform .1s ease;\n}\n.ra-shell .ra-btn:hover {\n background: hsl(var(--ra-muted));\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-btn:active {\n transform: translateY(1px);\n}\n.ra-shell .ra-btn[data-variant=primary] {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-surface));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-btn[data-variant=primary]:hover {\n background: hsl(var(--ra-accent) / 0.92);\n}\n.ra-shell .ra-btn[data-variant=ghost] {\n background: transparent;\n border-color: transparent;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-btn[data-variant=ghost]:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-btn[data-variant=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-btn[data-variant=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n border-color: hsl(var(--ra-danger) / 0.40);\n}\n.ra-shell .ra-intro {\n position: relative;\n display: flex;\n gap: 0.85rem;\n padding: 0.9rem 1rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-info) / 0.30);\n background: hsl(var(--ra-info) / 0.08);\n margin-bottom: 1rem;\n}\n.ra-shell .ra-intro[data-tone=success] {\n border-color: hsl(var(--ra-success) / 0.30);\n background: hsl(var(--ra-success) / 0.08);\n}\n.ra-shell .ra-intro[data-tone=warning] {\n border-color: hsl(var(--ra-warning) / 0.35);\n background: hsl(var(--ra-warning) / 0.10);\n}\n.ra-shell .ra-intro-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-info) / 0.18);\n color: hsl(var(--ra-info));\n}\n.ra-shell .ra-intro[data-tone=success] .ra-intro-icon {\n background: hsl(var(--ra-success) / 0.18);\n color: hsl(var(--ra-success));\n}\n.ra-shell .ra-intro[data-tone=warning] .ra-intro-icon {\n background: hsl(var(--ra-warning) / 0.20);\n color: hsl(var(--ra-warning));\n}\n.ra-shell .ra-intro-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-intro-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-title-weight);\n font-size: 0.875rem;\n color: hsl(var(--ra-text));\n margin: 0 0 0.2rem 0;\n}\n.ra-shell .ra-intro-text {\n font-size: 0.8125rem;\n color: hsl(var(--ra-text) / 0.85);\n line-height: 1.45;\n}\n.ra-shell .ra-intro-dismiss {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n width: 1.6rem;\n height: 1.6rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 0;\n color: hsl(var(--ra-muted-text));\n cursor: pointer;\n}\n.ra-shell .ra-intro-dismiss:hover {\n background: hsl(var(--ra-text) / 0.06);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-bulk-menu {\n min-width: 12rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow-hover);\n padding: 0.3rem;\n z-index: 60;\n}\n.ra-shell .ra-bulk-item {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n padding: 0.45rem 0.6rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-bulk-item:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-bulk-item[data-tone=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-bulk-item[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n}\n.ra-shell .ra-bulk-divider {\n height: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-preview-rail {\n background: hsl(var(--ra-surface));\n border-left: 1px solid hsl(var(--ra-border));\n box-shadow: -4px 0 16px hsl(var(--ra-accent) / 0.04);\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n.ra-shell .ra-preview-rail-header {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n background:\n linear-gradient(\n 180deg,\n hsl(var(--ra-surface)) 0%,\n hsl(var(--ra-surface) / 0.92) 100%);\n border-bottom: 1px solid hsl(var(--ra-border));\n backdrop-filter: blur(6px);\n}\n.ra-shell .ra-preview-rail-title {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-preview-rail-body {\n flex: 1;\n overflow-y: auto;\n padding: 1rem;\n}\n.ra-confirm-root {\n position: fixed;\n inset: 0;\n z-index: 2147483000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1rem;\n}\n.ra-confirm-root .ra-confirm-backdrop {\n position: absolute;\n inset: 0;\n background: hsl(0 0% 0% / 0.45);\n backdrop-filter: blur(2px);\n animation: ra-confirm-fade .12s ease-out;\n}\n.ra-confirm-root .ra-confirm-card {\n position: relative;\n width: min(440px, 100%);\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: 0 1px 2px hsl(0 0% 0% / 0.08), 0 24px 48px -12px hsl(0 0% 0% / 0.32);\n padding: 1.25rem;\n animation: ra-confirm-pop .14s ease-out;\n}\n.ra-confirm-root .ra-confirm-header {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n margin-bottom: 0.5rem;\n}\n.ra-confirm-root .ra-confirm-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: 999px;\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.12);\n color: hsl(var(--ra-warning, 38 92% 50%));\n}\n.ra-confirm-root .ra-confirm-title {\n font-family: var(--ra-font-display);\n font-weight: 600;\n font-size: 1rem;\n margin: 0;\n}\n.ra-confirm-root .ra-confirm-body {\n font-size: 0.875rem;\n color: hsl(var(--ra-muted-text));\n margin: 0 0 1.1rem;\n line-height: 1.45;\n}\n.ra-confirm-root .ra-confirm-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n.ra-confirm-root .ra-confirm-btn {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.45rem 0.85rem;\n font-size: 0.8125rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease;\n}\n.ra-confirm-root .ra-confirm-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-confirm-root .ra-confirm-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-confirm-root .ra-confirm-btn-ghost:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-confirm-root .ra-confirm-btn-danger {\n background: transparent;\n color: hsl(var(--ra-danger, 0 72% 51%));\n border-color: hsl(var(--ra-danger, 0 72% 51%) / 0.45);\n}\n.ra-confirm-root .ra-confirm-btn-danger:hover {\n background: hsl(var(--ra-danger, 0 72% 51%) / 0.08);\n border-color: hsl(var(--ra-danger, 0 72% 51%));\n}\n.ra-confirm-root .ra-confirm-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-confirm-root .ra-confirm-btn-primary:hover {\n filter: brightness(0.95);\n}\n@keyframes ra-confirm-fade {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes ra-confirm-pop {\n from {\n opacity: 0;\n transform: translateY(4px) scale(.98);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n.ra-shell .ra-unsaved-banner {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 0.75rem;\n border: 1px solid hsl(var(--ra-warning, 38 92% 50%) / 0.35);\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.08);\n border-radius: var(--ra-radius);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n animation: ra-unsaved-slide .14s ease-out;\n}\n.ra-shell .ra-unsaved-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-warning, 38 92% 50%));\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-text {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ra-shell .ra-unsaved-context {\n color: hsl(var(--ra-muted-text));\n font-weight: 400;\n}\n.ra-shell .ra-unsaved-error {\n color: hsl(var(--ra-danger, 0 72% 51%));\n font-size: 0.75rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n font-weight: 500;\n}\n.ra-shell .ra-unsaved-actions {\n display: inline-flex;\n gap: 0.4rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.3rem 0.6rem;\n font-size: 0.75rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease,\n opacity .12s ease;\n}\n.ra-shell .ra-unsaved-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.ra-shell .ra-unsaved-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-shell .ra-unsaved-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell .ra-unsaved-btn-ghost:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-unsaved-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-unsaved-btn-primary:hover:not(:disabled) {\n filter: brightness(0.95);\n}\n@keyframes ra-unsaved-slide {\n from {\n opacity: 0;\n transform: translateY(-3px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.ra-shell .ra-clipboard-toast {\n position: fixed;\n bottom: 1.25rem;\n left: 50%;\n transform: translateX(-50%);\n z-index: 90;\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n max-width: min(28rem, calc(100vw - 2rem));\n padding: 0.55rem 0.85rem;\n border-radius: 999px;\n background: hsl(var(--ra-text));\n color: hsl(var(--ra-surface));\n font-size: 0.75rem;\n line-height: 1;\n box-shadow: 0 8px 24px -10px hsl(0 0% 0% / 0.45);\n animation: ra-clipboard-pop 0.18s ease-out both;\n pointer-events: none;\n}\n@keyframes ra-clipboard-pop {\n from {\n opacity: 0;\n transform: translate(-50%, 6px);\n }\n to {\n opacity: 1;\n transform: translate(-50%, 0);\n }\n}\n.ra-shell .ra-row-menu-wrap {\n display: inline-flex;\n align-items: center;\n margin-left: 0.25rem;\n}\n.ra-shell .ra-row-menu-trigger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: 0.35rem;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n opacity: 0;\n transition:\n opacity .15s ease,\n background .15s ease,\n color .15s ease;\n border: 1px solid transparent;\n}\n.ra-shell .ra-row:hover .ra-row-menu-trigger,\n.ra-shell .ra-card-hover:hover .ra-row-menu-trigger,\n.ra-shell .ra-row-menu-trigger:focus-visible,\n.ra-shell .ra-row-menu-trigger[aria-expanded=true] {\n opacity: 1;\n}\n.ra-shell .ra-row-menu-trigger:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-menu {\n position: absolute;\n right: 0;\n top: calc(100% + 4px);\n z-index: 50;\n min-width: 11rem;\n padding: 0.25rem;\n border-radius: 0.5rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n box-shadow: 0 12px 28px -10px hsl(0 0% 0% / 0.25);\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n}\n.ra-shell .ra-row-menu-item {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.4rem 0.55rem;\n border-radius: 0.35rem;\n font-size: 0.75rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n text-align: left;\n width: 100%;\n cursor: pointer;\n}\n.ra-shell .ra-row-menu-item:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-row-menu-item:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n.ra-shell .ra-item-list {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-item-list-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 1rem 1.25rem 1.5rem;\n}\n.ra-shell .ra-item-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem;\n padding: 0.75rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-toolbar-title {\n display: flex;\n align-items: baseline;\n gap: 0.5rem;\n min-width: 0;\n}\n.ra-shell .ra-item-toolbar-count {\n font-size: 0.7rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.45rem;\n}\n.ra-shell .ra-item-toolbar-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-item-table-wrap {\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n background: hsl(var(--ra-surface));\n overflow: hidden;\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-item-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-table thead th {\n text-align: left;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n padding: 0.65rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.55);\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-item-table tbody td {\n padding: 0.65rem 0.85rem;\n border-bottom: 1px solid hsl(var(--ra-border) / 0.7);\n vertical-align: middle;\n}\n.ra-shell .ra-item-table tbody tr:last-child td {\n border-bottom: 0;\n}\n.ra-shell .ra-item-row {\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-item-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-item-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n}\n.ra-shell .ra-item-row-title {\n font-weight: var(--ra-title-weight);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-row-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-item-row-meta {\n font-size: 0.78rem;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-item-row-actions {\n text-align: right;\n white-space: nowrap;\n}\n.ra-shell .ra-item-row-actions .ra-row-action + .ra-row-action {\n margin-left: 0.15rem;\n}\n.ra-shell .ra-item-cards {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n gap: 0.85rem;\n}\n.ra-shell .ra-item-gallery {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 1rem;\n}\n.ra-shell .ra-item-card {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n text-align: left;\n padding: 0;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n overflow: hidden;\n cursor: pointer;\n transition:\n box-shadow .18s ease,\n transform .12s ease,\n border-color .15s ease;\n box-shadow: var(--ra-card-shadow);\n font-family: inherit;\n color: inherit;\n}\n.ra-shell .ra-item-card:hover {\n box-shadow: var(--ra-card-shadow-hover);\n border-color: hsl(var(--ra-accent) / 0.30);\n}\n.ra-shell .ra-item-card[data-selected=true] {\n border-color: hsl(var(--ra-accent) / 0.55);\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-item-card-thumb {\n width: 100%;\n aspect-ratio: 1 / 1;\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.12),\n hsl(var(--ra-accent) / 0.04));\n display: flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-accent));\n overflow: hidden;\n}\n.ra-shell .ra-item-card-thumb--gallery {\n aspect-ratio: 16 / 9;\n}\n.ra-shell .ra-item-card-thumb img {\n width: 100%;\n height: 100%;\n -o-object-fit: cover;\n object-fit: cover;\n}\n.ra-shell .ra-item-card-initials {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1.5rem;\n letter-spacing: 0.02em;\n}\n.ra-shell .ra-item-card-body {\n padding: 0.65rem 0.8rem 0.85rem;\n min-width: 0;\n}\n.ra-shell .ra-item-card-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.85rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-delete {\n position: absolute;\n top: 0.4rem;\n right: 0.4rem;\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(4px);\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-item-card:hover .ra-item-card-delete,\n.ra-shell .ra-item-card:focus-within .ra-item-card-delete {\n opacity: 1;\n}\n.ra-shell .ra-item-nav {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-nav-position {\n font-size: 0.72rem;\n color: hsl(var(--ra-muted-text));\n font-variant-numeric: tabular-nums;\n}\n.ra-shell .ra-item-nav-arrows {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n}\n.ra-shell .ra-item-nav-arrows .ra-row-action[disabled] {\n opacity: 0.35;\n cursor: not-allowed;\n}\n.ra-shell .ra-sibling-rail {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-sibling-back {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.6rem 0.85rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted) / 0.5);\n border: 0;\n border-bottom: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-sibling-back:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-sibling-heading {\n padding: 0.6rem 0.85rem 0.4rem;\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-sibling-body {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n.ra-shell .ra-sibling-list {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n.ra-shell .ra-status-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n border-radius: 9999px;\n}\n.ra-shell .ra-status-icon > svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n.ra-shell .ra-status-icon--own {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-status-icon--shared {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-status-icon--missing {\n color: hsl(var(--ra-status-missing) / 0.7);\n}\n.ra-shell .ra-row-status {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-row-scope {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n border-radius: calc(var(--ra-radius) * 0.5);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n margin-left: auto;\n opacity: 0.55;\n transition:\n opacity .12s ease,\n color .12s ease,\n background .12s ease;\n}\n.ra-shell .ra-row:hover .ra-row-scope {\n opacity: 0.85;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-scope {\n opacity: 1;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row[data-tone=own] .ra-row-sub {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-row[data-tone=shared] .ra-row-sub {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-row[data-selected=true] {\n background:\n linear-gradient(\n 90deg,\n hsl(var(--ra-accent) / 0.10) 0%,\n hsl(var(--ra-accent) / 0.04) 100%);\n border-left-width: 3px;\n border-left-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-dirty-pip {\n display: inline-block;\n width: 0.45rem;\n height: 0.45rem;\n border-radius: 9999px;\n background: hsl(var(--ra-warning));\n box-shadow: 0 0 0 2px hsl(var(--ra-warning) / 0.18);\n flex-shrink: 0;\n}\n.ra-shell .ra-group-summary {\n background: transparent;\n}\n.ra-shell {\n position: relative;\n}\n.ra-shell .ra-help-float {\n position: absolute;\n top: 0.65rem;\n right: 0.85rem;\n z-index: 5;\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n padding: 0.3rem 0.6rem;\n font-size: 0.7rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(6px);\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n border-color .12s ease;\n}\n.ra-shell .ra-help-float:hover {\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.4);\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-help-float svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-preview-reopen {\n position: absolute;\n top: 50%;\n right: 0;\n transform: translateY(-50%);\n z-index: 4;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.4rem;\n padding: 0.65rem 0.45rem;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n border-right: 0;\n border-radius: calc(var(--ra-radius) * 0.85) 0 0 calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow);\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n padding-right .15s ease;\n writing-mode: vertical-rl;\n font-size: 0.7rem;\n font-weight: 600;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n.ra-shell .ra-preview-reopen:hover {\n color: hsl(var(--ra-accent));\n background: hsl(var(--ra-accent) / 0.04);\n padding-right: 0.6rem;\n}\n.ra-shell .ra-preview-reopen svg {\n width: 0.85rem;\n height: 0.85rem;\n writing-mode: horizontal-tb;\n}\n");
|
|
3750
|
-
var TOP_LEVEL_SCOPES = ["
|
|
3751
|
-
var
|
|
3752
|
-
|
|
3753
|
-
const rand = Math.random().toString(36).slice(2, 8);
|
|
3754
|
-
return `${time}${rand}`;
|
|
3755
|
-
};
|
|
3756
|
-
var newRuleId = () => {
|
|
3757
|
-
const time = Date.now().toString(36);
|
|
3758
|
-
const rand = Math.random().toString(36).slice(2, 10);
|
|
3759
|
-
return `${time}${rand}`;
|
|
3760
|
-
};
|
|
3880
|
+
styleInject(".ra-shell {\n color: hsl(var(--ra-text));\n background: hsl(var(--ra-page-bg));\n font-family: var(--ra-font-ui);\n}\n.ra-shell *,\n.ra-shell *::before,\n.ra-shell *::after {\n box-sizing: border-box;\n}\n.ra-shell .ra-card {\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-card-hover {\n transition:\n box-shadow .18s ease,\n transform .18s ease,\n border-color .18s ease;\n}\n.ra-shell .ra-card-hover:hover {\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-display {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-title {\n font-weight: var(--ra-title-weight);\n}\n.ra-shell :where(button, [role=button], input, select, textarea, a):focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n border-radius: calc(var(--ra-radius) * 0.6);\n}\n.ra-shell .ra-header {\n position: relative;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.65rem 0.9rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-accent) / 0.12);\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.08),\n hsl(var(--ra-accent) / 0.02) 60%,\n hsl(var(--ra-surface)) 100%);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-header__main {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 0.625rem;\n}\n.ra-shell .ra-header-aside {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-header-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: calc(var(--ra-radius) * 0.9);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.18);\n}\n.ra-shell .ra-header-text {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-header-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n letter-spacing: -0.01em;\n margin: 0;\n}\n.ra-shell .ra-header-subtitle {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-header-stats {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n padding: 0.15rem 0.4rem;\n border-radius: calc(var(--ra-radius) * 0.75);\n background: hsl(var(--ra-surface) / 0.7);\n border: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-header-stats--titled {\n flex-direction: column;\n align-items: stretch;\n padding: 0.4rem 0.55rem;\n gap: 0.3rem;\n}\n.ra-shell .ra-header-stats .ra-stats-items {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n}\n.ra-shell .ra-header-stats .ra-stats-heading {\n display: flex;\n align-items: center;\n gap: 0.35rem;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon {\n display: inline-flex;\n align-items: center;\n color: hsl(var(--ra-text));\n opacity: 0.75;\n}\n.ra-shell .ra-header-stats .ra-stats-heading-icon > svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-stat {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 0.15rem 0.45rem;\n min-width: 2.5rem;\n}\n.ra-shell .ra-stat-value {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n line-height: 1;\n}\n.ra-shell .ra-stat-label {\n font-size: 0.6rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-stat-divider {\n width: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-header-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n.ra-shell .ra-tabs {\n display: flex;\n gap: 0.25rem;\n padding: 0.25rem;\n background: hsl(var(--sl-control-bg));\n border-radius: var(--sl-control-radius);\n border: 1px solid hsl(var(--sl-control-border));\n}\n.ra-shell .ra-tab {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.4rem 0.7rem;\n border-radius: calc(var(--sl-control-radius) - 2px);\n font-size: 0.78rem;\n font-weight: var(--sl-control-weight);\n color: hsl(var(--sl-control-fg));\n background: transparent;\n border: 0;\n cursor: pointer;\n transition:\n background .15s ease,\n color .15s ease,\n transform .15s ease;\n white-space: nowrap;\n}\n.ra-shell .ra-tab:hover {\n background: hsl(var(--sl-control-hover-bg) / 0.10);\n color: hsl(var(--sl-control-hover-fg));\n}\n.ra-shell .ra-tab:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px hsl(var(--sl-control-focus-ring) / 0.45);\n}\n.ra-shell .ra-tab[aria-selected=true] {\n background: hsl(var(--sl-control-active-bg));\n color: hsl(var(--sl-control-active-fg));\n border-color: hsl(var(--sl-control-active-bd));\n font-weight: var(--sl-control-active-weight);\n box-shadow: 0 1px 2px hsl(var(--sl-control-active-bg) / 0.25);\n}\n.ra-shell .ra-tab[aria-selected=true]:hover {\n background: hsl(var(--sl-control-active-bg) / 0.92);\n color: hsl(var(--sl-control-active-fg));\n}\n.ra-shell .ra-tab[aria-selected=true] .ra-tab-icon {\n color: hsl(var(--sl-control-active-fg));\n}\n.ra-shell .ra-tab[disabled] {\n opacity: .5;\n cursor: not-allowed;\n}\n.ra-shell .ra-tab-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.25rem;\n padding: 0 0.35rem;\n height: 1.1rem;\n border-radius: 999px;\n background: hsl(var(--sl-control-active-fg) / 0.20);\n color: hsl(var(--sl-control-active-fg));\n font-size: 0.625rem;\n font-weight: 600;\n line-height: 1;\n}\n.ra-shell .ra-tab[aria-selected=false] .ra-tab-count {\n background: hsl(var(--sl-control-fg) / 0.15);\n color: hsl(var(--sl-control-fg));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.4rem;\n}\n.ra-shell[data-density=compact] .ra-header {\n padding: 0.75rem 1rem;\n}\n.ra-shell[data-density=compact] .ra-header-icon {\n width: 2.25rem;\n height: 2.25rem;\n}\n.ra-shell .ra-row {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n text-align: left;\n padding: 0.45rem 0.75rem;\n border-left: 3px solid transparent;\n background: transparent;\n border-bottom: 1px solid transparent;\n transition: background .12s ease, border-color .12s ease;\n cursor: pointer;\n color: hsl(var(--ra-text));\n font-family: inherit;\n}\n.ra-shell .ra-row + .ra-row {\n border-top: 1px solid hsl(var(--ra-border) / 0.6);\n}\n.ra-shell .ra-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n border-left-color: var(--ra-row-active-bd);\n}\n.ra-shell .ra-row-compact {\n padding-block: 0.3rem;\n}\n.ra-shell .ra-row-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-icon {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-row-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.8125rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-sub {\n font-size: 0.6875rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.05rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-rule-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.2rem;\n margin-top: 0.2rem;\n}\n.ra-shell .ra-rule-chip {\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n padding: 0.05rem 0.4rem;\n border-radius: 999px;\n font-size: 0.625rem;\n font-weight: 500;\n line-height: 1.4;\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.20);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-rule-chip-more {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell[data-density=compact] .ra-row-rule-chips {\n margin-top: 0.15rem;\n gap: 0.15rem;\n}\n.ra-shell[data-density=compact] .ra-rule-chip {\n font-size: 0.6rem;\n padding: 0.02rem 0.35rem;\n}\n.ra-shell .ra-rule-filters {\n display: flex;\n flex-direction: column;\n gap: 0.3rem;\n}\n.ra-shell .ra-rule-filters-row {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n}\n.ra-shell .ra-rule-filter-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.65rem;\n font-weight: 500;\n line-height: 1.4;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n transition:\n background .12s ease,\n color .12s ease,\n border-color .12s ease;\n max-width: 100%;\n}\n.ra-shell .ra-rule-filter-chip:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n border-color: hsl(var(--ra-accent) / 0.25);\n}\n.ra-shell .ra-rule-filter-chip[data-active=true] {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.40);\n}\n.ra-shell .ra-rule-filter-chip[data-tone=complexity][data-active=true] {\n background: hsl(var(--ra-info) / 0.15);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.40);\n}\n.ra-shell .ra-rule-filter-chip-label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 9rem;\n}\n.ra-shell .ra-rule-filter-chip-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.1rem;\n height: 1rem;\n padding: 0 0.3rem;\n border-radius: 999px;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n font-size: 0.6rem;\n font-weight: 600;\n}\n.ra-shell .ra-rule-filter-chip[data-active=true] .ra-rule-filter-chip-count {\n background: hsl(var(--ra-accent) / 0.18);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-rule-filter-clear {\n align-self: flex-start;\n background: transparent;\n border: 0;\n padding: 0;\n color: hsl(var(--ra-muted-text));\n font-size: 0.65rem;\n cursor: pointer;\n text-decoration: underline;\n text-decoration-style: dotted;\n}\n.ra-shell .ra-rule-filter-clear:hover {\n color: hsl(var(--ra-text));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.3rem;\n gap: 0.45rem;\n}\n.ra-shell[data-density=compact] .ra-row-title {\n font-size: 0.78125rem;\n}\n.ra-shell .ra-row-actions {\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n margin-left: auto;\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-row:hover .ra-row-actions,\n.ra-shell .ra-row:focus-within .ra-row-actions {\n opacity: 1;\n}\n.ra-shell .ra-row-action {\n width: 1.6rem;\n height: 1.6rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 999px;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .15s ease, color .15s ease;\n}\n.ra-shell .ra-row-action:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-action[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.12);\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.6875rem;\n font-weight: 500;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n white-space: nowrap;\n max-width: 14rem;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-chip[data-tone=success] {\n background: hsl(var(--ra-success) / 0.12);\n color: hsl(var(--ra-success));\n border-color: hsl(var(--ra-success) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=warning] {\n background: hsl(var(--ra-warning) / 0.14);\n color: hsl(var(--ra-warning));\n border-color: hsl(var(--ra-warning) / 0.35);\n}\n.ra-shell .ra-chip[data-tone=info] {\n background: hsl(var(--ra-info) / 0.10);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=danger] {\n background: hsl(var(--ra-danger) / 0.10);\n color: hsl(var(--ra-danger));\n border-color: hsl(var(--ra-danger) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=muted] {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-style: dashed;\n}\n.ra-shell .ra-group {\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-group:last-child {\n border-bottom: 0;\n}\n.ra-shell .ra-group-summary {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.5rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.6);\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-group-summary:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-group-summary .ra-group-chevron {\n transition: transform .15s ease;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-chevron {\n transform: rotate(-90deg);\n}\n.ra-shell .ra-group-name {\n flex: 1;\n text-align: left;\n}\n.ra-shell .ra-group-count {\n font-size: 0.65rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.4rem;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-body {\n display: none;\n}\n.ra-shell .ra-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 2.5rem 1.5rem;\n gap: 0.75rem;\n}\n.ra-shell .ra-empty-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 3.25rem;\n height: 3.25rem;\n border-radius: 999px;\n background: hsl(var(--ra-accent) / 0.08);\n color: hsl(var(--ra-accent));\n margin-bottom: 0.25rem;\n}\n.ra-shell .ra-empty-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n color: hsl(var(--ra-text));\n margin: 0;\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-empty-body {\n font-size: 0.8125rem;\n color: hsl(var(--ra-muted-text));\n max-width: 22rem;\n line-height: 1.45;\n}\n.ra-shell .ra-empty-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-top: 0.25rem;\n flex-wrap: wrap;\n justify-content: center;\n}\n.ra-shell .ra-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.45rem 0.85rem;\n border-radius: calc(var(--ra-radius) * 0.7);\n font-size: 0.8125rem;\n font-weight: 500;\n border: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n cursor: pointer;\n transition:\n background .15s ease,\n border-color .15s ease,\n box-shadow .15s ease,\n transform .1s ease;\n}\n.ra-shell .ra-btn:hover {\n background: hsl(var(--ra-muted));\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-btn:active {\n transform: translateY(1px);\n}\n.ra-shell .ra-btn[data-variant=primary] {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-surface));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-btn[data-variant=primary]:hover {\n background: hsl(var(--ra-accent) / 0.92);\n}\n.ra-shell .ra-btn[data-variant=ghost] {\n background: transparent;\n border-color: transparent;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-btn[data-variant=ghost]:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-btn[data-variant=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-btn[data-variant=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n border-color: hsl(var(--ra-danger) / 0.40);\n}\n.ra-shell .ra-intro {\n position: relative;\n display: flex;\n gap: 0.85rem;\n padding: 0.9rem 1rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-info) / 0.30);\n background: hsl(var(--ra-info) / 0.08);\n}\n.ra-shell .ra-intro[data-tone=success] {\n border-color: hsl(var(--ra-success) / 0.30);\n background: hsl(var(--ra-success) / 0.08);\n}\n.ra-shell .ra-intro[data-tone=warning] {\n border-color: hsl(var(--ra-warning) / 0.35);\n background: hsl(var(--ra-warning) / 0.10);\n}\n.ra-shell .ra-intro-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-info) / 0.18);\n color: hsl(var(--ra-info));\n}\n.ra-shell .ra-intro[data-tone=success] .ra-intro-icon {\n background: hsl(var(--ra-success) / 0.18);\n color: hsl(var(--ra-success));\n}\n.ra-shell .ra-intro[data-tone=warning] .ra-intro-icon {\n background: hsl(var(--ra-warning) / 0.20);\n color: hsl(var(--ra-warning));\n}\n.ra-shell .ra-intro-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-intro-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-title-weight);\n font-size: 0.875rem;\n color: hsl(var(--ra-text));\n margin: 0 0 0.2rem 0;\n}\n.ra-shell .ra-intro-text {\n font-size: 0.8125rem;\n color: hsl(var(--ra-text) / 0.85);\n line-height: 1.45;\n}\n.ra-shell .ra-intro-dismiss {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n width: 1.6rem;\n height: 1.6rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 0;\n color: hsl(var(--ra-muted-text));\n cursor: pointer;\n}\n.ra-shell .ra-intro-dismiss:hover {\n background: hsl(var(--ra-text) / 0.06);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-bulk-menu {\n min-width: 12rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow-hover);\n padding: 0.3rem;\n z-index: 60;\n}\n.ra-shell .ra-bulk-item {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n padding: 0.45rem 0.6rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-bulk-item:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-bulk-item[data-tone=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-bulk-item[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n}\n.ra-shell .ra-bulk-divider {\n height: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-preview-rail {\n background: hsl(var(--ra-surface));\n border-left: 1px solid hsl(var(--ra-border));\n box-shadow: -4px 0 16px hsl(var(--ra-accent) / 0.04);\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n.ra-shell .ra-preview-rail-header {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n background:\n linear-gradient(\n 180deg,\n hsl(var(--ra-surface)) 0%,\n hsl(var(--ra-surface) / 0.92) 100%);\n border-bottom: 1px solid hsl(var(--ra-border));\n backdrop-filter: blur(6px);\n}\n.ra-shell .ra-preview-rail-title {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-preview-rail-body {\n flex: 1;\n overflow-y: auto;\n padding: 1rem;\n}\n.ra-confirm-root {\n position: fixed;\n inset: 0;\n z-index: 2147483000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1rem;\n}\n.ra-confirm-root .ra-confirm-backdrop {\n position: absolute;\n inset: 0;\n background: hsl(0 0% 0% / 0.45);\n backdrop-filter: blur(2px);\n animation: ra-confirm-fade .12s ease-out;\n}\n.ra-confirm-root .ra-confirm-card {\n position: relative;\n width: min(440px, 100%);\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: 0 1px 2px hsl(0 0% 0% / 0.08), 0 24px 48px -12px hsl(0 0% 0% / 0.32);\n padding: 1.25rem;\n animation: ra-confirm-pop .14s ease-out;\n}\n.ra-confirm-root .ra-confirm-header {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n margin-bottom: 0.5rem;\n}\n.ra-confirm-root .ra-confirm-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: 999px;\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.12);\n color: hsl(var(--ra-warning, 38 92% 50%));\n}\n.ra-confirm-root .ra-confirm-title {\n font-family: var(--ra-font-display);\n font-weight: 600;\n font-size: 1rem;\n margin: 0;\n}\n.ra-confirm-root .ra-confirm-body {\n font-size: 0.875rem;\n color: hsl(var(--ra-muted-text));\n margin: 0 0 1.1rem;\n line-height: 1.45;\n}\n.ra-confirm-root .ra-confirm-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n.ra-confirm-root .ra-confirm-btn {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.45rem 0.85rem;\n font-size: 0.8125rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease;\n}\n.ra-confirm-root .ra-confirm-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-confirm-root .ra-confirm-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-confirm-root .ra-confirm-btn-ghost:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-confirm-root .ra-confirm-btn-danger {\n background: transparent;\n color: hsl(var(--ra-danger, 0 72% 51%));\n border-color: hsl(var(--ra-danger, 0 72% 51%) / 0.45);\n}\n.ra-confirm-root .ra-confirm-btn-danger:hover {\n background: hsl(var(--ra-danger, 0 72% 51%) / 0.08);\n border-color: hsl(var(--ra-danger, 0 72% 51%));\n}\n.ra-confirm-root .ra-confirm-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-confirm-root .ra-confirm-btn-primary:hover {\n filter: brightness(0.95);\n}\n@keyframes ra-confirm-fade {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes ra-confirm-pop {\n from {\n opacity: 0;\n transform: translateY(4px) scale(.98);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n.ra-shell .ra-unsaved-banner {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 0.75rem;\n border: 1px solid hsl(var(--ra-warning, 38 92% 50%) / 0.35);\n background: hsl(var(--ra-warning, 38 92% 50%) / 0.08);\n border-radius: var(--ra-radius);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n animation: ra-unsaved-slide .14s ease-out;\n}\n.ra-shell .ra-unsaved-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-warning, 38 92% 50%));\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-text {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ra-shell .ra-unsaved-context {\n color: hsl(var(--ra-muted-text));\n font-weight: 400;\n}\n.ra-shell .ra-unsaved-error {\n color: hsl(var(--ra-danger, 0 72% 51%));\n font-size: 0.75rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n font-weight: 500;\n}\n.ra-shell .ra-unsaved-actions {\n display: inline-flex;\n gap: 0.4rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-unsaved-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border: 1px solid transparent;\n border-radius: calc(var(--ra-radius) - 2px);\n padding: 0.3rem 0.6rem;\n font-size: 0.75rem;\n font-weight: 500;\n cursor: pointer;\n transition:\n background-color .12s ease,\n border-color .12s ease,\n color .12s ease,\n opacity .12s ease;\n}\n.ra-shell .ra-unsaved-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.ra-shell .ra-unsaved-btn:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n}\n.ra-shell .ra-unsaved-btn-ghost {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-color: hsl(var(--ra-border));\n}\n.ra-shell .ra-unsaved-btn-ghost:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-unsaved-btn-primary {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-accent-fg, 0 0% 100%));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-unsaved-btn-primary:hover:not(:disabled) {\n filter: brightness(0.95);\n}\n@keyframes ra-unsaved-slide {\n from {\n opacity: 0;\n transform: translateY(-3px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.ra-shell .ra-clipboard-toast {\n position: fixed;\n bottom: 1.25rem;\n left: 50%;\n transform: translateX(-50%);\n z-index: 90;\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n max-width: min(28rem, calc(100vw - 2rem));\n padding: 0.55rem 0.85rem;\n border-radius: 999px;\n background: hsl(var(--ra-text));\n color: hsl(var(--ra-surface));\n font-size: 0.75rem;\n line-height: 1;\n box-shadow: 0 8px 24px -10px hsl(0 0% 0% / 0.45);\n animation: ra-clipboard-pop 0.18s ease-out both;\n pointer-events: none;\n}\n@keyframes ra-clipboard-pop {\n from {\n opacity: 0;\n transform: translate(-50%, 6px);\n }\n to {\n opacity: 1;\n transform: translate(-50%, 0);\n }\n}\n.ra-shell .ra-row-menu-wrap {\n display: inline-flex;\n align-items: center;\n margin-left: 0.25rem;\n}\n.ra-shell .ra-row-menu-trigger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: 0.35rem;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n opacity: 0;\n transition:\n opacity .15s ease,\n background .15s ease,\n color .15s ease;\n border: 1px solid transparent;\n}\n.ra-shell .ra-row:hover .ra-row-menu-trigger,\n.ra-shell .ra-card-hover:hover .ra-row-menu-trigger,\n.ra-shell .ra-row-menu-trigger:focus-visible,\n.ra-shell .ra-row-menu-trigger[aria-expanded=true] {\n opacity: 1;\n}\n.ra-shell .ra-row-menu-trigger:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-menu {\n position: absolute;\n right: 0;\n top: calc(100% + 4px);\n z-index: 50;\n min-width: 11rem;\n padding: 0.25rem;\n border-radius: 0.5rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n box-shadow: 0 12px 28px -10px hsl(0 0% 0% / 0.25);\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n}\n.ra-shell .ra-row-menu-item {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.4rem 0.55rem;\n border-radius: 0.35rem;\n font-size: 0.75rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n text-align: left;\n width: 100%;\n cursor: pointer;\n}\n.ra-shell .ra-row-menu-item:hover:not(:disabled) {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-row-menu-item:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n.ra-shell .ra-item-list {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-item-list-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 1rem 1.25rem 1.5rem;\n}\n.ra-shell .ra-item-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem;\n padding: 0.75rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-toolbar-title {\n display: flex;\n align-items: baseline;\n gap: 0.5rem;\n min-width: 0;\n}\n.ra-shell .ra-item-toolbar-count {\n font-size: 0.7rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.45rem;\n}\n.ra-shell .ra-item-toolbar-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-item-table-wrap {\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n background: hsl(var(--ra-surface));\n overflow: hidden;\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-item-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-table thead th {\n text-align: left;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n padding: 0.65rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.55);\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-item-table tbody td {\n padding: 0.65rem 0.85rem;\n border-bottom: 1px solid hsl(var(--ra-border) / 0.7);\n vertical-align: middle;\n}\n.ra-shell .ra-item-table tbody tr:last-child td {\n border-bottom: 0;\n}\n.ra-shell .ra-item-row {\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-item-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-item-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n}\n.ra-shell .ra-item-row-title {\n font-weight: var(--ra-title-weight);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-item-row-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-item-row-meta {\n font-size: 0.78rem;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-item-row-actions {\n text-align: right;\n white-space: nowrap;\n}\n.ra-shell .ra-item-row-actions .ra-row-action + .ra-row-action {\n margin-left: 0.15rem;\n}\n.ra-shell .ra-item-cards {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n gap: 0.85rem;\n}\n.ra-shell .ra-item-gallery {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 1rem;\n}\n.ra-shell .ra-item-card {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n text-align: left;\n padding: 0;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n overflow: hidden;\n cursor: pointer;\n transition:\n box-shadow .18s ease,\n transform .12s ease,\n border-color .15s ease;\n box-shadow: var(--ra-card-shadow);\n font-family: inherit;\n color: inherit;\n}\n.ra-shell .ra-item-card:hover {\n box-shadow: var(--ra-card-shadow-hover);\n border-color: hsl(var(--ra-accent) / 0.30);\n}\n.ra-shell .ra-item-card[data-selected=true] {\n border-color: hsl(var(--ra-accent) / 0.55);\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-item-card-thumb {\n width: 100%;\n aspect-ratio: 1 / 1;\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.12),\n hsl(var(--ra-accent) / 0.04));\n display: flex;\n align-items: center;\n justify-content: center;\n color: hsl(var(--ra-accent));\n overflow: hidden;\n}\n.ra-shell .ra-item-card-thumb--gallery {\n aspect-ratio: 16 / 9;\n}\n.ra-shell .ra-item-card-thumb img {\n width: 100%;\n height: 100%;\n -o-object-fit: cover;\n object-fit: cover;\n}\n.ra-shell .ra-item-card-initials {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1.5rem;\n letter-spacing: 0.02em;\n}\n.ra-shell .ra-item-card-body {\n padding: 0.65rem 0.8rem 0.85rem;\n min-width: 0;\n}\n.ra-shell .ra-item-card-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.85rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-item-card-delete {\n position: absolute;\n top: 0.4rem;\n right: 0.4rem;\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(4px);\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-item-card:hover .ra-item-card-delete,\n.ra-shell .ra-item-card:focus-within .ra-item-card-delete {\n opacity: 1;\n}\n.ra-shell .ra-item-nav {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n padding: 0.5rem 1.25rem;\n border-bottom: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-item-nav-position {\n font-size: 0.72rem;\n color: hsl(var(--ra-muted-text));\n font-variant-numeric: tabular-nums;\n}\n.ra-shell .ra-item-nav-arrows {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n}\n.ra-shell .ra-item-nav-arrows .ra-row-action[disabled] {\n opacity: 0.35;\n cursor: not-allowed;\n}\n.ra-shell .ra-sibling-rail {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n.ra-shell .ra-sibling-back {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.6rem 0.85rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-muted) / 0.5);\n border: 0;\n border-bottom: 1px solid hsl(var(--ra-border));\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-sibling-back:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-sibling-heading {\n padding: 0.6rem 0.85rem 0.4rem;\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-sibling-body {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n.ra-shell .ra-sibling-list {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n.ra-shell .ra-status-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n border-radius: 9999px;\n}\n.ra-shell .ra-status-icon > svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n.ra-shell .ra-status-icon--own {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-status-icon--shared {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-status-icon--missing {\n color: hsl(var(--ra-status-missing) / 0.7);\n}\n.ra-shell .ra-row-status {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-row-scope {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n border-radius: calc(var(--ra-radius) * 0.5);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n margin-left: auto;\n opacity: 0.55;\n transition:\n opacity .12s ease,\n color .12s ease,\n background .12s ease;\n}\n.ra-shell .ra-row:hover .ra-row-scope {\n opacity: 0.85;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-scope {\n opacity: 1;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row[data-tone=own] .ra-row-sub {\n color: hsl(var(--ra-status-own));\n}\n.ra-shell .ra-row[data-tone=shared] .ra-row-sub {\n color: hsl(var(--ra-status-shared));\n}\n.ra-shell .ra-row[data-selected=true] {\n background:\n linear-gradient(\n 90deg,\n hsl(var(--ra-accent) / 0.10) 0%,\n hsl(var(--ra-accent) / 0.04) 100%);\n border-left-width: 3px;\n border-left-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-dirty-pip {\n display: inline-block;\n width: 0.45rem;\n height: 0.45rem;\n border-radius: 9999px;\n background: hsl(var(--ra-warning));\n box-shadow: 0 0 0 2px hsl(var(--ra-warning) / 0.18);\n flex-shrink: 0;\n}\n.ra-shell .ra-group-summary {\n background: transparent;\n}\n.ra-shell {\n position: relative;\n}\n.ra-shell .ra-help-float {\n position: absolute;\n top: 0.65rem;\n right: 0.85rem;\n z-index: 5;\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n padding: 0.3rem 0.6rem;\n font-size: 0.7rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface) / 0.85);\n backdrop-filter: blur(6px);\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n border-color .12s ease;\n}\n.ra-shell .ra-help-float:hover {\n color: hsl(var(--ra-accent));\n border-color: hsl(var(--ra-accent) / 0.4);\n background: hsl(var(--ra-surface));\n}\n.ra-shell .ra-help-float svg {\n width: 0.85rem;\n height: 0.85rem;\n}\n.ra-shell .ra-preview-reopen {\n position: absolute;\n top: 50%;\n right: 0;\n transform: translateY(-50%);\n z-index: 4;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.4rem;\n padding: 0.65rem 0.45rem;\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n border-right: 0;\n border-radius: calc(var(--ra-radius) * 0.85) 0 0 calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow);\n cursor: pointer;\n transition:\n color .12s ease,\n background .12s ease,\n padding-right .15s ease;\n writing-mode: vertical-rl;\n font-size: 0.7rem;\n font-weight: 600;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n.ra-shell .ra-preview-reopen:hover {\n color: hsl(var(--ra-accent));\n background: hsl(var(--ra-accent) / 0.04);\n padding-right: 0.6rem;\n}\n.ra-shell .ra-preview-reopen svg {\n width: 0.85rem;\n height: 0.85rem;\n writing-mode: horizontal-tb;\n}\n");
|
|
3881
|
+
var TOP_LEVEL_SCOPES = ["collection", "rule", "product"];
|
|
3882
|
+
var WARNED_FACET_DEPRECATED = false;
|
|
3883
|
+
var DRAFT_ID = "__draft__";
|
|
3761
3884
|
var productItemToSummary = (p) => {
|
|
3762
3885
|
const ref = buildRef({ productId: p.id });
|
|
3763
3886
|
return {
|
|
@@ -3876,15 +3999,35 @@ function RecordsAdminShell(props) {
|
|
|
3876
3999
|
deepLinkState.emit({ view: next }, "view");
|
|
3877
4000
|
}, [onTelemetry, recordType, itemView, setItemView, deepLinkState]);
|
|
3878
4001
|
const [selectedItemId, setSelectedItemId] = useState(null);
|
|
4002
|
+
const [pendingDeepLinkRecordId, setPendingDeepLinkRecordId] = useState(null);
|
|
3879
4003
|
const ctx = useMemo(
|
|
3880
4004
|
() => ({ SL, collectionId, appId, recordType }),
|
|
3881
4005
|
[SL, collectionId, appId, recordType]
|
|
3882
4006
|
);
|
|
3883
4007
|
const probe = useScopeProbe({ SL, collectionId });
|
|
3884
|
-
const topLevelScopes = useMemo(
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
4008
|
+
const topLevelScopes = useMemo(() => {
|
|
4009
|
+
const requested = requestedScopes ?? [];
|
|
4010
|
+
if (requested.length > 0) {
|
|
4011
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4012
|
+
const ordered = [];
|
|
4013
|
+
for (const s of requested) {
|
|
4014
|
+
if (!TOP_LEVEL_SCOPES.includes(s)) continue;
|
|
4015
|
+
if (seen.has(s)) continue;
|
|
4016
|
+
seen.add(s);
|
|
4017
|
+
ordered.push(s);
|
|
4018
|
+
}
|
|
4019
|
+
return ordered;
|
|
4020
|
+
}
|
|
4021
|
+
return [...TOP_LEVEL_SCOPES];
|
|
4022
|
+
}, [requestedScopes]);
|
|
4023
|
+
useEffect(() => {
|
|
4024
|
+
if (requestedScopes.includes("facet") && !WARNED_FACET_DEPRECATED) {
|
|
4025
|
+
WARNED_FACET_DEPRECATED = true;
|
|
4026
|
+
console.warn(
|
|
4027
|
+
'[RecordsAdminShell] The "facet" top-level scope was removed in 0.5.0. Use the Rules tab\'s built-in "Browse by facet" filter instead. Drop "facet" (and any `defaultScope: "facet"`) from your `scopes` prop.'
|
|
4028
|
+
);
|
|
4029
|
+
}
|
|
4030
|
+
}, [requestedScopes]);
|
|
3888
4031
|
const drillVariantsAllowed = useMemo(
|
|
3889
4032
|
() => requestedScopes.includes("variant") && (probe.isLoading || probe.hasVariants),
|
|
3890
4033
|
[requestedScopes, probe.isLoading, probe.hasVariants]
|
|
@@ -3896,7 +4039,6 @@ function RecordsAdminShell(props) {
|
|
|
3896
4039
|
const initialScope = useMemo(() => {
|
|
3897
4040
|
if (contextScope?.productId && topLevelScopes.includes("product")) return "product";
|
|
3898
4041
|
if (defaultScope && topLevelScopes.includes(defaultScope)) return defaultScope;
|
|
3899
|
-
if (topLevelScopes.includes("facet")) return "facet";
|
|
3900
4042
|
return topLevelScopes[0] ?? "product";
|
|
3901
4043
|
}, [contextScope?.productId, defaultScope, topLevelScopes]);
|
|
3902
4044
|
const [activeScope, setActiveScope] = useState(initialScope);
|
|
@@ -3906,7 +4048,9 @@ function RecordsAdminShell(props) {
|
|
|
3906
4048
|
const [search, setSearch] = useState("");
|
|
3907
4049
|
const [filter, setFilter] = useState("all");
|
|
3908
4050
|
const [ruleFilters, setRuleFilters] = useState(EMPTY_RULE_FILTERS);
|
|
3909
|
-
const [
|
|
4051
|
+
const [facetBrowseFilter, setFacetBrowseFilter] = useState(null);
|
|
4052
|
+
const [selectedRecordId, setSelectedRecordId] = useState(null);
|
|
4053
|
+
const [draftKind, setDraftKind] = useState(null);
|
|
3910
4054
|
const [selectedProductId, setSelectedProductId] = useState(
|
|
3911
4055
|
contextScope?.productId
|
|
3912
4056
|
);
|
|
@@ -3950,7 +4094,7 @@ function RecordsAdminShell(props) {
|
|
|
3950
4094
|
search: activeScope === "product" ? search : "",
|
|
3951
4095
|
enabled: activeScope === "product" && !contextScope?.productId
|
|
3952
4096
|
});
|
|
3953
|
-
const recordListEnabled = (activeScope === "
|
|
4097
|
+
const recordListEnabled = (activeScope === "rule" || activeScope === "collection") && !probe.isLoading;
|
|
3954
4098
|
const recordList = useRecordList({
|
|
3955
4099
|
ctx,
|
|
3956
4100
|
scopeKind: activeScope,
|
|
@@ -3963,10 +4107,8 @@ function RecordsAdminShell(props) {
|
|
|
3963
4107
|
const facetBrowse = useFacetBrowse({
|
|
3964
4108
|
SL,
|
|
3965
4109
|
collectionId,
|
|
3966
|
-
existing:
|
|
3967
|
-
|
|
3968
|
-
filter,
|
|
3969
|
-
enabled: activeScope === "facet" && !probe.isLoading
|
|
4110
|
+
existing: [],
|
|
4111
|
+
enabled: (activeScope === "rule" || activeScope === "collection") && !probe.isLoading
|
|
3970
4112
|
});
|
|
3971
4113
|
const variantChildren = useProductChildren({
|
|
3972
4114
|
SL,
|
|
@@ -3986,32 +4128,32 @@ function RecordsAdminShell(props) {
|
|
|
3986
4128
|
const first = productBrowse.items[0];
|
|
3987
4129
|
if (first) setSelectedProductId(first.id);
|
|
3988
4130
|
}, [activeScope, selectedProductId, productBrowse.items]);
|
|
3989
|
-
useEffect(() => {
|
|
3990
|
-
if (activeScope !== "facet") return;
|
|
3991
|
-
if (selectedFacetRef) return;
|
|
3992
|
-
const first = facetBrowse.items[0];
|
|
3993
|
-
if (first) setSelectedFacetRef(first.ref);
|
|
3994
|
-
}, [activeScope, selectedFacetRef, facetBrowse.items]);
|
|
3995
4131
|
useEffect(() => {
|
|
3996
4132
|
if (activeScope !== "rule" && activeScope !== "collection") return;
|
|
3997
|
-
if (
|
|
4133
|
+
if (selectedRecordId !== null) return;
|
|
3998
4134
|
if (activeScope === "collection" && cardinality === "collection") {
|
|
3999
|
-
setSelectedFacetRef("");
|
|
4000
4135
|
return;
|
|
4001
4136
|
}
|
|
4002
4137
|
const first = recordList.items[0];
|
|
4003
|
-
if (first)
|
|
4004
|
-
}, [activeScope,
|
|
4138
|
+
if (first?.id) setSelectedRecordId(first.id);
|
|
4139
|
+
}, [activeScope, selectedRecordId, recordList.items, cardinality]);
|
|
4005
4140
|
useEffect(() => {
|
|
4006
4141
|
setSearch("");
|
|
4007
4142
|
setFilter("all");
|
|
4008
4143
|
setRuleFilters(EMPTY_RULE_FILTERS);
|
|
4009
|
-
|
|
4144
|
+
setFacetBrowseFilter(null);
|
|
4145
|
+
setSelectedRecordId(null);
|
|
4146
|
+
setDraftKind(null);
|
|
4010
4147
|
}, [activeScope]);
|
|
4011
4148
|
const editingScope = useMemo(() => {
|
|
4012
|
-
if (activeScope === "
|
|
4013
|
-
if (
|
|
4014
|
-
|
|
4149
|
+
if (activeScope === "rule" || activeScope === "collection") {
|
|
4150
|
+
if (selectedRecordId === null) return null;
|
|
4151
|
+
if (selectedRecordId === DRAFT_ID) {
|
|
4152
|
+
return parseRef("");
|
|
4153
|
+
}
|
|
4154
|
+
const hit = recordList.items.find((it) => it.id === selectedRecordId);
|
|
4155
|
+
if (!hit) return null;
|
|
4156
|
+
return hit.scope;
|
|
4015
4157
|
}
|
|
4016
4158
|
if (!selectedProductId) return null;
|
|
4017
4159
|
if (drillTab === "variant") {
|
|
@@ -4023,19 +4165,9 @@ function RecordsAdminShell(props) {
|
|
|
4023
4165
|
return parseRef(buildRef({ productId: selectedProductId, batchId: selectedBatchId }));
|
|
4024
4166
|
}
|
|
4025
4167
|
return parseRef(buildRef({ productId: selectedProductId }));
|
|
4026
|
-
}, [activeScope,
|
|
4168
|
+
}, [activeScope, selectedRecordId, recordList.items, selectedProductId, drillTab, selectedVariantId, selectedBatchId]);
|
|
4027
4169
|
const isCollection = cardinality === "collection";
|
|
4028
|
-
const
|
|
4029
|
-
if (!isCollection) return null;
|
|
4030
|
-
if (!selectedItemId) return null;
|
|
4031
|
-
const baseRef = editingScope?.raw ?? "";
|
|
4032
|
-
return buildItemRef(baseRef, selectedItemId);
|
|
4033
|
-
}, [isCollection, selectedItemId, editingScope]);
|
|
4034
|
-
const editingTargetScope = useMemo(() => {
|
|
4035
|
-
if (!isCollection) return editingScope;
|
|
4036
|
-
if (!editingItemRef) return null;
|
|
4037
|
-
return parseRef(editingItemRef);
|
|
4038
|
-
}, [isCollection, editingScope, editingItemRef]);
|
|
4170
|
+
const editingTargetScope = editingScope;
|
|
4039
4171
|
const skipNextItemResetRef = useRef(false);
|
|
4040
4172
|
useEffect(() => {
|
|
4041
4173
|
if (skipNextItemResetRef.current) {
|
|
@@ -4052,20 +4184,19 @@ function RecordsAdminShell(props) {
|
|
|
4052
4184
|
useEffect(() => {
|
|
4053
4185
|
if (!deepLinkState.enabled) return;
|
|
4054
4186
|
if (selectedItemId) return;
|
|
4055
|
-
deepLinkState.emit({ scope: editingScope?.raw ?? null,
|
|
4187
|
+
deepLinkState.emit({ scope: editingScope?.raw ?? null, recordId: null }, "scope");
|
|
4056
4188
|
lastAppliedDLRef.current = `${""}|${editingScope?.raw ?? ""}|${itemView}`;
|
|
4057
4189
|
}, [deepLinkState.enabled, editingScope?.raw, selectedItemId, itemView]);
|
|
4058
4190
|
useEffect(() => {
|
|
4059
4191
|
if (!deepLinkState.enabled) return;
|
|
4060
|
-
const {
|
|
4061
|
-
const sig = `${
|
|
4192
|
+
const { recordId, scope, view } = deepLinkState.urlState;
|
|
4193
|
+
const sig = `${recordId ?? ""}|${scope ?? ""}|${view ?? ""}`;
|
|
4062
4194
|
if (sig === lastAppliedDLRef.current) return;
|
|
4063
4195
|
lastAppliedDLRef.current = sig;
|
|
4064
4196
|
if (view && itemViews.includes(view) && view !== itemView) {
|
|
4065
4197
|
setItemView(view);
|
|
4066
4198
|
}
|
|
4067
|
-
const railRef =
|
|
4068
|
-
const itemId = item ? item.includes("item:") ? item.slice(item.lastIndexOf("item:") + "item:".length) : item : null;
|
|
4199
|
+
const railRef = scope ?? "";
|
|
4069
4200
|
const parsed = railRef ? parseRef(railRef) : null;
|
|
4070
4201
|
if (parsed?.productId) {
|
|
4071
4202
|
if (activeScope !== "product") setActiveScope("product");
|
|
@@ -4075,17 +4206,16 @@ function RecordsAdminShell(props) {
|
|
|
4075
4206
|
if (parsed.variantId && selectedVariantId !== parsed.variantId) setSelectedVariantId(parsed.variantId);
|
|
4076
4207
|
if (parsed.batchId && selectedBatchId !== parsed.batchId) setSelectedBatchId(parsed.batchId);
|
|
4077
4208
|
} else if (parsed?.facetId) {
|
|
4078
|
-
if (activeScope !== "
|
|
4079
|
-
if (
|
|
4080
|
-
|
|
4081
|
-
if (selectedFacetRef) setSelectedFacetRef(void 0);
|
|
4082
|
-
}
|
|
4083
|
-
if (itemId !== selectedItemId) {
|
|
4084
|
-
if (railRef && railRef !== editingScope?.raw) {
|
|
4085
|
-
skipNextItemResetRef.current = true;
|
|
4209
|
+
if (activeScope !== "rule" && topLevelScopes.includes("rule")) setActiveScope("rule");
|
|
4210
|
+
if (parsed.facetValue) {
|
|
4211
|
+
setFacetBrowseFilter({ facetKey: parsed.facetId, facetValue: parsed.facetValue });
|
|
4086
4212
|
}
|
|
4087
|
-
|
|
4213
|
+
if (selectedRecordId !== null) setSelectedRecordId(null);
|
|
4214
|
+
} else {
|
|
4215
|
+
if (selectedRecordId !== null) setSelectedRecordId(null);
|
|
4088
4216
|
}
|
|
4217
|
+
setPendingDeepLinkRecordId(recordId ?? null);
|
|
4218
|
+
if (!recordId && selectedItemId !== null) setSelectedItemId(null);
|
|
4089
4219
|
}, [deepLinkState.enabled, deepLinkState.urlState]);
|
|
4090
4220
|
const supportedForResolution = useMemo(() => requestedScopes, [requestedScopes]);
|
|
4091
4221
|
const resolved = useResolvedRecord({
|
|
@@ -4098,7 +4228,12 @@ function RecordsAdminShell(props) {
|
|
|
4098
4228
|
batchId: editingTargetScope?.batchId,
|
|
4099
4229
|
facetId: editingTargetScope?.facetId,
|
|
4100
4230
|
facetValue: editingTargetScope?.facetValue,
|
|
4101
|
-
|
|
4231
|
+
// Id-primary path: when the user has selected a saved record by UUID
|
|
4232
|
+
// (records-driven tabs, deep-link by `?recordId=`), bypass the
|
|
4233
|
+
// inheritance chain and load that exact row. Drafts (`DRAFT_ID`) and
|
|
4234
|
+
// pinned-anchor tabs (Products) leave `recordId` undefined so the
|
|
4235
|
+
// resolver runs `match()` against the anchors above.
|
|
4236
|
+
recordId: selectedRecordId && selectedRecordId !== DRAFT_ID ? selectedRecordId : void 0,
|
|
4102
4237
|
supportedScopes: supportedForResolution,
|
|
4103
4238
|
enabled: !!editingTargetScope
|
|
4104
4239
|
});
|
|
@@ -4129,8 +4264,6 @@ function RecordsAdminShell(props) {
|
|
|
4129
4264
|
onTelemetry?.({ type: "record.delete", recordType, ref: editingTargetScope?.raw ?? "" });
|
|
4130
4265
|
if (isCollection && selectedItemId) {
|
|
4131
4266
|
setSelectedItemId(null);
|
|
4132
|
-
} else if (activeScope === "facet") {
|
|
4133
|
-
setSelectedFacetRef(void 0);
|
|
4134
4267
|
} else if (drillTab === "variant") {
|
|
4135
4268
|
setSelectedVariantId(void 0);
|
|
4136
4269
|
} else if (drillTab === "batch") {
|
|
@@ -4205,24 +4338,16 @@ function RecordsAdminShell(props) {
|
|
|
4205
4338
|
const effectivePreviewScope = previewScope ?? editingScope;
|
|
4206
4339
|
const editorHeaderLabel = useMemo(() => {
|
|
4207
4340
|
if (!editingScope) return void 0;
|
|
4208
|
-
if (activeScope === "facet" && selectedFacetRef) {
|
|
4209
|
-
const hit = facetBrowse.items.find((it) => it.ref === selectedFacetRef);
|
|
4210
|
-
return hit?.label;
|
|
4211
|
-
}
|
|
4212
4341
|
if (activeScope === "product" && selectedProductId) {
|
|
4213
4342
|
const hit = productBrowse.items.find((it) => it.id === selectedProductId);
|
|
4214
4343
|
return hit?.name ?? selectedProductId;
|
|
4215
4344
|
}
|
|
4216
4345
|
return void 0;
|
|
4217
|
-
}, [activeScope, editingScope,
|
|
4346
|
+
}, [activeScope, editingScope, selectedProductId, productBrowse.items]);
|
|
4218
4347
|
const editorHeaderSubtitle = useMemo(() => {
|
|
4219
4348
|
if (!editingScope) return void 0;
|
|
4220
|
-
if (activeScope === "facet" && selectedFacetRef) {
|
|
4221
|
-
const hit = facetBrowse.items.find((it) => it.ref === selectedFacetRef);
|
|
4222
|
-
return hit?.subtitle;
|
|
4223
|
-
}
|
|
4224
4349
|
return void 0;
|
|
4225
|
-
}, [activeScope, editingScope
|
|
4350
|
+
}, [activeScope, editingScope]);
|
|
4226
4351
|
const editorHeaderMeta = useMemo(() => {
|
|
4227
4352
|
if (!editingScope) return void 0;
|
|
4228
4353
|
if (activeScope === "product" && selectedProductId) {
|
|
@@ -4236,8 +4361,8 @@ function RecordsAdminShell(props) {
|
|
|
4236
4361
|
const sourceValue = onCopyOverride ? onCopyOverride({ value: editorCtx.value, scope: editingScope }) : cloneValue(editorCtx.value);
|
|
4237
4362
|
clipboard.set({
|
|
4238
4363
|
value: sourceValue,
|
|
4239
|
-
sourceScope: editingScope
|
|
4240
|
-
|
|
4364
|
+
sourceScope: editingScope,
|
|
4365
|
+
sourceRecordId: resolved.recordId,
|
|
4241
4366
|
sourceLabel: editorHeaderLabel
|
|
4242
4367
|
});
|
|
4243
4368
|
onTelemetry?.({ type: "clipboard.copy", recordType, sourceRef: editingScope.raw });
|
|
@@ -4258,10 +4383,7 @@ function RecordsAdminShell(props) {
|
|
|
4258
4383
|
]);
|
|
4259
4384
|
const pasteCurrent = useCallback(async () => {
|
|
4260
4385
|
if (!enableClipboard || !editingScope || !clipboard.entry) return;
|
|
4261
|
-
const compat = checkPasteCompatibility(
|
|
4262
|
-
{ kind: clipboard.entry.sourceScope, raw: clipboard.entry.sourceRef },
|
|
4263
|
-
editingScope
|
|
4264
|
-
);
|
|
4386
|
+
const compat = checkPasteCompatibility(clipboard.entry.sourceScope, editingScope);
|
|
4265
4387
|
if (compat.status === "denied") {
|
|
4266
4388
|
setClipboardNotice({ message: compat.reason ?? "Paste not allowed here", variant: "paste" });
|
|
4267
4389
|
return;
|
|
@@ -4288,7 +4410,7 @@ function RecordsAdminShell(props) {
|
|
|
4288
4410
|
});
|
|
4289
4411
|
if (!ok) return;
|
|
4290
4412
|
}
|
|
4291
|
-
const sourceParsed =
|
|
4413
|
+
const sourceParsed = clipboard.entry.sourceScope;
|
|
4292
4414
|
const transformed = onPasteOverride ? onPasteOverride(
|
|
4293
4415
|
{ value: clipboard.entry.value, sourceScope: sourceParsed },
|
|
4294
4416
|
{ scope: editingScope, currentValue: editorCtx.value ?? null }
|
|
@@ -4298,12 +4420,12 @@ function RecordsAdminShell(props) {
|
|
|
4298
4420
|
onTelemetry?.({
|
|
4299
4421
|
type: "clipboard.paste",
|
|
4300
4422
|
recordType,
|
|
4301
|
-
sourceRef: clipboard.entry.
|
|
4423
|
+
sourceRef: clipboard.entry.sourceScope.raw,
|
|
4302
4424
|
destinationRef: editingScope.raw,
|
|
4303
4425
|
replaced: willReplace
|
|
4304
4426
|
});
|
|
4305
4427
|
setClipboardNotice({
|
|
4306
|
-
message: i18n.pasteToast.replace("{name}", clipboard.entry.sourceLabel ?? clipboard.entry.
|
|
4428
|
+
message: i18n.pasteToast.replace("{name}", clipboard.entry.sourceLabel ?? clipboard.entry.sourceScope.raw),
|
|
4307
4429
|
variant: "paste"
|
|
4308
4430
|
});
|
|
4309
4431
|
}, [
|
|
@@ -4327,11 +4449,10 @@ function RecordsAdminShell(props) {
|
|
|
4327
4449
|
]);
|
|
4328
4450
|
const editorPasteCompat = useMemo(() => {
|
|
4329
4451
|
if (!enableClipboard || !clipboard.entry || !editingScope) return null;
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
);
|
|
4452
|
+
const sameRecord = clipboard.entry.sourceRecordId && resolved.recordId && clipboard.entry.sourceRecordId === resolved.recordId;
|
|
4453
|
+
const sameAnchor = !clipboard.entry.sourceRecordId && clipboard.entry.sourceScope.raw === editingScope.raw;
|
|
4454
|
+
if (sameRecord || sameAnchor) return { status: "denied" };
|
|
4455
|
+
return checkPasteCompatibility(clipboard.entry.sourceScope, editingScope);
|
|
4335
4456
|
}, [enableClipboard, clipboard.entry, editingScope]);
|
|
4336
4457
|
const editorClipboard = enableClipboard && editingScope ? {
|
|
4337
4458
|
onCopy: copyCurrent,
|
|
@@ -4343,31 +4464,30 @@ function RecordsAdminShell(props) {
|
|
|
4343
4464
|
pasteSourceLabel: clipboard.entry?.sourceLabel,
|
|
4344
4465
|
pasteWillReplace: resolved.source === "self" && !!clipboard.entry
|
|
4345
4466
|
} : void 0;
|
|
4346
|
-
const [
|
|
4467
|
+
const [pendingPasteTarget, setPendingPasteTarget] = useState(null);
|
|
4347
4468
|
useEffect(() => {
|
|
4348
|
-
if (!
|
|
4349
|
-
if (!editingScope
|
|
4469
|
+
if (!pendingPasteTarget) return;
|
|
4470
|
+
if (!editingScope) return;
|
|
4471
|
+
const matched = pendingPasteTarget.kind === "record" ? selectedRecordId === pendingPasteTarget.recordId : editingScope.raw === pendingPasteTarget.ref;
|
|
4472
|
+
if (!matched) return;
|
|
4350
4473
|
const t = window.setTimeout(() => {
|
|
4351
|
-
|
|
4474
|
+
setPendingPasteTarget(null);
|
|
4352
4475
|
void pasteCurrent();
|
|
4353
4476
|
}, 0);
|
|
4354
4477
|
return () => window.clearTimeout(t);
|
|
4355
|
-
}, [
|
|
4478
|
+
}, [pendingPasteTarget, editingScope, selectedRecordId, pasteCurrent]);
|
|
4356
4479
|
const rowClipboard = enableClipboard ? (record) => {
|
|
4357
4480
|
const summaryHasData = record.data != null;
|
|
4358
4481
|
const sourceParsed = record.scope;
|
|
4359
|
-
const compat = clipboard.entry ? checkPasteCompatibility(
|
|
4360
|
-
|
|
4361
|
-
sourceParsed
|
|
4362
|
-
) : null;
|
|
4363
|
-
const sameRef = clipboard.entry?.sourceRef === record.ref;
|
|
4482
|
+
const compat = clipboard.entry ? checkPasteCompatibility(clipboard.entry.sourceScope, sourceParsed) : null;
|
|
4483
|
+
const sameTarget = clipboard.entry ? clipboard.entry.sourceRecordId && record.id ? clipboard.entry.sourceRecordId === record.id : clipboard.entry.sourceScope.raw === record.ref : false;
|
|
4364
4484
|
return {
|
|
4365
4485
|
onCopy: summaryHasData ? () => {
|
|
4366
4486
|
const value = onCopyOverride ? onCopyOverride({ value: record.data, scope: sourceParsed }) : cloneValue(record.data);
|
|
4367
4487
|
clipboard.set({
|
|
4368
4488
|
value,
|
|
4369
|
-
sourceScope: sourceParsed
|
|
4370
|
-
|
|
4489
|
+
sourceScope: sourceParsed,
|
|
4490
|
+
sourceRecordId: record.id ?? void 0,
|
|
4371
4491
|
sourceLabel: record.label
|
|
4372
4492
|
});
|
|
4373
4493
|
onTelemetry?.({ type: "clipboard.copy", recordType, sourceRef: record.ref });
|
|
@@ -4378,9 +4498,11 @@ function RecordsAdminShell(props) {
|
|
|
4378
4498
|
} : void 0,
|
|
4379
4499
|
onPaste: () => {
|
|
4380
4500
|
onLeftSelectRef.current?.(record);
|
|
4381
|
-
|
|
4501
|
+
setPendingPasteTarget(
|
|
4502
|
+
record.id ? { kind: "record", recordId: record.id } : { kind: "anchor", ref: record.ref }
|
|
4503
|
+
);
|
|
4382
4504
|
},
|
|
4383
|
-
canPaste: !!clipboard.entry && !
|
|
4505
|
+
canPaste: !!clipboard.entry && !sameTarget && compat?.status !== "denied",
|
|
4384
4506
|
pasteWillReplace: record.status === "configured",
|
|
4385
4507
|
clipboardSourceLabel: clipboard.entry?.sourceLabel
|
|
4386
4508
|
};
|
|
@@ -4389,6 +4511,7 @@ function RecordsAdminShell(props) {
|
|
|
4389
4511
|
const baseScopeRef = editingScope?.raw ?? "";
|
|
4390
4512
|
const itemNounLabel = itemNoun || "item";
|
|
4391
4513
|
const buildItemUrlValue = useCallback((id) => {
|
|
4514
|
+
if (!baseScopeRef && id.startsWith("item:")) return id;
|
|
4392
4515
|
return baseScopeRef ? `${baseScopeRef}/item:${id}` : id;
|
|
4393
4516
|
}, [baseScopeRef]);
|
|
4394
4517
|
const onItemOpen = useCallback((itemId) => {
|
|
@@ -4396,31 +4519,31 @@ function RecordsAdminShell(props) {
|
|
|
4396
4519
|
void runWithGuard(() => {
|
|
4397
4520
|
setSelectedItemId(itemId);
|
|
4398
4521
|
onTelemetry?.({ type: "item.open", recordType, scopeRef: baseScopeRef, itemId });
|
|
4399
|
-
deepLinkState.emit({
|
|
4522
|
+
deepLinkState.emit({ recordId: itemId, scope: baseScopeRef || null }, "record.open");
|
|
4400
4523
|
});
|
|
4401
4524
|
}, [isCollection, runWithGuard, onTelemetry, recordType, baseScopeRef, deepLinkState, buildItemUrlValue]);
|
|
4402
4525
|
const onItemCreate = useCallback(() => {
|
|
4403
4526
|
if (!isCollection) return;
|
|
4404
4527
|
void runWithGuard(() => {
|
|
4405
|
-
const id = generateItemId ? generateItemId() :
|
|
4528
|
+
const id = generateItemId ? generateItemId() : DRAFT_ID;
|
|
4406
4529
|
setSelectedItemId(id);
|
|
4407
4530
|
onTelemetry?.({ type: "item.create", recordType, scopeRef: baseScopeRef });
|
|
4408
|
-
deepLinkState.emit({
|
|
4531
|
+
deepLinkState.emit({ recordId: null, scope: baseScopeRef || null }, "record.open");
|
|
4409
4532
|
});
|
|
4410
4533
|
}, [isCollection, runWithGuard, generateItemId, onTelemetry, recordType, baseScopeRef, deepLinkState, buildItemUrlValue]);
|
|
4411
4534
|
const onItemDelete = useCallback(async (itemId) => {
|
|
4412
4535
|
if (!isCollection) return;
|
|
4413
|
-
|
|
4536
|
+
if (itemId === DRAFT_ID) return;
|
|
4414
4537
|
if (onBeforeDelete) {
|
|
4415
|
-
const ok = await onBeforeDelete(parseRef(
|
|
4538
|
+
const ok = await onBeforeDelete(editingScope ?? parseRef(""));
|
|
4416
4539
|
if (!ok) return;
|
|
4417
4540
|
}
|
|
4418
4541
|
try {
|
|
4419
|
-
const {
|
|
4420
|
-
await
|
|
4542
|
+
const { removeRecord: removeRecord2 } = await import('../../records-JWS6LKJ2.js');
|
|
4543
|
+
await removeRecord2(ctx, itemId);
|
|
4421
4544
|
onTelemetry?.({ type: "item.delete", recordType, scopeRef: baseScopeRef, itemId });
|
|
4422
4545
|
if (selectedItemId === itemId) setSelectedItemId(null);
|
|
4423
|
-
if (selectedItemId === itemId) deepLinkState.emit({
|
|
4546
|
+
if (selectedItemId === itemId) deepLinkState.emit({ recordId: null }, "record.close");
|
|
4424
4547
|
collectionItems.refetch();
|
|
4425
4548
|
} catch (err) {
|
|
4426
4549
|
console.error("[RecordsAdminShell] item delete failed", err);
|
|
@@ -4455,14 +4578,14 @@ function RecordsAdminShell(props) {
|
|
|
4455
4578
|
const onItemBack = useCallback(() => {
|
|
4456
4579
|
void runWithGuard(() => {
|
|
4457
4580
|
setSelectedItemId(null);
|
|
4458
|
-
deepLinkState.emit({
|
|
4581
|
+
deepLinkState.emit({ recordId: null }, "record.close");
|
|
4459
4582
|
});
|
|
4460
4583
|
}, [runWithGuard, deepLinkState]);
|
|
4461
4584
|
const stepToItem = useCallback((id) => {
|
|
4462
4585
|
void runWithGuard(() => {
|
|
4463
4586
|
setSelectedItemId(id);
|
|
4464
4587
|
onTelemetry?.({ type: "item.open", recordType, scopeRef: baseScopeRef, itemId: id });
|
|
4465
|
-
deepLinkState.emit({
|
|
4588
|
+
deepLinkState.emit({ recordId: id, scope: baseScopeRef || null }, "record.step");
|
|
4466
4589
|
});
|
|
4467
4590
|
}, [runWithGuard, onTelemetry, recordType, baseScopeRef, deepLinkState, buildItemUrlValue]);
|
|
4468
4591
|
const onItemPrev = useCallback(() => {
|
|
@@ -4615,16 +4738,7 @@ function RecordsAdminShell(props) {
|
|
|
4615
4738
|
const productPinned = !!contextScope?.productId;
|
|
4616
4739
|
const effectivePresentation = isProductTab ? presentation : "list";
|
|
4617
4740
|
const showPresentationSwitcher = isProductTab && presentations.length > 1;
|
|
4618
|
-
const effectiveGroupBy =
|
|
4619
|
-
if (groupBy) return groupBy;
|
|
4620
|
-
if (isProductTab) return void 0;
|
|
4621
|
-
return (record) => {
|
|
4622
|
-
const key = record.scope.facetId;
|
|
4623
|
-
if (!key) return null;
|
|
4624
|
-
const label2 = record.subtitle ?? key;
|
|
4625
|
-
return { key, label: label2 };
|
|
4626
|
-
};
|
|
4627
|
-
}, [groupBy, isProductTab]);
|
|
4741
|
+
const effectiveGroupBy = groupBy;
|
|
4628
4742
|
const productListItems = useMemo(() => {
|
|
4629
4743
|
if (productPinned) {
|
|
4630
4744
|
return [{
|
|
@@ -4644,35 +4758,81 @@ function RecordsAdminShell(props) {
|
|
|
4644
4758
|
const isRecordsTab = isRuleTab || isGlobalTab;
|
|
4645
4759
|
const onCreateRule = useCallback(() => {
|
|
4646
4760
|
void runWithGuard(() => {
|
|
4647
|
-
const id = newRuleId();
|
|
4648
|
-
const ref = `rule:${id}`;
|
|
4649
4761
|
if (activeScope !== "rule") setActiveScope("rule");
|
|
4650
|
-
|
|
4762
|
+
setSelectedRecordId(DRAFT_ID);
|
|
4763
|
+
setDraftKind("rule");
|
|
4651
4764
|
});
|
|
4652
4765
|
}, [runWithGuard, activeScope]);
|
|
4653
4766
|
const hasGlobalRecord = useMemo(
|
|
4654
|
-
() => recordList.items.some((it) => !it.scope.productId && !it.scope.facetId && !it.scope.variantId && !it.scope.batchId && !it.scope.proofId
|
|
4767
|
+
() => recordList.items.some((it) => !it.scope.productId && !it.scope.facetId && !it.scope.variantId && !it.scope.batchId && !it.scope.proofId),
|
|
4655
4768
|
[recordList.items]
|
|
4656
4769
|
);
|
|
4657
|
-
const showCreateGlobal = isGlobalTab &&
|
|
4770
|
+
const showCreateGlobal = isGlobalTab && !isCollection && !hasGlobalRecord;
|
|
4658
4771
|
const onCreateGlobal = useCallback(() => {
|
|
4659
4772
|
void runWithGuard(() => {
|
|
4660
4773
|
if (activeScope !== "collection") setActiveScope("collection");
|
|
4661
|
-
|
|
4774
|
+
setSelectedRecordId(DRAFT_ID);
|
|
4775
|
+
setDraftKind("global");
|
|
4662
4776
|
});
|
|
4663
4777
|
}, [runWithGuard, activeScope]);
|
|
4664
4778
|
const filteredRuleItems = useMemo(
|
|
4665
4779
|
() => isRuleTab ? applyRuleFilters(recordList.items, ruleFilters) : recordList.items,
|
|
4666
4780
|
[isRuleTab, recordList.items, ruleFilters]
|
|
4667
4781
|
);
|
|
4668
|
-
const
|
|
4669
|
-
(items) =>
|
|
4670
|
-
|
|
4782
|
+
const applyFacetBrowseFilter = useCallback(
|
|
4783
|
+
(items) => {
|
|
4784
|
+
if (!facetBrowseFilter) return items;
|
|
4785
|
+
const { facetKey, facetValue } = facetBrowseFilter;
|
|
4786
|
+
return items.filter((r) => {
|
|
4787
|
+
const rule = r.facetRule;
|
|
4788
|
+
if (rule?.all?.length) {
|
|
4789
|
+
return rule.all.some((c) => c.facetKey === facetKey && (c.anyOf ?? []).includes(facetValue));
|
|
4790
|
+
}
|
|
4791
|
+
if (r.scope.facetId === facetKey && r.scope.facetValue === facetValue) return true;
|
|
4792
|
+
return false;
|
|
4793
|
+
});
|
|
4794
|
+
},
|
|
4795
|
+
[facetBrowseFilter]
|
|
4796
|
+
);
|
|
4797
|
+
const facetBrowseFacets = useMemo(() => {
|
|
4798
|
+
if (!facetBrowse.items.length) return [];
|
|
4799
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
4800
|
+
for (const it of facetBrowse.items) {
|
|
4801
|
+
const key = it.scope.facetId;
|
|
4802
|
+
const value = it.scope.facetValue;
|
|
4803
|
+
if (!key || !value) continue;
|
|
4804
|
+
const facetLabel = it.subtitle ?? key;
|
|
4805
|
+
const valueLabel = it.label ?? value;
|
|
4806
|
+
const existing = byKey.get(key);
|
|
4807
|
+
if (existing) {
|
|
4808
|
+
if (!existing.values.some((v) => v.key === value)) {
|
|
4809
|
+
existing.values.push({ key: value, label: valueLabel });
|
|
4810
|
+
}
|
|
4811
|
+
} else {
|
|
4812
|
+
byKey.set(key, { key, label: facetLabel, values: [{ key: value, label: valueLabel }] });
|
|
4813
|
+
}
|
|
4814
|
+
}
|
|
4815
|
+
return Array.from(byKey.values());
|
|
4816
|
+
}, [facetBrowse.items]);
|
|
4817
|
+
const collectionGlobalAllRow = useMemo(
|
|
4818
|
+
() => ({
|
|
4819
|
+
id: null,
|
|
4820
|
+
ref: "",
|
|
4821
|
+
scope: parseRef(""),
|
|
4822
|
+
data: null,
|
|
4823
|
+
status: "empty",
|
|
4824
|
+
label: i18n.itemsAllLabel,
|
|
4825
|
+
subtitle: collectionItems.items.length ? `${collectionItems.items.length} ${itemNoun}${collectionItems.items.length === 1 ? "" : "s"}` : void 0
|
|
4826
|
+
}),
|
|
4827
|
+
[i18n.itemsAllLabel, collectionItems.items.length, itemNoun]
|
|
4671
4828
|
);
|
|
4672
|
-
const leftItems = isProductTab ? productListItems : isRuleTab ?
|
|
4673
|
-
const leftLoading = isProductTab ? !productPinned && productBrowse.isLoading : isRecordsTab ? recordList.isLoading || probe.isLoading :
|
|
4674
|
-
const leftError = isProductTab ? productBrowse.error : isRecordsTab ? recordList.error :
|
|
4675
|
-
const
|
|
4829
|
+
const leftItems = isProductTab ? productListItems : isRuleTab ? applyFacetBrowseFilter(filteredRuleItems) : isGlobalTab && isCollection ? [collectionGlobalAllRow] : isRecordsTab ? applyFacetBrowseFilter(recordList.items) : [];
|
|
4830
|
+
const leftLoading = isProductTab ? !productPinned && productBrowse.isLoading : isRecordsTab ? recordList.isLoading || probe.isLoading : false;
|
|
4831
|
+
const leftError = isProductTab ? productBrowse.error : isRecordsTab ? recordList.error : null;
|
|
4832
|
+
const leftSelectedId = isProductTab ? void 0 : selectedRecordId && selectedRecordId !== DRAFT_ID ? selectedRecordId : void 0;
|
|
4833
|
+
const leftSelectedAnchorKey = isProductTab ? selectedProductId ? buildRef({ productId: selectedProductId }) : void 0 : void 0;
|
|
4834
|
+
const dirtyId = !editorCtx.isDirty ? void 0 : selectedRecordId && selectedRecordId !== DRAFT_ID ? selectedRecordId : void 0;
|
|
4835
|
+
const dirtyAnchorKey = !editorCtx.isDirty ? void 0 : isProductTab ? editingScope?.raw : void 0;
|
|
4676
4836
|
const onLeftSelect = (item) => {
|
|
4677
4837
|
void runWithGuard(() => {
|
|
4678
4838
|
if (isProductTab) {
|
|
@@ -4681,7 +4841,8 @@ function RecordsAdminShell(props) {
|
|
|
4681
4841
|
setSelectedBatchId(void 0);
|
|
4682
4842
|
setDrillTab("product");
|
|
4683
4843
|
} else {
|
|
4684
|
-
|
|
4844
|
+
setSelectedRecordId(item.id ?? null);
|
|
4845
|
+
setDraftKind(null);
|
|
4685
4846
|
}
|
|
4686
4847
|
});
|
|
4687
4848
|
};
|
|
@@ -4833,8 +4994,7 @@ function RecordsAdminShell(props) {
|
|
|
4833
4994
|
},
|
|
4834
4995
|
loading: probe.isLoading,
|
|
4835
4996
|
counts: {
|
|
4836
|
-
product: productBrowse.items.length
|
|
4837
|
-
facet: facetBrowse.items.length
|
|
4997
|
+
product: productBrowse.items.length
|
|
4838
4998
|
},
|
|
4839
4999
|
icons: icons.scope
|
|
4840
5000
|
}
|
|
@@ -4893,7 +5053,7 @@ function RecordsAdminShell(props) {
|
|
|
4893
5053
|
}
|
|
4894
5054
|
)
|
|
4895
5055
|
] }),
|
|
4896
|
-
!isProductTab && /* @__PURE__ */ jsx(
|
|
5056
|
+
!isProductTab && !isRuleTab && !isGlobalTab && /* @__PURE__ */ jsx(
|
|
4897
5057
|
StatusFilterPills,
|
|
4898
5058
|
{
|
|
4899
5059
|
value: filter,
|
|
@@ -4910,6 +5070,15 @@ function RecordsAdminShell(props) {
|
|
|
4910
5070
|
value: ruleFilters,
|
|
4911
5071
|
onChange: setRuleFilters
|
|
4912
5072
|
}
|
|
5073
|
+
),
|
|
5074
|
+
(isRuleTab || isGlobalTab && !isCollection) && /* @__PURE__ */ jsx(
|
|
5075
|
+
FacetBrowseFilter,
|
|
5076
|
+
{
|
|
5077
|
+
facets: facetBrowseFacets,
|
|
5078
|
+
value: facetBrowseFilter,
|
|
5079
|
+
onChange: setFacetBrowseFilter,
|
|
5080
|
+
isLoading: facetBrowse.isLoading
|
|
5081
|
+
}
|
|
4913
5082
|
)
|
|
4914
5083
|
] }),
|
|
4915
5084
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
|
|
@@ -4928,9 +5097,11 @@ function RecordsAdminShell(props) {
|
|
|
4928
5097
|
RecordList,
|
|
4929
5098
|
{
|
|
4930
5099
|
items: leftItems,
|
|
4931
|
-
|
|
5100
|
+
selectedId: leftSelectedId,
|
|
5101
|
+
selectedAnchorKey: leftSelectedAnchorKey,
|
|
4932
5102
|
onSelect: onLeftSelect,
|
|
4933
|
-
|
|
5103
|
+
dirtyId,
|
|
5104
|
+
dirtyAnchorKey,
|
|
4934
5105
|
presentation: effectivePresentation,
|
|
4935
5106
|
renderListRow,
|
|
4936
5107
|
groupBy: effectiveGroupBy,
|
|
@@ -4973,7 +5144,6 @@ function RecordsAdminShell(props) {
|
|
|
4973
5144
|
}
|
|
4974
5145
|
),
|
|
4975
5146
|
!isCollection && !editingScope && activeScope === "product" && !selectedProductId && /* @__PURE__ */ jsx(EmptyState, { title: i18n.emptyTitle, body: i18n.emptyBody }),
|
|
4976
|
-
!isCollection && !editingScope && activeScope === "facet" && /* @__PURE__ */ jsx(EmptyState, { title: i18n.emptyTitle, body: i18n.emptyBody }),
|
|
4977
5147
|
isProductTab && selectedProductId && (!isCollection || selectedItemId) && /* @__PURE__ */ jsx(
|
|
4978
5148
|
ProductDrillDown,
|
|
4979
5149
|
{
|
|
@@ -5024,7 +5194,7 @@ var RecordBrowser = ({
|
|
|
5024
5194
|
scopes,
|
|
5025
5195
|
activeScope,
|
|
5026
5196
|
onActiveScopeChange,
|
|
5027
|
-
|
|
5197
|
+
selectedId,
|
|
5028
5198
|
onSelectRef,
|
|
5029
5199
|
items,
|
|
5030
5200
|
counts,
|
|
@@ -5067,7 +5237,7 @@ var RecordBrowser = ({
|
|
|
5067
5237
|
!isLoading && error && /* @__PURE__ */ jsx(ErrorState, { error }),
|
|
5068
5238
|
!isLoading && !error && items.length === 0 && /* @__PURE__ */ jsx(EmptyState, { title: i18n.noResults, body: search ? void 0 : i18n.emptyBody }),
|
|
5069
5239
|
!isLoading && !error && items.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5070
|
-
/* @__PURE__ */ jsx(RecordList, { items,
|
|
5240
|
+
/* @__PURE__ */ jsx(RecordList, { items, selectedId, onSelect: onSelectRef }),
|
|
5071
5241
|
hasNextPage && /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
|
|
5072
5242
|
"button",
|
|
5073
5243
|
{
|
|
@@ -5332,16 +5502,13 @@ function useCollectedRecords(args) {
|
|
|
5332
5502
|
target.facetValue = facetValue;
|
|
5333
5503
|
const ctx = { SL, collectionId, appId, recordType };
|
|
5334
5504
|
const result = await matchRecords(ctx, parsedRefToTarget(target), { strategy: "all" }).catch(() => null);
|
|
5335
|
-
const
|
|
5336
|
-
const baseList =
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
depth: i
|
|
5343
|
-
};
|
|
5344
|
-
});
|
|
5505
|
+
const entries = result?.data ?? [];
|
|
5506
|
+
const baseList = entries.map((entry, i) => ({
|
|
5507
|
+
ref: entry.ref ?? "",
|
|
5508
|
+
scope: parseRef(entry.ref ?? ""),
|
|
5509
|
+
data: entry.data,
|
|
5510
|
+
depth: i
|
|
5511
|
+
}));
|
|
5345
5512
|
const sortKind = sort?.kind ?? "specificity";
|
|
5346
5513
|
const direction = sort?.direction ?? (sortKind === "specificity" ? "desc" : "asc");
|
|
5347
5514
|
const sign = direction === "desc" ? -1 : 1;
|
|
@@ -5424,11 +5591,11 @@ function useMergedRecord(args) {
|
|
|
5424
5591
|
target.facetValue = facetValue;
|
|
5425
5592
|
const ctx = { SL, collectionId, appId, recordType };
|
|
5426
5593
|
const result = await matchRecords(ctx, parsedRefToTarget(target), { strategy: "all" }).catch(() => null);
|
|
5427
|
-
const
|
|
5428
|
-
if (
|
|
5429
|
-
const present =
|
|
5430
|
-
ref: entry.
|
|
5431
|
-
data: entry.
|
|
5594
|
+
const entries = result?.data ?? [];
|
|
5595
|
+
if (entries.length === 0) return { data: null, provenance: {}, layers: [] };
|
|
5596
|
+
const present = entries.map((entry) => ({
|
|
5597
|
+
ref: entry.ref ?? "",
|
|
5598
|
+
data: entry.data
|
|
5432
5599
|
}));
|
|
5433
5600
|
const ordered = [...present].reverse();
|
|
5434
5601
|
let merged = null;
|
|
@@ -5451,6 +5618,6 @@ function useMergedRecord(args) {
|
|
|
5451
5618
|
};
|
|
5452
5619
|
}
|
|
5453
5620
|
|
|
5454
|
-
export { ALL_ITEM_VIEWS, ALL_PRESENTATIONS, BatchList, BulkActionsMenu, DEFAULT_DEEP_LINK_PARAM_NAMES, DEFAULT_I18N, DEFAULT_ICONS, DefaultItemCards, DefaultItemTable, DefaultRecordCard, DefaultRecordRow, DeleteButton, DrawerPreview, EditorItemNav, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, ItemListView, ItemViewSwitcher, LoadingState, PresentationSwitcher, PreviewScopePicker, PreviewToggleButton, ProductDrillDown, ProductList, RecordBrowser, RecordEditor, RecordList, RecordsAdminShell, ResolvedPreview, ScopeBreadcrumb, ScopeTabs, SiblingRail, SidePreview, StatusDot, StatusFilterPills, StatusIcon, TabbedPreview, UtilityRow, VariantList,
|
|
5621
|
+
export { ALL_ITEM_VIEWS, ALL_PRESENTATIONS, BatchList, BulkActionsMenu, DEFAULT_DEEP_LINK_PARAM_NAMES, DEFAULT_I18N, DEFAULT_ICONS, DefaultItemCards, DefaultItemTable, DefaultRecordCard, DefaultRecordRow, DeleteButton, DrawerPreview, EditorItemNav, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, ItemListView, ItemViewSwitcher, LoadingState, PresentationSwitcher, PreviewScopePicker, PreviewToggleButton, ProductDrillDown, ProductList, RecordBrowser, RecordEditor, RecordList, RecordsAdminShell, ResolvedPreview, ScopeBreadcrumb, ScopeTabs, SiblingRail, SidePreview, StatusDot, StatusFilterPills, StatusIcon, TabbedPreview, UtilityRow, VariantList, buildRef, checkPasteCompatibility, cloneValue, createDefaultDeepLinkAdapter, downloadBlob, exportCsv, importCsv, mergeIcons, parseRef, pickHeaderIcon, resolutionChain, resolveRecord, statusToneLabel, useCollectedRecords, useCollectionItems, useDeepLinkState, useDirtyNavigation, useFacetBrowse, useIntroDismissed, useItemViewPref, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordClipboard, useRecordEditor, useRecordList, useResolveAllRecords, useResolvedRecord, useRulePreview, useScopeProbe, useUnsavedGuard };
|
|
5455
5622
|
//# sourceMappingURL=index.js.map
|
|
5456
5623
|
//# sourceMappingURL=index.js.map
|