@proveanything/smartlinks-utils-ui 0.9.13 → 0.10.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/components/AssetPicker/index.css +29 -0
- package/dist/components/AssetPicker/index.css.map +1 -1
- package/dist/components/ConditionsEditor/index.css +29 -0
- package/dist/components/ConditionsEditor/index.css.map +1 -1
- package/dist/components/FontPicker/index.css +29 -0
- package/dist/components/FontPicker/index.css.map +1 -1
- package/dist/components/IconPicker/index.css +29 -0
- package/dist/components/IconPicker/index.css.map +1 -1
- package/dist/components/RecordsAdmin/index.css +29 -0
- package/dist/components/RecordsAdmin/index.css.map +1 -1
- package/dist/components/RecordsAdmin/index.d.ts +125 -14
- package/dist/components/RecordsAdmin/index.js +257 -103
- package/dist/components/RecordsAdmin/index.js.map +1 -1
- package/dist/index.css +29 -0
- package/dist/index.css.map +1 -1
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@ import { cn } from '../../chunk-L7FQ52F5.js';
|
|
|
6
6
|
import { parsedRefToTarget, parsedRefToScope, matchRecords, scopesEqual, getRecordById, listRecords, upsertRecord, updateRecord, createRecord, removeRecord } from '../../chunk-KA4MKRHL.js';
|
|
7
7
|
export { bulkDelete, bulkUpsert, createRecord, getRecordById, listRecords, matchRecords, parsedRefToScope, parsedRefToTarget, removeRecord, restoreRecord, scopesEqual, upsertRecord } from '../../chunk-KA4MKRHL.js';
|
|
8
8
|
import { createContext, useState, useEffect, useCallback, useMemo, useRef, useContext, useSyncExternalStore, useLayoutEffect, createElement, useId } from 'react';
|
|
9
|
-
import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, List, SlidersHorizontal, Globe, Tag, Boxes, Layers, Package, Rows3, ChevronRight, Eraser, ClipboardPaste, Box, X, Search, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, CornerDownLeft, Circle, AlertCircle, Undo2, Save, Loader2, XCircle, ArrowRight, BookOpen, Globe2,
|
|
9
|
+
import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, List, SlidersHorizontal, Globe, Tag, Boxes, Layers, Package, Target, Rows3, ChevronRight, Eraser, ClipboardPaste, Box, X, Search, Image, Table, ArrowLeft, ChevronLeft, AlertTriangle, Info, HelpCircle, CornerDownLeft, Circle, CopyPlus, AlertCircle, Undo2, Save, Loader2, XCircle, ArrowRight, BookOpen, Globe2, Check, Settings2 } from 'lucide-react';
|
|
10
10
|
import { useQuery, useQueryClient, useInfiniteQuery } from '@tanstack/react-query';
|
|
11
11
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
12
12
|
import { createPortal } from 'react-dom';
|
|
@@ -142,6 +142,8 @@ var DEFAULT_I18N = {
|
|
|
142
142
|
pasteConfirmCancel: "Cancel",
|
|
143
143
|
pasteWarnTitle: "Cross-scope paste",
|
|
144
144
|
pasteWarnContinue: "Continue",
|
|
145
|
+
duplicateAction: "Duplicate",
|
|
146
|
+
duplicateToast: "Duplicated {name}. Review and Save.",
|
|
145
147
|
itemsAllLabel: "All items",
|
|
146
148
|
subtitleEmpty: "Not set",
|
|
147
149
|
subtitleConfigured: "Configured",
|
|
@@ -1549,7 +1551,8 @@ function useShellClipboard(args) {
|
|
|
1549
1551
|
onTelemetry,
|
|
1550
1552
|
onCopyOverride,
|
|
1551
1553
|
onPasteOverride,
|
|
1552
|
-
onLeftSelectRef
|
|
1554
|
+
onLeftSelectRef,
|
|
1555
|
+
onCreateItemDraftRef
|
|
1553
1556
|
} = args;
|
|
1554
1557
|
const clipboard = useRecordClipboard({
|
|
1555
1558
|
appId,
|
|
@@ -1681,8 +1684,7 @@ function useShellClipboard(args) {
|
|
|
1681
1684
|
const rowClipboard = enabled ? (record) => {
|
|
1682
1685
|
const summaryHasData = record.data != null;
|
|
1683
1686
|
const sourceParsed = record.scope;
|
|
1684
|
-
const
|
|
1685
|
-
const sameTarget = clipboard.entry ? clipboard.entry.sourceRecordId && record.id ? clipboard.entry.sourceRecordId === record.id : clipboard.entry.sourceScope.raw === anchorKey(record.scope) : false;
|
|
1687
|
+
const canDuplicate = summaryHasData && isCollection;
|
|
1686
1688
|
return {
|
|
1687
1689
|
onCopy: summaryHasData ? () => {
|
|
1688
1690
|
const value = onCopyOverride ? onCopyOverride({ value: record.data, scope: sourceParsed }) : cloneValue(record.data);
|
|
@@ -1698,15 +1700,27 @@ function useShellClipboard(args) {
|
|
|
1698
1700
|
variant: "copy"
|
|
1699
1701
|
});
|
|
1700
1702
|
} : void 0,
|
|
1701
|
-
|
|
1703
|
+
onDuplicate: canDuplicate ? () => {
|
|
1704
|
+
const value = onCopyOverride ? onCopyOverride({ value: record.data, scope: sourceParsed }) : cloneValue(record.data);
|
|
1705
|
+
clipboard.set({
|
|
1706
|
+
value,
|
|
1707
|
+
sourceScope: sourceParsed,
|
|
1708
|
+
sourceRecordId: record.id ?? void 0,
|
|
1709
|
+
sourceLabel: record.label
|
|
1710
|
+
});
|
|
1711
|
+
onTelemetry?.({ type: "clipboard.copy", recordType, sourceRef: anchorKey(record.scope) });
|
|
1702
1712
|
onLeftSelectRef.current?.(record);
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
)
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1713
|
+
const create = onCreateItemDraftRef?.current;
|
|
1714
|
+
if (!create) return;
|
|
1715
|
+
window.setTimeout(() => {
|
|
1716
|
+
const newId = create();
|
|
1717
|
+
if (newId) setPendingPasteTarget({ kind: "record", recordId: newId });
|
|
1718
|
+
}, 0);
|
|
1719
|
+
setNotice({
|
|
1720
|
+
message: i18n.duplicateToast.replace("{name}", record.label),
|
|
1721
|
+
variant: "copy"
|
|
1722
|
+
});
|
|
1723
|
+
} : void 0
|
|
1710
1724
|
};
|
|
1711
1725
|
} : void 0;
|
|
1712
1726
|
const toast = notice ? /* @__PURE__ */ jsx(
|
|
@@ -1860,14 +1874,17 @@ function useShellNavigation(args) {
|
|
|
1860
1874
|
lastAppliedDLRef
|
|
1861
1875
|
]);
|
|
1862
1876
|
const onItemCreate = useCallback(() => {
|
|
1863
|
-
if (!isCollection) return;
|
|
1877
|
+
if (!isCollection) return void 0;
|
|
1878
|
+
let createdId;
|
|
1864
1879
|
void runWithGuard(() => {
|
|
1865
1880
|
const id = coerceDraftItemId(generateItemId);
|
|
1881
|
+
createdId = id;
|
|
1866
1882
|
setSelectedItemId(id);
|
|
1867
1883
|
onTelemetry?.({ type: "item.create", recordType, scopeRef: baseScopeRef });
|
|
1868
1884
|
deepLinkState.emit({ recordId: null, scope: baseScopeRef || null }, "record.open");
|
|
1869
1885
|
stampEcho(null, baseScopeRef || null);
|
|
1870
1886
|
});
|
|
1887
|
+
return createdId;
|
|
1871
1888
|
}, [
|
|
1872
1889
|
isCollection,
|
|
1873
1890
|
runWithGuard,
|
|
@@ -1951,7 +1968,9 @@ function useShellNavigation(args) {
|
|
|
1951
1968
|
]);
|
|
1952
1969
|
const itemViewCtx = useMemo(() => ({
|
|
1953
1970
|
onOpen: onItemOpen,
|
|
1954
|
-
onCreate:
|
|
1971
|
+
onCreate: () => {
|
|
1972
|
+
onItemCreate();
|
|
1973
|
+
},
|
|
1955
1974
|
onDelete: (id) => {
|
|
1956
1975
|
void onItemDelete(id);
|
|
1957
1976
|
},
|
|
@@ -2108,20 +2127,6 @@ var useShellDeepLink = (args) => {
|
|
|
2108
2127
|
const [pendingDeepLinkRecordId, setPendingDeepLinkRecordId] = useState(null);
|
|
2109
2128
|
const preserveInitialRecordIdRef = useRef(!!deepLinkState.urlState.recordId);
|
|
2110
2129
|
const warnedMissingRef = useRef(/* @__PURE__ */ new Set());
|
|
2111
|
-
const bootLoggedRef = useRef(false);
|
|
2112
|
-
if (!bootLoggedRef.current) {
|
|
2113
|
-
bootLoggedRef.current = true;
|
|
2114
|
-
console.info("[RecordsAdminShell] deep-link boot snapshot", {
|
|
2115
|
-
enabled: deepLinkState.enabled,
|
|
2116
|
-
urlStateRecordId: deepLinkState.urlState.recordId ?? null,
|
|
2117
|
-
urlStateScope: deepLinkState.urlState.scope ?? null,
|
|
2118
|
-
urlStateView: deepLinkState.urlState.view ?? null,
|
|
2119
|
-
urlStateRaw: JSON.stringify(deepLinkState.urlState),
|
|
2120
|
-
paramNames: deepLinkState.paramNames,
|
|
2121
|
-
windowHash: typeof window !== "undefined" ? window.location.hash : null,
|
|
2122
|
-
windowSearch: typeof window !== "undefined" ? window.location.search : null
|
|
2123
|
-
});
|
|
2124
|
-
}
|
|
2125
2130
|
useEffect(() => {
|
|
2126
2131
|
if (!deepLinkState.enabled) return;
|
|
2127
2132
|
if (selectedItemId) return;
|
|
@@ -2140,14 +2145,6 @@ var useShellDeepLink = (args) => {
|
|
|
2140
2145
|
useEffect(() => {
|
|
2141
2146
|
const { recordId, scope, view } = deepLinkState.urlState;
|
|
2142
2147
|
const sig = `${recordId ?? ""}|${scope ?? ""}|${view ?? ""}`;
|
|
2143
|
-
console.info("[RecordsAdminShell] restore effect tick", {
|
|
2144
|
-
enabled: deepLinkState.enabled,
|
|
2145
|
-
recordId,
|
|
2146
|
-
scope,
|
|
2147
|
-
view,
|
|
2148
|
-
sig,
|
|
2149
|
-
lastApplied: lastAppliedDLRef.current
|
|
2150
|
-
});
|
|
2151
2148
|
if (!deepLinkState.enabled) return;
|
|
2152
2149
|
if (sig === lastAppliedDLRef.current) return;
|
|
2153
2150
|
lastAppliedDLRef.current = sig;
|
|
@@ -2174,31 +2171,9 @@ var useShellDeepLink = (args) => {
|
|
|
2174
2171
|
}
|
|
2175
2172
|
setPendingDeepLinkRecordId(recordId ?? null);
|
|
2176
2173
|
if (recordId) preserveInitialRecordIdRef.current = true;
|
|
2177
|
-
if (recordId) {
|
|
2178
|
-
console.info("[RecordsAdminShell] deep-link restore \u2014 pending recordId set", {
|
|
2179
|
-
recordId,
|
|
2180
|
-
scope: scope ?? null,
|
|
2181
|
-
view: view ?? null
|
|
2182
|
-
});
|
|
2183
|
-
}
|
|
2184
|
-
if (!recordId && selectedItemId !== null) {
|
|
2185
|
-
console.info("[RecordsAdminShell] preserving selected item during restore without recordId", {
|
|
2186
|
-
selectedItemId,
|
|
2187
|
-
scope,
|
|
2188
|
-
view
|
|
2189
|
-
});
|
|
2190
|
-
}
|
|
2191
2174
|
}, [deepLinkState.enabled, deepLinkState.urlState]);
|
|
2192
2175
|
useEffect(() => {
|
|
2193
2176
|
const pending = pendingDeepLinkRecordId;
|
|
2194
|
-
console.info("[RecordsAdminShell] resolver tick", {
|
|
2195
|
-
pending,
|
|
2196
|
-
isCollection,
|
|
2197
|
-
collectionItemsCount: collectionItems.items.length,
|
|
2198
|
-
collectionItemsLoading: collectionItems.isLoading,
|
|
2199
|
-
recordListCount: recordListItems.length,
|
|
2200
|
-
recordListLoading
|
|
2201
|
-
});
|
|
2202
2177
|
if (!pending) return;
|
|
2203
2178
|
if (isCollection) {
|
|
2204
2179
|
const hit2 = collectionItems.items.find((it) => it.id === pending || it.itemId === pending);
|
|
@@ -3282,10 +3257,8 @@ var statusToneLabel = (tone) => {
|
|
|
3282
3257
|
};
|
|
3283
3258
|
var RowContextMenu = ({
|
|
3284
3259
|
onCopy,
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
pasteWillReplace,
|
|
3288
|
-
pasteSourceLabel,
|
|
3260
|
+
onDuplicate,
|
|
3261
|
+
actions,
|
|
3289
3262
|
i18n
|
|
3290
3263
|
}) => {
|
|
3291
3264
|
const [open, setOpen] = useState(false);
|
|
@@ -3334,8 +3307,9 @@ var RowContextMenu = ({
|
|
|
3334
3307
|
window.removeEventListener("scroll", update, true);
|
|
3335
3308
|
};
|
|
3336
3309
|
}, [open]);
|
|
3337
|
-
|
|
3338
|
-
|
|
3310
|
+
const hasActions = (actions?.length ?? 0) > 0;
|
|
3311
|
+
if (!onCopy && !onDuplicate && !hasActions) return null;
|
|
3312
|
+
const showDivider = (onCopy || onDuplicate) && hasActions;
|
|
3339
3313
|
return /* @__PURE__ */ jsxs("div", { ref: wrapperRef, className: "ra-row-menu-wrap relative", children: [
|
|
3340
3314
|
/* @__PURE__ */ jsx(
|
|
3341
3315
|
"button",
|
|
@@ -3381,24 +3355,49 @@ var RowContextMenu = ({
|
|
|
3381
3355
|
]
|
|
3382
3356
|
}
|
|
3383
3357
|
),
|
|
3384
|
-
|
|
3358
|
+
onDuplicate && /* @__PURE__ */ jsxs(
|
|
3385
3359
|
"button",
|
|
3386
3360
|
{
|
|
3387
3361
|
type: "button",
|
|
3388
3362
|
role: "menuitem",
|
|
3389
3363
|
className: "ra-row-menu-item",
|
|
3390
|
-
disabled: !canPaste,
|
|
3391
3364
|
onClick: (e) => {
|
|
3392
3365
|
e.stopPropagation();
|
|
3393
3366
|
setOpen(false);
|
|
3394
|
-
|
|
3367
|
+
onDuplicate();
|
|
3395
3368
|
},
|
|
3396
3369
|
children: [
|
|
3397
|
-
/* @__PURE__ */ jsx(
|
|
3398
|
-
/* @__PURE__ */ jsx("span", {
|
|
3370
|
+
/* @__PURE__ */ jsx(CopyPlus, { className: "w-3 h-3", "aria-hidden": "true" }),
|
|
3371
|
+
/* @__PURE__ */ jsx("span", { children: i18n.duplicateAction })
|
|
3399
3372
|
]
|
|
3400
3373
|
}
|
|
3401
|
-
)
|
|
3374
|
+
),
|
|
3375
|
+
showDivider && /* @__PURE__ */ jsx("div", { className: "ra-row-menu-divider", role: "separator" }),
|
|
3376
|
+
hasActions && actions.map((action) => {
|
|
3377
|
+
const Icon = action.icon;
|
|
3378
|
+
return /* @__PURE__ */ jsxs(
|
|
3379
|
+
"button",
|
|
3380
|
+
{
|
|
3381
|
+
type: "button",
|
|
3382
|
+
role: "menuitem",
|
|
3383
|
+
className: "ra-row-menu-item",
|
|
3384
|
+
"data-tone": action.variant === "danger" ? "danger" : void 0,
|
|
3385
|
+
disabled: action.disabled,
|
|
3386
|
+
title: action.disabled ? action.disabledReason : void 0,
|
|
3387
|
+
onClick: (e) => {
|
|
3388
|
+
e.stopPropagation();
|
|
3389
|
+
if (action.disabled) return;
|
|
3390
|
+
setOpen(false);
|
|
3391
|
+
void action.onAction();
|
|
3392
|
+
},
|
|
3393
|
+
children: [
|
|
3394
|
+
Icon && /* @__PURE__ */ jsx(Icon, { className: "w-3 h-3" }),
|
|
3395
|
+
/* @__PURE__ */ jsx("span", { children: action.label })
|
|
3396
|
+
]
|
|
3397
|
+
},
|
|
3398
|
+
action.key
|
|
3399
|
+
);
|
|
3400
|
+
})
|
|
3402
3401
|
]
|
|
3403
3402
|
}
|
|
3404
3403
|
),
|
|
@@ -3447,7 +3446,7 @@ var RuleLabelLookupProvider = ({
|
|
|
3447
3446
|
return /* @__PURE__ */ jsx(RuleLabelLookupContext.Provider, { value: v, children });
|
|
3448
3447
|
};
|
|
3449
3448
|
var DefaultRecordRow = ({ record, ctx, compact = false }) => {
|
|
3450
|
-
const { selected, onSelect, isDirty, hasError, onCopy,
|
|
3449
|
+
const { selected, onSelect, isDirty, hasError, onCopy, onDuplicate, actions } = ctx;
|
|
3451
3450
|
const ruleLabelLookup = useRuleLabelLookup();
|
|
3452
3451
|
const ScopeIcon = record.scope.kind && record.scope.kind !== "collection" ? DEFAULT_ICONS.scope[record.scope.kind] : DEFAULT_ICONS.scope.product;
|
|
3453
3452
|
const tone = resolveTone(void 0, record.status);
|
|
@@ -3500,7 +3499,7 @@ var DefaultRecordRow = ({ record, ctx, compact = false }) => {
|
|
|
3500
3499
|
className: "ra-row-rule-pip",
|
|
3501
3500
|
title: ruleSummary ? `Targeted: ${ruleSummary}` : "This record has targeting rules",
|
|
3502
3501
|
"aria-label": ruleSummary ? `Targeted: ${ruleSummary}` : "This record has targeting rules",
|
|
3503
|
-
children: /* @__PURE__ */ jsx(
|
|
3502
|
+
children: /* @__PURE__ */ jsx(Target, { className: "w-3 h-3", "aria-hidden": "true" })
|
|
3504
3503
|
}
|
|
3505
3504
|
),
|
|
3506
3505
|
hasError ? /* @__PURE__ */ jsx(
|
|
@@ -3519,20 +3518,15 @@ var DefaultRecordRow = ({ record, ctx, compact = false }) => {
|
|
|
3519
3518
|
}
|
|
3520
3519
|
)
|
|
3521
3520
|
] }),
|
|
3522
|
-
(onCopy ||
|
|
3521
|
+
(onCopy || onDuplicate || actions && actions.length > 0) && /* @__PURE__ */ jsx(
|
|
3523
3522
|
RowContextMenu,
|
|
3524
3523
|
{
|
|
3525
3524
|
onCopy,
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
pasteWillReplace,
|
|
3529
|
-
pasteSourceLabel: clipboardSourceLabel,
|
|
3525
|
+
onDuplicate,
|
|
3526
|
+
actions,
|
|
3530
3527
|
i18n: {
|
|
3531
3528
|
copy: DEFAULT_I18N.copy,
|
|
3532
|
-
|
|
3533
|
-
pasteFrom: DEFAULT_I18N.pasteFrom,
|
|
3534
|
-
pasteReplace: DEFAULT_I18N.pasteReplace,
|
|
3535
|
-
clipboardEmpty: DEFAULT_I18N.clipboardEmpty
|
|
3529
|
+
duplicateAction: DEFAULT_I18N.duplicateAction
|
|
3536
3530
|
}
|
|
3537
3531
|
}
|
|
3538
3532
|
)
|
|
@@ -3554,10 +3548,37 @@ var RecordList = ({
|
|
|
3554
3548
|
groupBy,
|
|
3555
3549
|
renderGroupActions,
|
|
3556
3550
|
rowClipboard,
|
|
3551
|
+
rowActions,
|
|
3557
3552
|
i18n
|
|
3558
3553
|
}) => {
|
|
3554
|
+
const containerRef = useRef(null);
|
|
3555
|
+
const onKeyDown = useCallback((e) => {
|
|
3556
|
+
const key = e.key;
|
|
3557
|
+
if (key !== "ArrowDown" && key !== "ArrowUp" && key !== "Home" && key !== "End") {
|
|
3558
|
+
return;
|
|
3559
|
+
}
|
|
3560
|
+
const root = containerRef.current;
|
|
3561
|
+
if (!root) return;
|
|
3562
|
+
const buttons = Array.from(
|
|
3563
|
+
root.querySelectorAll("button.ra-row-hit")
|
|
3564
|
+
).filter((btn) => !btn.hasAttribute("disabled") && btn.offsetParent !== null);
|
|
3565
|
+
if (buttons.length === 0) return;
|
|
3566
|
+
const active = document.activeElement;
|
|
3567
|
+
const currentIdx = active ? buttons.indexOf(active) : -1;
|
|
3568
|
+
let nextIdx = currentIdx;
|
|
3569
|
+
if (key === "ArrowDown") nextIdx = currentIdx < 0 ? 0 : Math.min(currentIdx + 1, buttons.length - 1);
|
|
3570
|
+
else if (key === "ArrowUp") nextIdx = currentIdx <= 0 ? 0 : currentIdx - 1;
|
|
3571
|
+
else if (key === "Home") nextIdx = 0;
|
|
3572
|
+
else if (key === "End") nextIdx = buttons.length - 1;
|
|
3573
|
+
if (nextIdx !== currentIdx && buttons[nextIdx]) {
|
|
3574
|
+
e.preventDefault();
|
|
3575
|
+
buttons[nextIdx].focus();
|
|
3576
|
+
buttons[nextIdx].scrollIntoView({ block: "nearest" });
|
|
3577
|
+
}
|
|
3578
|
+
}, []);
|
|
3559
3579
|
const buildCtx = (item) => {
|
|
3560
3580
|
const cb = rowClipboard ? rowClipboard(item) : null;
|
|
3581
|
+
const extraActions = rowActions ? rowActions(item) ?? void 0 : void 0;
|
|
3561
3582
|
const itemAnchorKey = anchorKey(item.scope);
|
|
3562
3583
|
const idMatch = selectedId != null && item.id != null && item.id === selectedId;
|
|
3563
3584
|
const anchorMatch = selectedAnchorKey != null && !!itemAnchorKey && itemAnchorKey === selectedAnchorKey;
|
|
@@ -3572,7 +3593,8 @@ var RecordList = ({
|
|
|
3572
3593
|
isDirty: dirtyIdMatch || dirtyAnchorMatch || idInStore || anchorInStore,
|
|
3573
3594
|
hasError: errorInStore,
|
|
3574
3595
|
i18n,
|
|
3575
|
-
...cb ?? {}
|
|
3596
|
+
...cb ?? {},
|
|
3597
|
+
actions: extraActions && extraActions.length > 0 ? extraActions : void 0
|
|
3576
3598
|
};
|
|
3577
3599
|
};
|
|
3578
3600
|
const groups = useMemo(() => {
|
|
@@ -3599,15 +3621,33 @@ var RecordList = ({
|
|
|
3599
3621
|
};
|
|
3600
3622
|
if (groups) {
|
|
3601
3623
|
return /* @__PURE__ */ jsx(
|
|
3602
|
-
|
|
3624
|
+
"div",
|
|
3603
3625
|
{
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3626
|
+
ref: containerRef,
|
|
3627
|
+
onKeyDown,
|
|
3628
|
+
role: "listbox",
|
|
3629
|
+
"aria-label": "Records",
|
|
3630
|
+
children: /* @__PURE__ */ jsx(
|
|
3631
|
+
GroupedList,
|
|
3632
|
+
{
|
|
3633
|
+
groups,
|
|
3634
|
+
renderItems,
|
|
3635
|
+
renderGroupActions
|
|
3636
|
+
}
|
|
3637
|
+
)
|
|
3607
3638
|
}
|
|
3608
3639
|
);
|
|
3609
3640
|
}
|
|
3610
|
-
return
|
|
3641
|
+
return /* @__PURE__ */ jsx(
|
|
3642
|
+
"div",
|
|
3643
|
+
{
|
|
3644
|
+
ref: containerRef,
|
|
3645
|
+
onKeyDown,
|
|
3646
|
+
role: "listbox",
|
|
3647
|
+
"aria-label": "Records",
|
|
3648
|
+
children: renderItems(items)
|
|
3649
|
+
}
|
|
3650
|
+
);
|
|
3611
3651
|
};
|
|
3612
3652
|
var GroupedList = ({
|
|
3613
3653
|
groups,
|
|
@@ -5518,6 +5558,8 @@ function DefaultItemTable({
|
|
|
5518
5558
|
selectedId,
|
|
5519
5559
|
onOpen,
|
|
5520
5560
|
onDelete,
|
|
5561
|
+
rowActions,
|
|
5562
|
+
rowClipboard,
|
|
5521
5563
|
i18n
|
|
5522
5564
|
}) {
|
|
5523
5565
|
const cols = columns ?? [];
|
|
@@ -5555,6 +5597,31 @@ function DefaultItemTable({
|
|
|
5555
5597
|
/* @__PURE__ */ jsx("td", { className: "ra-item-row-meta", children: formatDate(item.updatedAt) })
|
|
5556
5598
|
] }) : cols.map((c) => /* @__PURE__ */ jsx("td", { style: { textAlign: c.align ?? "left" }, children: c.render(item) }, c.key)),
|
|
5557
5599
|
/* @__PURE__ */ jsxs("td", { className: "ra-item-row-actions", children: [
|
|
5600
|
+
(() => {
|
|
5601
|
+
const extra = rowActions ? rowActions(item) ?? void 0 : void 0;
|
|
5602
|
+
const cb = rowClipboard ? rowClipboard(item) : null;
|
|
5603
|
+
const hasExtras = !!(extra && extra.length > 0);
|
|
5604
|
+
if (!cb?.onCopy && !cb?.onDuplicate && !hasExtras) return null;
|
|
5605
|
+
return /* @__PURE__ */ jsx(
|
|
5606
|
+
"span",
|
|
5607
|
+
{
|
|
5608
|
+
onClick: (e) => e.stopPropagation(),
|
|
5609
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
5610
|
+
children: /* @__PURE__ */ jsx(
|
|
5611
|
+
RowContextMenu,
|
|
5612
|
+
{
|
|
5613
|
+
onCopy: cb?.onCopy,
|
|
5614
|
+
onDuplicate: cb?.onDuplicate,
|
|
5615
|
+
actions: extra ?? void 0,
|
|
5616
|
+
i18n: {
|
|
5617
|
+
copy: DEFAULT_I18N.copy,
|
|
5618
|
+
duplicateAction: DEFAULT_I18N.duplicateAction
|
|
5619
|
+
}
|
|
5620
|
+
}
|
|
5621
|
+
)
|
|
5622
|
+
}
|
|
5623
|
+
);
|
|
5624
|
+
})(),
|
|
5558
5625
|
/* @__PURE__ */ jsx(
|
|
5559
5626
|
"button",
|
|
5560
5627
|
{
|
|
@@ -5598,6 +5665,8 @@ function DefaultItemCards({
|
|
|
5598
5665
|
ctx,
|
|
5599
5666
|
renderCard,
|
|
5600
5667
|
cardSize = "md",
|
|
5668
|
+
rowActions,
|
|
5669
|
+
rowClipboard,
|
|
5601
5670
|
i18n
|
|
5602
5671
|
}) {
|
|
5603
5672
|
const isGallery = variant === "gallery";
|
|
@@ -5610,10 +5679,13 @@ function DefaultItemCards({
|
|
|
5610
5679
|
const id = item.itemId ?? "";
|
|
5611
5680
|
const key = item.id ?? (id || anchorKey(item.scope) || `pos:${idx}`);
|
|
5612
5681
|
const open = () => ctx.onOpen(id);
|
|
5682
|
+
const extraActions = rowActions ? rowActions(item) ?? void 0 : void 0;
|
|
5683
|
+
const cb = rowClipboard ? rowClipboard(item) : null;
|
|
5613
5684
|
const slotCtx = {
|
|
5614
5685
|
...ctx,
|
|
5615
5686
|
selected: selectedId === id,
|
|
5616
|
-
onSelect: open
|
|
5687
|
+
onSelect: open,
|
|
5688
|
+
actions: extraActions && extraActions.length > 0 ? extraActions : void 0
|
|
5617
5689
|
};
|
|
5618
5690
|
if (renderCard) {
|
|
5619
5691
|
return /* @__PURE__ */ jsx(
|
|
@@ -5640,6 +5712,26 @@ function DefaultItemCards({
|
|
|
5640
5712
|
/* @__PURE__ */ jsx("div", { className: "ra-item-card-title", children: item.label }),
|
|
5641
5713
|
item.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-item-card-sub", children: item.subtitle })
|
|
5642
5714
|
] }),
|
|
5715
|
+
(cb?.onCopy || cb?.onDuplicate || extraActions && extraActions.length > 0) && /* @__PURE__ */ jsx(
|
|
5716
|
+
"span",
|
|
5717
|
+
{
|
|
5718
|
+
className: "ra-item-card-menu",
|
|
5719
|
+
onClick: (e) => e.stopPropagation(),
|
|
5720
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
5721
|
+
children: /* @__PURE__ */ jsx(
|
|
5722
|
+
RowContextMenu,
|
|
5723
|
+
{
|
|
5724
|
+
onCopy: cb?.onCopy,
|
|
5725
|
+
onDuplicate: cb?.onDuplicate,
|
|
5726
|
+
actions: extraActions,
|
|
5727
|
+
i18n: {
|
|
5728
|
+
copy: DEFAULT_I18N.copy,
|
|
5729
|
+
duplicateAction: DEFAULT_I18N.duplicateAction
|
|
5730
|
+
}
|
|
5731
|
+
}
|
|
5732
|
+
)
|
|
5733
|
+
}
|
|
5734
|
+
),
|
|
5643
5735
|
/* @__PURE__ */ jsx(
|
|
5644
5736
|
"button",
|
|
5645
5737
|
{
|
|
@@ -5677,6 +5769,8 @@ function ItemListView({
|
|
|
5677
5769
|
renderItemEmpty,
|
|
5678
5770
|
itemColumns,
|
|
5679
5771
|
cardSize = "md",
|
|
5772
|
+
rowActions,
|
|
5773
|
+
rowClipboard,
|
|
5680
5774
|
i18n
|
|
5681
5775
|
}) {
|
|
5682
5776
|
const newLabel = i18n.newItem.includes("{noun}") ? i18n.newItem.replace("{noun}", itemNoun) : i18n.newItem;
|
|
@@ -5747,6 +5841,8 @@ function ItemListView({
|
|
|
5747
5841
|
selectedId: ctx.selectedId,
|
|
5748
5842
|
onOpen: ctx.onOpen,
|
|
5749
5843
|
onDelete: ctx.onDelete,
|
|
5844
|
+
rowActions,
|
|
5845
|
+
rowClipboard,
|
|
5750
5846
|
i18n
|
|
5751
5847
|
}
|
|
5752
5848
|
);
|
|
@@ -5760,6 +5856,8 @@ function ItemListView({
|
|
|
5760
5856
|
ctx,
|
|
5761
5857
|
renderCard: renderItemCard,
|
|
5762
5858
|
cardSize,
|
|
5859
|
+
rowActions,
|
|
5860
|
+
rowClipboard,
|
|
5763
5861
|
i18n
|
|
5764
5862
|
}
|
|
5765
5863
|
);
|
|
@@ -5890,7 +5988,7 @@ function SiblingRail({
|
|
|
5890
5988
|
className: "ra-row-rule-pip",
|
|
5891
5989
|
title: ruleSummary ? `Targeted: ${ruleSummary}` : "This item has targeting rules",
|
|
5892
5990
|
"aria-label": ruleSummary ? `Targeted: ${ruleSummary}` : "This item has targeting rules",
|
|
5893
|
-
children: /* @__PURE__ */ jsx(
|
|
5991
|
+
children: /* @__PURE__ */ jsx(Target, { className: "w-3 h-3", "aria-hidden": "true" })
|
|
5894
5992
|
}
|
|
5895
5993
|
),
|
|
5896
5994
|
hasError ? /* @__PURE__ */ jsx(
|
|
@@ -7144,6 +7242,7 @@ function RecordsAdminShellInner(props) {
|
|
|
7144
7242
|
unsaved,
|
|
7145
7243
|
clipboard,
|
|
7146
7244
|
actions,
|
|
7245
|
+
recordActions,
|
|
7147
7246
|
icons: iconsOverride,
|
|
7148
7247
|
// Deep linking
|
|
7149
7248
|
deepLink
|
|
@@ -7600,6 +7699,7 @@ function RecordsAdminShellInner(props) {
|
|
|
7600
7699
|
i18n
|
|
7601
7700
|
]);
|
|
7602
7701
|
const onLeftSelectRef = useRef(null);
|
|
7702
|
+
const onCreateItemDraftRef = useRef(null);
|
|
7603
7703
|
const { runWithGuard } = useDirtyNavigation({
|
|
7604
7704
|
strategy: dirtyStrategy,
|
|
7605
7705
|
isDirty: editorCtx.isDirty,
|
|
@@ -7654,19 +7754,37 @@ function RecordsAdminShellInner(props) {
|
|
|
7654
7754
|
onTelemetry,
|
|
7655
7755
|
onCopyOverride,
|
|
7656
7756
|
onPasteOverride,
|
|
7657
|
-
onLeftSelectRef
|
|
7757
|
+
onLeftSelectRef,
|
|
7758
|
+
onCreateItemDraftRef
|
|
7658
7759
|
});
|
|
7659
7760
|
const editorClipboard = shellClipboard.editorClipboard;
|
|
7660
7761
|
const rowClipboard = shellClipboard.rowClipboard;
|
|
7762
|
+
const wrappedRecordActions = recordActions ? (record) => {
|
|
7763
|
+
const list = recordActions(record, record.scope);
|
|
7764
|
+
if (!list || list.length === 0) return list ?? void 0;
|
|
7765
|
+
return list.map((a) => ({
|
|
7766
|
+
...a,
|
|
7767
|
+
onAction: () => {
|
|
7768
|
+
onTelemetry?.({
|
|
7769
|
+
type: "recordAction.invoke",
|
|
7770
|
+
recordType,
|
|
7771
|
+
key: a.key,
|
|
7772
|
+
ref: anchorKey(record.scope)
|
|
7773
|
+
});
|
|
7774
|
+
return a.onAction();
|
|
7775
|
+
}
|
|
7776
|
+
}));
|
|
7777
|
+
} : void 0;
|
|
7661
7778
|
const baseScopeRef = editingScope?.raw ?? "";
|
|
7662
7779
|
const itemNounLabel = itemNoun || "item";
|
|
7663
7780
|
const {
|
|
7664
7781
|
onItemOpen,
|
|
7782
|
+
onItemCreate,
|
|
7665
7783
|
onItemBack,
|
|
7666
7784
|
onItemPrev,
|
|
7667
7785
|
onItemNext,
|
|
7668
7786
|
itemPosition,
|
|
7669
|
-
itemViewCtx} = useShellNavigation({
|
|
7787
|
+
itemViewCtx: baseItemViewCtx} = useShellNavigation({
|
|
7670
7788
|
isCollection,
|
|
7671
7789
|
runWithGuard,
|
|
7672
7790
|
selectedItemId,
|
|
@@ -7686,6 +7804,7 @@ function RecordsAdminShellInner(props) {
|
|
|
7686
7804
|
hooks: props.hooks,
|
|
7687
7805
|
lastAppliedDLRef
|
|
7688
7806
|
});
|
|
7807
|
+
const itemViewCtx = baseItemViewCtx;
|
|
7689
7808
|
const renderEditorWithPreview = () => {
|
|
7690
7809
|
if (!editingTargetScope) return null;
|
|
7691
7810
|
const previewBody = renderPreview && effectivePreviewScope ? renderPreview({ resolved: editorCtx.value, previewScope: effectivePreviewScope }) : null;
|
|
@@ -8151,6 +8270,7 @@ function RecordsAdminShellInner(props) {
|
|
|
8151
8270
|
});
|
|
8152
8271
|
};
|
|
8153
8272
|
onLeftSelectRef.current = onLeftSelect;
|
|
8273
|
+
onCreateItemDraftRef.current = onItemCreate;
|
|
8154
8274
|
return /* @__PURE__ */ jsx(RuleLabelLookupProvider, { value: ruleLabelLookup, children: /* @__PURE__ */ jsxs(
|
|
8155
8275
|
"div",
|
|
8156
8276
|
{
|
|
@@ -8179,7 +8299,7 @@ function RecordsAdminShellInner(props) {
|
|
|
8179
8299
|
}
|
|
8180
8300
|
);
|
|
8181
8301
|
})(),
|
|
8182
|
-
/* @__PURE__ */ jsxs("div", { className: "px-
|
|
8302
|
+
/* @__PURE__ */ jsxs("div", { className: "px-2 pt-2 space-y-2", children: [
|
|
8183
8303
|
intro && !dismissed && !(headerWillRender && resolvedReopenAffordance === "header") && /* @__PURE__ */ jsx(
|
|
8184
8304
|
IntroCard,
|
|
8185
8305
|
{
|
|
@@ -8491,6 +8611,7 @@ function RecordsAdminShellInner(props) {
|
|
|
8491
8611
|
),
|
|
8492
8612
|
renderGroupActions: renderRuleGroupActions,
|
|
8493
8613
|
rowClipboard,
|
|
8614
|
+
rowActions: wrappedRecordActions,
|
|
8494
8615
|
i18n
|
|
8495
8616
|
}
|
|
8496
8617
|
),
|
|
@@ -8589,6 +8710,8 @@ function RecordsAdminShellInner(props) {
|
|
|
8589
8710
|
itemColumns,
|
|
8590
8711
|
cardSize: itemCardSize,
|
|
8591
8712
|
ruleSummary: activeRuleSummary,
|
|
8713
|
+
rowActions: wrappedRecordActions,
|
|
8714
|
+
rowClipboard,
|
|
8592
8715
|
i18n
|
|
8593
8716
|
}
|
|
8594
8717
|
),
|
|
@@ -8675,7 +8798,41 @@ var RecordBrowser = ({
|
|
|
8675
8798
|
scopesLoading,
|
|
8676
8799
|
i18n
|
|
8677
8800
|
}) => {
|
|
8678
|
-
|
|
8801
|
+
const rootRef = useRef(null);
|
|
8802
|
+
const searchRef = useRef(null);
|
|
8803
|
+
useEffect(() => {
|
|
8804
|
+
const root = rootRef.current;
|
|
8805
|
+
if (!root) return;
|
|
8806
|
+
const handler = (e) => {
|
|
8807
|
+
if (e.key !== "/" || e.metaKey || e.ctrlKey || e.altKey) return;
|
|
8808
|
+
const target = e.target;
|
|
8809
|
+
if (!target || !root.contains(target)) return;
|
|
8810
|
+
const tag = target.tagName;
|
|
8811
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || target.isContentEditable) return;
|
|
8812
|
+
e.preventDefault();
|
|
8813
|
+
searchRef.current?.focus();
|
|
8814
|
+
searchRef.current?.select();
|
|
8815
|
+
};
|
|
8816
|
+
root.addEventListener("keydown", handler);
|
|
8817
|
+
return () => root.removeEventListener("keydown", handler);
|
|
8818
|
+
}, []);
|
|
8819
|
+
const onSearchKeyDown = (e) => {
|
|
8820
|
+
if (e.key === "Escape") {
|
|
8821
|
+
if (search) {
|
|
8822
|
+
e.preventDefault();
|
|
8823
|
+
onSearchChange("");
|
|
8824
|
+
} else {
|
|
8825
|
+
e.currentTarget.blur();
|
|
8826
|
+
}
|
|
8827
|
+
} else if (e.key === "ArrowDown") {
|
|
8828
|
+
const first = rootRef.current?.querySelector("button.ra-row-hit");
|
|
8829
|
+
if (first) {
|
|
8830
|
+
e.preventDefault();
|
|
8831
|
+
first.focus();
|
|
8832
|
+
}
|
|
8833
|
+
}
|
|
8834
|
+
};
|
|
8835
|
+
return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: "flex flex-col h-full", style: { background: "hsl(var(--ra-surface))" }, children: [
|
|
8679
8836
|
/* @__PURE__ */ jsx(ScopeTabs, { scopes, active: activeScope, onChange: onActiveScopeChange, loading: scopesLoading }),
|
|
8680
8837
|
/* @__PURE__ */ jsxs("div", { className: "p-3 space-y-2.5 border-b", style: { borderColor: "hsl(var(--ra-border))" }, children: [
|
|
8681
8838
|
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
@@ -8683,9 +8840,11 @@ var RecordBrowser = ({
|
|
|
8683
8840
|
/* @__PURE__ */ jsx(
|
|
8684
8841
|
"input",
|
|
8685
8842
|
{
|
|
8843
|
+
ref: searchRef,
|
|
8686
8844
|
type: "text",
|
|
8687
8845
|
value: search,
|
|
8688
8846
|
onChange: (e) => onSearchChange(e.target.value),
|
|
8847
|
+
onKeyDown: onSearchKeyDown,
|
|
8689
8848
|
placeholder: i18n.searchPlaceholder,
|
|
8690
8849
|
className: "w-full pl-8 pr-3 py-1.5 text-xs rounded-md border bg-transparent focus:outline-none focus:ring-1",
|
|
8691
8850
|
style: {
|
|
@@ -8720,7 +8879,7 @@ var RecordBrowser = ({
|
|
|
8720
8879
|
};
|
|
8721
8880
|
var initials2 = (s) => s.split(/\s+/).filter(Boolean).slice(0, 2).map((p) => p[0]?.toUpperCase() ?? "").join("") || "?";
|
|
8722
8881
|
var DefaultRecordCard = ({ record, ctx, variant = "grid" }) => {
|
|
8723
|
-
const { selected, onSelect, isDirty, hasError, onCopy,
|
|
8882
|
+
const { selected, onSelect, isDirty, hasError, onCopy, onDuplicate, actions } = ctx;
|
|
8724
8883
|
const aspect = variant === "gallery" ? "aspect-video" : "aspect-square";
|
|
8725
8884
|
return /* @__PURE__ */ jsxs(
|
|
8726
8885
|
"button",
|
|
@@ -8781,20 +8940,15 @@ var DefaultRecordCard = ({ record, ctx, variant = "grid" }) => {
|
|
|
8781
8940
|
/* @__PURE__ */ jsxs("div", { className: "p-2.5 min-w-0", children: [
|
|
8782
8941
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-1.5 min-w-0", children: [
|
|
8783
8942
|
/* @__PURE__ */ jsx("div", { className: "ra-row-title flex-1 min-w-0", children: record.label }),
|
|
8784
|
-
(onCopy ||
|
|
8943
|
+
(onCopy || onDuplicate || actions && actions.length > 0) && /* @__PURE__ */ jsx(
|
|
8785
8944
|
RowContextMenu,
|
|
8786
8945
|
{
|
|
8787
8946
|
onCopy,
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
pasteWillReplace,
|
|
8791
|
-
pasteSourceLabel: clipboardSourceLabel,
|
|
8947
|
+
onDuplicate,
|
|
8948
|
+
actions,
|
|
8792
8949
|
i18n: {
|
|
8793
8950
|
copy: DEFAULT_I18N.copy,
|
|
8794
|
-
|
|
8795
|
-
pasteFrom: DEFAULT_I18N.pasteFrom,
|
|
8796
|
-
pasteReplace: DEFAULT_I18N.pasteReplace,
|
|
8797
|
-
clipboardEmpty: DEFAULT_I18N.clipboardEmpty
|
|
8951
|
+
duplicateAction: DEFAULT_I18N.duplicateAction
|
|
8798
8952
|
}
|
|
8799
8953
|
}
|
|
8800
8954
|
)
|