@vertebr/react 0.9.0 → 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/admin/AddonEditor.d.ts +3 -2
- package/dist/components/admin/AddonEditor.d.ts.map +1 -1
- package/dist/components/admin/AddonEditor.js +4 -2
- package/dist/components/admin/AdminContent.d.ts +4 -1
- package/dist/components/admin/AdminContent.d.ts.map +1 -1
- package/dist/components/admin/AdminContent.js +25 -11
- package/dist/components/admin/AdminTopBar.d.ts +6 -2
- package/dist/components/admin/AdminTopBar.d.ts.map +1 -1
- package/dist/components/admin/AdminTopBar.js +27 -4
- package/dist/components/admin/AuditBoard.d.ts +7 -0
- package/dist/components/admin/AuditBoard.d.ts.map +1 -0
- package/dist/components/admin/AuditBoard.js +43 -0
- package/dist/components/admin/HealthModal.d.ts +9 -0
- package/dist/components/admin/HealthModal.d.ts.map +1 -0
- package/dist/components/admin/HealthModal.js +59 -0
- package/dist/components/admin/VertebrAdmin.d.ts.map +1 -1
- package/dist/components/admin/VertebrAdmin.js +88 -22
- package/dist/components/admin/adminSearch.d.ts.map +1 -1
- package/dist/components/admin/adminSearch.js +9 -0
- package/dist/components/admin/breadcrumbs.d.ts.map +1 -1
- package/dist/components/admin/breadcrumbs.js +2 -0
- package/dist/components/admin/routes.d.ts.map +1 -1
- package/dist/components/admin/routes.js +13 -1
- package/dist/components/admin/types.d.ts +2 -0
- package/dist/components/admin/types.d.ts.map +1 -1
- package/dist/components/config/ReferenceInput.d.ts +11 -0
- package/dist/components/config/ReferenceInput.d.ts.map +1 -0
- package/dist/components/config/ReferenceInput.js +99 -0
- package/dist/components/config/RevisionHistory.d.ts +8 -0
- package/dist/components/config/RevisionHistory.d.ts.map +1 -0
- package/dist/components/config/RevisionHistory.js +84 -0
- package/dist/components/config/form/ConfigField.d.ts +3 -2
- package/dist/components/config/form/ConfigField.d.ts.map +1 -1
- package/dist/components/config/form/ConfigField.js +3 -2
- package/dist/components/config/form/ConfigForm.d.ts +1 -1
- package/dist/components/config/form/ConfigForm.d.ts.map +1 -1
- package/dist/components/config/form/ConfigForm.js +13 -6
- package/dist/components/config/form/RecordConfigForm.d.ts +3 -2
- package/dist/components/config/form/RecordConfigForm.d.ts.map +1 -1
- package/dist/components/config/form/RecordConfigForm.js +2 -1
- package/dist/components/config/form/SettingsConfigForm.d.ts +3 -2
- package/dist/components/config/form/SettingsConfigForm.d.ts.map +1 -1
- package/dist/components/config/form/SettingsConfigForm.js +2 -2
- package/dist/components/config/form/types.d.ts +5 -1
- package/dist/components/config/form/types.d.ts.map +1 -1
- package/dist/components/resources/ResourceTable.d.ts +7 -1
- package/dist/components/resources/ResourceTable.d.ts.map +1 -1
- package/dist/components/resources/ResourceTable.js +56 -6
- package/dist/components/theme/ThemeToggle.d.ts +3 -1
- package/dist/components/theme/ThemeToggle.d.ts.map +1 -1
- package/dist/components/theme/ThemeToggle.js +2 -2
- package/dist/components/ui/icons.d.ts +1 -0
- package/dist/components/ui/icons.d.ts.map +1 -1
- package/dist/components/ui/icons.js +6 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/lib/capabilities.d.ts +4 -0
- package/dist/lib/capabilities.d.ts.map +1 -0
- package/dist/lib/capabilities.js +9 -0
- package/dist/styles/audit.css +34 -0
- package/dist/styles/form.css +143 -0
- package/dist/styles/index.css +1 -0
- package/dist/styles/modal.css +111 -0
- package/dist/styles/shell.css +234 -18
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@ import { useToast } from "../../../hooks/useToast";
|
|
|
7
7
|
import { buildZodSchema, groupFields, withSpecVisibility, withSpecVisibilityValues, } from "./helpers";
|
|
8
8
|
import { RecordConfigForm } from "./RecordConfigForm";
|
|
9
9
|
import { SettingsConfigForm } from "./SettingsConfigForm";
|
|
10
|
-
export function ConfigForm({ schema, value, onSave, submitLabel, variant = "config", uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, fonts, fontsLoading, onListFonts, onRefreshFonts, onChange, hideActions, }) {
|
|
10
|
+
export function ConfigForm({ schema, value, onSave, submitLabel, variant = "config", uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, fonts, fontsLoading, onListFonts, onRefreshFonts, onChange, hideActions, client, canWrite = true, }) {
|
|
11
11
|
const { register, clear } = useSaveBar();
|
|
12
12
|
const { push: pushToast } = useToast();
|
|
13
13
|
const editorSchema = useMemo(() => (variant === "record" ? withSpecVisibility(schema) : schema), [schema, variant]);
|
|
@@ -35,6 +35,8 @@ export function ConfigForm({ schema, value, onSave, submitLabel, variant = "conf
|
|
|
35
35
|
setTone(undefined);
|
|
36
36
|
};
|
|
37
37
|
const onSubmit = form.handleSubmit(async (data) => {
|
|
38
|
+
if (!canWrite)
|
|
39
|
+
return;
|
|
38
40
|
setStatus("Saving…");
|
|
39
41
|
setTone(undefined);
|
|
40
42
|
register({ saving: true, isDirty: true, visible: true });
|
|
@@ -65,9 +67,11 @@ export function ConfigForm({ schema, value, onSave, submitLabel, variant = "conf
|
|
|
65
67
|
visible: isDirty,
|
|
66
68
|
isDirty,
|
|
67
69
|
saving: status === "Saving…",
|
|
68
|
-
message:
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
message: !canWrite && isDirty
|
|
71
|
+
? "Missing config.write capability"
|
|
72
|
+
: (status ?? undefined),
|
|
73
|
+
tone: !canWrite && isDirty ? "danger" : tone,
|
|
74
|
+
onSave: canWrite ? () => void onSubmit() : undefined,
|
|
71
75
|
onDiscard,
|
|
72
76
|
});
|
|
73
77
|
return () => clear();
|
|
@@ -80,17 +84,19 @@ export function ConfigForm({ schema, value, onSave, submitLabel, variant = "conf
|
|
|
80
84
|
onDiscard,
|
|
81
85
|
register,
|
|
82
86
|
clear,
|
|
87
|
+
canWrite,
|
|
83
88
|
]);
|
|
84
89
|
useEffect(() => {
|
|
85
90
|
const onKeyDown = (event) => {
|
|
86
91
|
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "s") {
|
|
87
92
|
event.preventDefault();
|
|
88
|
-
|
|
93
|
+
if (canWrite)
|
|
94
|
+
void onSubmit();
|
|
89
95
|
}
|
|
90
96
|
};
|
|
91
97
|
window.addEventListener("keydown", onKeyDown);
|
|
92
98
|
return () => window.removeEventListener("keydown", onKeyDown);
|
|
93
|
-
}, [onSubmit]);
|
|
99
|
+
}, [onSubmit, canWrite]);
|
|
94
100
|
const shared = {
|
|
95
101
|
schema: editorSchema,
|
|
96
102
|
groups,
|
|
@@ -105,6 +111,7 @@ export function ConfigForm({ schema, value, onSave, submitLabel, variant = "conf
|
|
|
105
111
|
fontsLoading,
|
|
106
112
|
onListFonts,
|
|
107
113
|
onRefreshFonts,
|
|
114
|
+
client,
|
|
108
115
|
onSubmit,
|
|
109
116
|
isDirty,
|
|
110
117
|
status,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { UseFormReturn } from "react-hook-form";
|
|
2
|
-
import type { FieldSchema, ResourceUploadMeta } from "@vertebr/client";
|
|
2
|
+
import type { FieldSchema, ResourceUploadMeta, VertebrClient } from "@vertebr/client";
|
|
3
3
|
import type { FieldGroup, GalleryHandlers } from "./types";
|
|
4
4
|
export type RecordConfigFormProps = GalleryHandlers & {
|
|
5
5
|
schema: Record<string, FieldSchema>;
|
|
@@ -11,6 +11,7 @@ export type RecordConfigFormProps = GalleryHandlers & {
|
|
|
11
11
|
url: string;
|
|
12
12
|
name?: string;
|
|
13
13
|
}>>;
|
|
14
|
+
client?: VertebrClient;
|
|
14
15
|
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
|
|
15
16
|
isDirty: boolean;
|
|
16
17
|
status: string | null;
|
|
@@ -19,5 +20,5 @@ export type RecordConfigFormProps = GalleryHandlers & {
|
|
|
19
20
|
submitLabel?: string;
|
|
20
21
|
hideActions?: boolean;
|
|
21
22
|
};
|
|
22
|
-
export declare function RecordConfigForm({ schema, groups, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, onSubmit, isDirty, status, tone, onDiscard, submitLabel, hideActions, }: RecordConfigFormProps): import("react").JSX.Element;
|
|
23
|
+
export declare function RecordConfigForm({ schema, groups, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, client, onSubmit, isDirty, status, tone, onDiscard, submitLabel, hideActions, }: RecordConfigFormProps): import("react").JSX.Element;
|
|
23
24
|
//# sourceMappingURL=RecordConfigForm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RecordConfigForm.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/RecordConfigForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"RecordConfigForm.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/RecordConfigForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAYtF,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE3D,MAAM,MAAM,qBAAqB,GAAG,eAAe,GAAG;IACpD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC;IACvB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,MAAM,EACN,OAAO,EACP,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,EACb,eAAe,EACf,MAAM,EACN,QAAQ,EACR,OAAO,EACP,MAAM,EACN,IAAI,EACJ,SAAS,EACT,WAAW,EACX,WAAW,GACZ,EAAE,qBAAqB,+BAuJvB"}
|
|
@@ -5,7 +5,7 @@ import { ConfigField } from "./ConfigField";
|
|
|
5
5
|
import { ConfigFormActions } from "./ConfigFormActions";
|
|
6
6
|
import { VisibilityEyeButton } from "../VisibilityEye";
|
|
7
7
|
import { findPrimaryImageKey, firstImageUrl, groupVisibilityKey, isStockField, } from "./helpers";
|
|
8
|
-
export function RecordConfigForm({ schema, groups, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, onSubmit, isDirty, status, tone, onDiscard, submitLabel, hideActions, }) {
|
|
8
|
+
export function RecordConfigForm({ schema, groups, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, client, onSubmit, isDirty, status, tone, onDiscard, submitLabel, hideActions, }) {
|
|
9
9
|
const imageKey = findPrimaryImageKey(schema, watched);
|
|
10
10
|
const imageValue = imageKey ? firstImageUrl(watched?.[imageKey]) ?? "" : "";
|
|
11
11
|
const asideGroups = groups.filter((group) => /^(Media|Display|Status)$/i.test(group.id));
|
|
@@ -20,6 +20,7 @@ export function RecordConfigForm({ schema, groups, watched, form, uploads, onUpl
|
|
|
20
20
|
galleryUpload,
|
|
21
21
|
onListGallery,
|
|
22
22
|
onUploadGallery,
|
|
23
|
+
client,
|
|
23
24
|
};
|
|
24
25
|
return (_jsxs("form", { className: "vertebr-form", "data-variant": "record", onSubmit: onSubmit, children: [_jsx("div", { className: "vertebr-form-scroll", children: _jsxs("div", { className: "vertebr-record-layout", children: [_jsxs("aside", { className: "vertebr-record-aside", children: [_jsx("div", { className: "vertebr-record-preview", children: imageValue && looksLikeUrl(imageValue) ? (_jsx("img", { src: imageValue, alt: "" })) : (_jsx("div", { className: "vertebr-record-preview-empty", children: "No image" })) }), imageKey && uploads?.[imageKey] && onUpload ? (_jsx(ImageUploadControl, { meta: uploads[imageKey], label: "Drop a new image or browse", onUpload: async (files) => {
|
|
25
26
|
const [first] = await onUpload(imageKey, files);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { UseFormReturn } from "react-hook-form";
|
|
2
|
-
import type { FieldSchema, ResourceUploadMeta } from "@vertebr/client";
|
|
2
|
+
import type { FieldSchema, ResourceUploadMeta, VertebrClient } from "@vertebr/client";
|
|
3
3
|
import type { FieldGroup, FontLibraryHandlers, GalleryHandlers } from "./types";
|
|
4
4
|
export type SettingsConfigFormProps = GalleryHandlers & FontLibraryHandlers & {
|
|
5
5
|
schema: Record<string, FieldSchema>;
|
|
@@ -11,6 +11,7 @@ export type SettingsConfigFormProps = GalleryHandlers & FontLibraryHandlers & {
|
|
|
11
11
|
url: string;
|
|
12
12
|
name?: string;
|
|
13
13
|
}>>;
|
|
14
|
+
client?: VertebrClient;
|
|
14
15
|
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
|
|
15
16
|
isDirty: boolean;
|
|
16
17
|
status: string | null;
|
|
@@ -19,5 +20,5 @@ export type SettingsConfigFormProps = GalleryHandlers & FontLibraryHandlers & {
|
|
|
19
20
|
submitLabel?: string;
|
|
20
21
|
hideActions?: boolean;
|
|
21
22
|
};
|
|
22
|
-
export declare function SettingsConfigForm({ schema, groups, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, fonts, fontsLoading, onListFonts, onRefreshFonts, onSubmit, isDirty, status, tone, onDiscard, submitLabel, hideActions, }: SettingsConfigFormProps): import("react").JSX.Element;
|
|
23
|
+
export declare function SettingsConfigForm({ schema, groups, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, fonts, fontsLoading, onListFonts, onRefreshFonts, client, onSubmit, isDirty, status, tone, onDiscard, submitLabel, hideActions, }: SettingsConfigFormProps): import("react").JSX.Element;
|
|
23
24
|
//# sourceMappingURL=SettingsConfigForm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsConfigForm.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/SettingsConfigForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"SettingsConfigForm.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/SettingsConfigForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAItF,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAEhF,MAAM,MAAM,uBAAuB,GAAG,eAAe,GACnD,mBAAmB,GAAG;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC;IACvB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEJ,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,MAAM,EACN,OAAO,EACP,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,EACb,eAAe,EACf,KAAK,EACL,YAAY,EACZ,WAAW,EACX,cAAc,EACd,MAAM,EACN,QAAQ,EACR,OAAO,EACP,MAAM,EACN,IAAI,EACJ,SAAS,EACT,WAAW,EACX,WAAW,GACZ,EAAE,uBAAuB,+BAgGzB"}
|
|
@@ -2,11 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { ConfigField } from "./ConfigField";
|
|
3
3
|
import { ConfigFormActions } from "./ConfigFormActions";
|
|
4
4
|
import { isBooleanOnlyGroup } from "./helpers/fields";
|
|
5
|
-
export function SettingsConfigForm({ schema, groups, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, fonts, fontsLoading, onListFonts, onRefreshFonts, onSubmit, isDirty, status, tone, onDiscard, submitLabel, hideActions, }) {
|
|
5
|
+
export function SettingsConfigForm({ schema, groups, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, fonts, fontsLoading, onListFonts, onRefreshFonts, client, onSubmit, isDirty, status, tone, onDiscard, submitLabel, hideActions, }) {
|
|
6
6
|
const singleGroup = groups.length === 1;
|
|
7
7
|
return (_jsxs("form", { className: "vertebr-form", "data-variant": "config", onSubmit: onSubmit, children: [_jsx("div", { className: "vertebr-form-scroll", children: groups.map((group) => {
|
|
8
8
|
const toggleList = isBooleanOnlyGroup(group.fields);
|
|
9
9
|
const showSectionHead = !singleGroup || (group.id !== "General" && group.fields.length > 0);
|
|
10
|
-
return (_jsxs("div", { className: "vertebr-form-section", "data-plain": singleGroup && !showSectionHead ? "true" : undefined, children: [showSectionHead ? (_jsxs("div", { className: "vertebr-form-section-head", children: [_jsx("h3", { children: group.label }), _jsx("span", { className: "vertebr-form-section-count", children: group.fields.length })] })) : null, _jsx("div", { className: "vertebr-form-fields", "data-layout": toggleList ? "settings" : undefined, children: toggleList ? (_jsx("ul", { className: "vertebr-settings-list", children: group.fields.map(([key, field]) => (_jsx(ConfigField, { fieldKey: key, field: field, groupLabel: group.label, variant: "config", schema: schema, watched: watched, form: form, uploads: uploads, onUpload: onUpload, galleryUpload: galleryUpload, onListGallery: onListGallery, onUploadGallery: onUploadGallery, fonts: fonts, fontsLoading: fontsLoading, onListFonts: onListFonts, onRefreshFonts: onRefreshFonts, settingsRow: true }, key))) })) : (group.fields.map(([key, field]) => (_jsx(ConfigField, { fieldKey: key, field: field, groupLabel: group.label, variant: "config", schema: schema, watched: watched, form: form, uploads: uploads, onUpload: onUpload, galleryUpload: galleryUpload, onListGallery: onListGallery, onUploadGallery: onUploadGallery, fonts: fonts, fontsLoading: fontsLoading, onListFonts: onListFonts, onRefreshFonts: onRefreshFonts }, key)))) })] }, group.id));
|
|
10
|
+
return (_jsxs("div", { className: "vertebr-form-section", "data-plain": singleGroup && !showSectionHead ? "true" : undefined, children: [showSectionHead ? (_jsxs("div", { className: "vertebr-form-section-head", children: [_jsx("h3", { children: group.label }), _jsx("span", { className: "vertebr-form-section-count", children: group.fields.length })] })) : null, _jsx("div", { className: "vertebr-form-fields", "data-layout": toggleList ? "settings" : undefined, children: toggleList ? (_jsx("ul", { className: "vertebr-settings-list", children: group.fields.map(([key, field]) => (_jsx(ConfigField, { fieldKey: key, field: field, groupLabel: group.label, variant: "config", schema: schema, watched: watched, form: form, uploads: uploads, onUpload: onUpload, galleryUpload: galleryUpload, onListGallery: onListGallery, onUploadGallery: onUploadGallery, fonts: fonts, fontsLoading: fontsLoading, onListFonts: onListFonts, onRefreshFonts: onRefreshFonts, client: client, settingsRow: true }, key))) })) : (group.fields.map(([key, field]) => (_jsx(ConfigField, { fieldKey: key, field: field, groupLabel: group.label, variant: "config", schema: schema, watched: watched, form: form, uploads: uploads, onUpload: onUpload, galleryUpload: galleryUpload, onListGallery: onListGallery, onUploadGallery: onUploadGallery, fonts: fonts, fontsLoading: fontsLoading, onListFonts: onListFonts, onRefreshFonts: onRefreshFonts, client: client }, key)))) })] }, group.id));
|
|
11
11
|
}) }), hideActions ? null : (_jsx(ConfigFormActions, { form: form, isDirty: isDirty, status: status, tone: tone, onDiscard: onDiscard, submitLabel: submitLabel }))] }));
|
|
12
12
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FieldSchema, FontLibraryItem, GalleryItem, ResourceUploadMeta } from "@vertebr/client";
|
|
1
|
+
import type { FieldSchema, FontLibraryItem, GalleryItem, ResourceUploadMeta, VertebrClient } from "@vertebr/client";
|
|
2
2
|
export type ConfigFormVariant = "config" | "record";
|
|
3
3
|
export type ConfigFormProps = {
|
|
4
4
|
schema: Record<string, FieldSchema>;
|
|
@@ -26,6 +26,10 @@ export type ConfigFormProps = {
|
|
|
26
26
|
onChange?: (value: Record<string, unknown>) => void;
|
|
27
27
|
/** Hide Save / Discard — parent owns submit. */
|
|
28
28
|
hideActions?: boolean;
|
|
29
|
+
/** Used by `reference` fields for typeahead lookup. */
|
|
30
|
+
client?: VertebrClient;
|
|
31
|
+
/** When false, save actions are disabled (missing write capability). */
|
|
32
|
+
canWrite?: boolean;
|
|
29
33
|
};
|
|
30
34
|
export type FieldEntry = [string, FieldSchema];
|
|
31
35
|
export type FieldGroup = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,aAAa,EACd,MAAM,iBAAiB,CAAC;AAEzB,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEpD,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,sDAAsD;IACtD,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,aAAa,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAC/C,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACpD,gDAAgD;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uDAAuD;IACvD,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAE/C,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,eAAe,EACf,eAAe,GAAG,eAAe,GAAG,iBAAiB,CACtD,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,IAAI,CACpC,eAAe,EACf,OAAO,GAAG,cAAc,GAAG,aAAa,GAAG,gBAAgB,CAC5D,CAAC"}
|
|
@@ -22,6 +22,12 @@ type ResourcePanelProps = {
|
|
|
22
22
|
onPreviewMail?: (rowId: string, actionId: string, input?: Record<string, unknown>) => Promise<MailPreviewResponse>;
|
|
23
23
|
collectionActions?: Record<string, ResourceActionMeta>;
|
|
24
24
|
onCollectionAction?: (actionId: string, input?: Record<string, unknown>) => Promise<unknown>;
|
|
25
|
+
bulkActions?: Record<string, ResourceActionMeta>;
|
|
26
|
+
onBulkAction?: (actionId: string, rowIds: string[], input?: Record<string, unknown>) => Promise<unknown>;
|
|
27
|
+
listQuery?: boolean | Record<string, FieldSchema>;
|
|
28
|
+
total?: number;
|
|
29
|
+
searchQuery?: string;
|
|
30
|
+
onSearchChange?: (q: string) => void;
|
|
25
31
|
onUpload?: (field: string, files: File[]) => Promise<Array<{
|
|
26
32
|
url: string;
|
|
27
33
|
name?: string;
|
|
@@ -32,7 +38,7 @@ type ResourcePanelProps = {
|
|
|
32
38
|
initialEditRowId?: string;
|
|
33
39
|
onEditRowIdChange?: (rowId: string | null) => void;
|
|
34
40
|
};
|
|
35
|
-
export declare function ResourcePanel({ schema, items, permissions, actions, label, uploads, rowIdKeys, storageKey, onUpdate, onCreate, onDelete, onAction, onActionDone, onPreviewMail, collectionActions, onCollectionAction, onUpload, galleryUpload, onListGallery, onUploadGallery, initialEditRowId, onEditRowIdChange, }: ResourcePanelProps): import("react").JSX.Element;
|
|
41
|
+
export declare function ResourcePanel({ schema, items, permissions, actions, label, uploads, rowIdKeys, storageKey, onUpdate, onCreate, onDelete, onAction, onActionDone, onPreviewMail, collectionActions, onCollectionAction, bulkActions, onBulkAction, listQuery, total, searchQuery, onSearchChange, onUpload, galleryUpload, onListGallery, onUploadGallery, initialEditRowId, onEditRowIdChange, }: ResourcePanelProps): import("react").JSX.Element;
|
|
36
42
|
/** @deprecated Prefer ResourcePanel */
|
|
37
43
|
export declare function ResourceTable(props: {
|
|
38
44
|
schema: Record<string, FieldSchema>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResourceTable.d.ts","sourceRoot":"","sources":["../../../src/components/resources/ResourceTable.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ResourceTable.d.ts","sourceRoot":"","sources":["../../../src/components/resources/ResourceTable.tsx"],"names":[],"mappings":"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"}
|
|
@@ -130,15 +130,17 @@ function titleFromFilename(name) {
|
|
|
130
130
|
.replace(/\s+/g, " ")
|
|
131
131
|
.trim();
|
|
132
132
|
}
|
|
133
|
-
export function ResourcePanel({ schema, items, permissions, actions = {}, label, uploads, rowIdKeys = ["id", "slug", "uid", "email"], storageKey, onUpdate, onCreate, onDelete, onAction, onActionDone, onPreviewMail, collectionActions = {}, onCollectionAction, onUpload, galleryUpload, onListGallery, onUploadGallery, initialEditRowId, onEditRowIdChange, }) {
|
|
133
|
+
export function ResourcePanel({ schema, items, permissions, actions = {}, label, uploads, rowIdKeys = ["id", "slug", "uid", "email"], storageKey, onUpdate, onCreate, onDelete, onAction, onActionDone, onPreviewMail, collectionActions = {}, onCollectionAction, bulkActions = {}, onBulkAction, listQuery, total, searchQuery = "", onSearchChange, onUpload, galleryUpload, onListGallery, onUploadGallery, initialEditRowId, onEditRowIdChange, }) {
|
|
134
134
|
const [editing, setEditing] = useState(null);
|
|
135
135
|
const [creating, setCreating] = useState(false);
|
|
136
136
|
const [viewing, setViewing] = useState(null);
|
|
137
137
|
const [bulkOpen, setBulkOpen] = useState(false);
|
|
138
138
|
const [busyAction, setBusyAction] = useState(null);
|
|
139
139
|
const [selected, setSelected] = useState(new Set());
|
|
140
|
+
const [searchDraft, setSearchDraft] = useState(searchQuery);
|
|
140
141
|
const [pendingAction, setPendingAction] = useState(null);
|
|
141
142
|
const [pendingCollectionAction, setPendingCollectionAction] = useState(null);
|
|
143
|
+
const [pendingBulkAction, setPendingBulkAction] = useState(null);
|
|
142
144
|
const tableWrapRef = useRef(null);
|
|
143
145
|
const [tableOverflow, setTableOverflow] = useState({
|
|
144
146
|
overflow: false,
|
|
@@ -156,9 +158,24 @@ export function ResourcePanel({ schema, items, permissions, actions = {}, label,
|
|
|
156
158
|
const canUpload = Boolean(uploads && onUpload && Object.keys(uploads).length);
|
|
157
159
|
const actionEntries = Object.entries(actions);
|
|
158
160
|
const collectionActionEntries = Object.entries(collectionActions);
|
|
161
|
+
const bulkActionEntries = Object.entries(bulkActions);
|
|
159
162
|
const fieldKeys = Object.keys(schema);
|
|
160
163
|
const visibilityFields = useMemo(() => fieldKeys.filter((key) => isListVisibilityField(key, schema[key])), [fieldKeys, schema]);
|
|
161
|
-
const selectable = Boolean(onAction && actionEntries.length > 0)
|
|
164
|
+
const selectable = Boolean((onAction && actionEntries.length > 0) ||
|
|
165
|
+
(onBulkAction && bulkActionEntries.length > 0));
|
|
166
|
+
const showSearch = Boolean(listQuery && onSearchChange);
|
|
167
|
+
useEffect(() => {
|
|
168
|
+
setSearchDraft(searchQuery);
|
|
169
|
+
}, [searchQuery]);
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
if (!onSearchChange)
|
|
172
|
+
return;
|
|
173
|
+
const handle = window.setTimeout(() => {
|
|
174
|
+
if (searchDraft !== searchQuery)
|
|
175
|
+
onSearchChange(searchDraft);
|
|
176
|
+
}, 250);
|
|
177
|
+
return () => window.clearTimeout(handle);
|
|
178
|
+
}, [searchDraft, searchQuery, onSearchChange]);
|
|
162
179
|
const openEdit = useCallback((row) => {
|
|
163
180
|
setEditing(row);
|
|
164
181
|
onEditRowIdChange?.(resolveRowId(row, rowIdKeys));
|
|
@@ -332,6 +349,38 @@ export function ResourcePanel({ schema, items, permissions, actions = {}, label,
|
|
|
332
349
|
return;
|
|
333
350
|
void runCollectionAction(actionId);
|
|
334
351
|
}, [collectionActions, onCollectionAction, runCollectionAction]);
|
|
352
|
+
const runBulkAction = useCallback(async (actionId, rowIds, input) => {
|
|
353
|
+
if (!onBulkAction || rowIds.length === 0)
|
|
354
|
+
return;
|
|
355
|
+
setBusyAction(actionId);
|
|
356
|
+
try {
|
|
357
|
+
await onBulkAction(actionId, rowIds, input);
|
|
358
|
+
await onActionDone?.();
|
|
359
|
+
setSelected(new Set());
|
|
360
|
+
}
|
|
361
|
+
catch (error) {
|
|
362
|
+
window.alert(error instanceof Error ? error.message : "Bulk action failed");
|
|
363
|
+
}
|
|
364
|
+
finally {
|
|
365
|
+
setBusyAction(null);
|
|
366
|
+
setPendingBulkAction(null);
|
|
367
|
+
}
|
|
368
|
+
}, [onBulkAction, onActionDone]);
|
|
369
|
+
const queueBulkAction = useCallback((actionId, rowIds) => {
|
|
370
|
+
const meta = bulkActions[actionId];
|
|
371
|
+
if (!meta || rowIds.length === 0 || !onBulkAction)
|
|
372
|
+
return;
|
|
373
|
+
if (actionHasInput(meta)) {
|
|
374
|
+
setPendingBulkAction(actionId);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
const detail = meta.confirm
|
|
378
|
+
? `${meta.label} on ${rowIds.length} row(s)?\n\n${meta.confirm}`
|
|
379
|
+
: `${meta.label} on ${rowIds.length} row(s)?`;
|
|
380
|
+
if (!window.confirm(detail))
|
|
381
|
+
return;
|
|
382
|
+
void runBulkAction(actionId, rowIds);
|
|
383
|
+
}, [bulkActions, onBulkAction, runBulkAction]);
|
|
335
384
|
useEffect(() => {
|
|
336
385
|
setColumnVisibility(readVisibility(storageKey, schema));
|
|
337
386
|
}, [storageKey]);
|
|
@@ -510,7 +559,7 @@ export function ResourcePanel({ schema, items, permissions, actions = {}, label,
|
|
|
510
559
|
closeEdit();
|
|
511
560
|
} })] }));
|
|
512
561
|
}
|
|
513
|
-
const toolbar = (_jsxs("div", { className: "vertebr-table-toolbar", children: [_jsxs("div", { className: "vertebr-table-toolbar-start", children: [columnOptions.length > 0 ? (_jsx(ColumnVisibilityMenu, { columns: columnOptions, visibility: columnVisibility, onChange: setColumnVisibility })) : null, canUpload ? (_jsxs("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-icon", onClick: () => setBulkOpen(true), children: [_jsx(ImageUploadIcon, {}), "Bulk upload"] })) : null, visibilityFields.length > 0 && dirtyVisibilityCount > 0 ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "vertebr-count", children: [dirtyVisibilityCount, " visibility change", dirtyVisibilityCount === 1 ? "" : "s"] }), _jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-primary", disabled: savingVisibility, onClick: () => void saveVisibility(), children: savingVisibility ? "Saving…" : "Save visibility" }), _jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", disabled: savingVisibility, onClick: () => setVisibilityDrafts({}), children: "Discard" })] })) : null, collectionActionEntries.map(([actionId, meta]) => (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", disabled: busyAction != null, onClick: () => queueCollectionAction(actionId), children: meta.label }, actionId))), selectable && selected.size > 0 ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "vertebr-count", children: [selected.size, " selected"] }), actionEntries.map(([actionId, meta]) => (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", disabled: busyAction != null, onClick: () => queueAction(actionId, [...selected]), children: meta.label }, actionId))), _jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", onClick: () => setSelected(new Set()), children: "Clear" })] })) : null] }), tableOverflow.overflow ? (_jsxs("div", { className: "vertebr-table-scroll-controls", role: "group", "aria-label": "Scroll columns", children: [_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-icon vertebr-table-scroll-btn", disabled: !tableOverflow.canLeft, onClick: () => scrollTable("left"), "aria-label": "Scroll columns left", children: _jsx(ChevronLeftIcon, {}) }), _jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-icon vertebr-table-scroll-btn", disabled: !tableOverflow.canRight, onClick: () => scrollTable("right"), "aria-label": "Scroll columns right", children: _jsx(ChevronRightIcon, {}) })] })) : null] }));
|
|
562
|
+
const toolbar = (_jsxs("div", { className: "vertebr-table-toolbar", children: [_jsxs("div", { className: "vertebr-table-toolbar-start", children: [columnOptions.length > 0 ? (_jsx(ColumnVisibilityMenu, { columns: columnOptions, visibility: columnVisibility, onChange: setColumnVisibility })) : null, canUpload ? (_jsxs("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-icon", onClick: () => setBulkOpen(true), children: [_jsx(ImageUploadIcon, {}), "Bulk upload"] })) : null, visibilityFields.length > 0 && dirtyVisibilityCount > 0 ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "vertebr-count", children: [dirtyVisibilityCount, " visibility change", dirtyVisibilityCount === 1 ? "" : "s"] }), _jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-primary", disabled: savingVisibility, onClick: () => void saveVisibility(), children: savingVisibility ? "Saving…" : "Save visibility" }), _jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", disabled: savingVisibility, onClick: () => setVisibilityDrafts({}), children: "Discard" })] })) : null, collectionActionEntries.map(([actionId, meta]) => (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", disabled: busyAction != null, onClick: () => queueCollectionAction(actionId), children: meta.label }, actionId))), selectable && selected.size > 0 ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "vertebr-count", children: [selected.size, " selected"] }), actionEntries.map(([actionId, meta]) => (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", disabled: busyAction != null, onClick: () => queueAction(actionId, [...selected]), children: meta.label }, actionId))), bulkActionEntries.map(([actionId, meta]) => (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", disabled: busyAction != null, onClick: () => queueBulkAction(actionId, [...selected]), children: meta.label }, `bulk:${actionId}`))), _jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", onClick: () => setSelected(new Set()), children: "Clear" })] })) : null] }), tableOverflow.overflow ? (_jsxs("div", { className: "vertebr-table-scroll-controls", role: "group", "aria-label": "Scroll columns", children: [_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-icon vertebr-table-scroll-btn", disabled: !tableOverflow.canLeft, onClick: () => scrollTable("left"), "aria-label": "Scroll columns left", children: _jsx(ChevronLeftIcon, {}) }), _jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-icon vertebr-table-scroll-btn", disabled: !tableOverflow.canRight, onClick: () => scrollTable("right"), "aria-label": "Scroll columns right", children: _jsx(ChevronRightIcon, {}) })] })) : null] }));
|
|
514
563
|
const bulkModal = bulkOpen && uploads && onUpload ? (_jsx(BulkImageUploadModal, { uploads: uploads, canCreate: canCreate, fieldLabels: Object.fromEntries(Object.keys(uploads).map((key) => [
|
|
515
564
|
key,
|
|
516
565
|
schema[key]?.label ?? humanizeKey(key),
|
|
@@ -538,13 +587,14 @@ export function ResourcePanel({ schema, items, permissions, actions = {}, label,
|
|
|
538
587
|
: `Send to ${pendingAction.rowIds.length}`, onClose: () => setPendingAction(null), onSubmit: (value) => runActions(pendingAction.actionId, pendingAction.rowIds, value) })) : null) : null;
|
|
539
588
|
const pendingCollectionModal = pendingCollectionAction &&
|
|
540
589
|
collectionActions[pendingCollectionAction]?.input ? (_jsx(ResourceActionModal, { title: collectionActions[pendingCollectionAction]?.label ?? "Run action", eyebrow: "This resource", schema: actionInputSchema(collectionActions[pendingCollectionAction].input), submitLabel: busyAction ? "Working…" : "Run", onClose: () => setPendingCollectionAction(null), onSubmit: (value) => runCollectionAction(pendingCollectionAction, value) })) : null;
|
|
541
|
-
const
|
|
590
|
+
const pendingBulkModal = pendingBulkAction && bulkActions[pendingBulkAction]?.input ? (_jsx(ResourceActionModal, { title: bulkActions[pendingBulkAction]?.label ?? "Bulk action", eyebrow: `${selected.size} selected`, schema: actionInputSchema(bulkActions[pendingBulkAction].input), submitLabel: busyAction ? "Working…" : "Run", onClose: () => setPendingBulkAction(null), onSubmit: (value) => runBulkAction(pendingBulkAction, [...selected], value) })) : null;
|
|
591
|
+
const recordsHead = (_jsxs("div", { className: "vertebr-panel-head", children: [_jsx("h2", { children: "Records" }), _jsxs("div", { className: "vertebr-panel-head-actions", children: [showSearch ? (_jsx("input", { className: "vertebr-resource-search", type: "search", placeholder: "Search\u2026", value: searchDraft, onChange: (event) => setSearchDraft(event.target.value), "aria-label": "Search records" })) : null, canCreate ? (_jsxs("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet vertebr-btn-icon", onClick: () => setCreating(true), children: [_jsx(PlusIcon, {}), createLabel] })) : null, _jsx("span", { className: "vertebr-count", children: total != null ? `${items.length} of ${total}` : items.length })] })] }));
|
|
542
592
|
if (items.length === 0) {
|
|
543
593
|
return (_jsxs("div", { className: "vertebr-resource-body", children: [recordsHead, canUpload ||
|
|
544
594
|
columnOptions.length > 0 ||
|
|
545
595
|
collectionActionEntries.length > 0
|
|
546
596
|
? toolbar
|
|
547
|
-
: null, _jsx("div", { className: "vertebr-empty", children: "No rows yet." }), bulkModal, createModal, pendingActionModal, pendingCollectionModal] }));
|
|
597
|
+
: null, _jsx("div", { className: "vertebr-empty", children: "No rows yet." }), bulkModal, createModal, pendingActionModal, pendingCollectionModal, pendingBulkModal] }));
|
|
548
598
|
}
|
|
549
599
|
return (_jsxs("div", { className: "vertebr-resource-body", children: [recordsHead, toolbar, _jsx("div", { className: "vertebr-table-wrap", ref: tableWrapRef, "data-overflow": tableOverflow.overflow ? "true" : undefined, "data-overflow-left": tableOverflow.canLeft ? "true" : undefined, "data-overflow-right": tableOverflow.canRight ? "true" : undefined, children: _jsxs("table", { className: "vertebr-table", children: [_jsx("thead", { children: table.getHeaderGroups().map((headerGroup) => (_jsx("tr", { children: headerGroup.headers.map((header) => (_jsx("th", { className: header.column.id === "_actions"
|
|
550
600
|
? "vertebr-col-actions"
|
|
@@ -568,7 +618,7 @@ export function ResourcePanel({ schema, items, permissions, actions = {}, label,
|
|
|
568
618
|
: undefined, children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id))) }, row.id))) })] }) }), viewing ? (_jsx(ResourceViewModal, { schema: schema, row: viewing, title: rowTitle(viewing, rowIdKeys), canEdit: canUpdate, onClose: () => setViewing(null), onEdit: () => {
|
|
569
619
|
openEdit(viewing);
|
|
570
620
|
setViewing(null);
|
|
571
|
-
} })) : null, pendingActionModal, pendingCollectionModal, bulkModal, createModal] }));
|
|
621
|
+
} })) : null, pendingActionModal, pendingCollectionModal, pendingBulkModal, bulkModal, createModal] }));
|
|
572
622
|
}
|
|
573
623
|
/** @deprecated Prefer ResourcePanel */
|
|
574
624
|
export function ResourceTable(props) {
|
|
@@ -2,6 +2,8 @@ import type { VbTheme } from "../../hooks/useVertebrTheme";
|
|
|
2
2
|
export type ThemeToggleProps = {
|
|
3
3
|
theme: VbTheme;
|
|
4
4
|
onChange: (theme: VbTheme) => void;
|
|
5
|
+
/** Icon-only control for dense chrome (top bar). */
|
|
6
|
+
compact?: boolean;
|
|
5
7
|
};
|
|
6
|
-
export declare function ThemeToggle({ theme, onChange }: ThemeToggleProps): import("react").JSX.Element;
|
|
8
|
+
export declare function ThemeToggle({ theme, onChange, compact }: ThemeToggleProps): import("react").JSX.Element;
|
|
7
9
|
//# sourceMappingURL=ThemeToggle.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemeToggle.d.ts","sourceRoot":"","sources":["../../../src/components/theme/ThemeToggle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAE3D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"ThemeToggle.d.ts","sourceRoot":"","sources":["../../../src/components/theme/ThemeToggle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAE3D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,gBAAgB,+BAmCzE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
export function ThemeToggle({ theme, onChange }) {
|
|
3
|
-
return (_jsx("div", { className: "vertebr-theme", children: _jsxs("div", { className: "vertebr-theme-toggle", role: "group", "aria-label": "Appearance", children: [_jsxs("button", { type: "button", className: "vertebr-theme-option", "data-active": theme === "light", "aria-pressed": theme === "light", onClick: () => onChange("light"), children: [_jsx(ThemeSunIcon, {}), "Light"] }), _jsxs("button", { type: "button", className: "vertebr-theme-option", "data-active": theme === "dark", "aria-pressed": theme === "dark", onClick: () => onChange("dark"), children: [_jsx(ThemeMoonIcon, {}), "Dark"] })] }) }));
|
|
2
|
+
export function ThemeToggle({ theme, onChange, compact }) {
|
|
3
|
+
return (_jsx("div", { className: "vertebr-theme", "data-compact": compact ? "true" : undefined, children: _jsxs("div", { className: "vertebr-theme-toggle", role: "group", "aria-label": "Appearance", children: [_jsxs("button", { type: "button", className: "vertebr-theme-option", "data-active": theme === "light", "aria-pressed": theme === "light", "aria-label": "Light", title: "Light", onClick: () => onChange("light"), children: [_jsx(ThemeSunIcon, {}), compact ? null : "Light"] }), _jsxs("button", { type: "button", className: "vertebr-theme-option", "data-active": theme === "dark", "aria-pressed": theme === "dark", "aria-label": "Dark", title: "Dark", onClick: () => onChange("dark"), children: [_jsx(ThemeMoonIcon, {}), compact ? null : "Dark"] })] }) }));
|
|
4
4
|
}
|
|
5
5
|
function ThemeSunIcon() {
|
|
6
6
|
return (_jsxs("svg", { className: "vertebr-theme-icon", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("circle", { cx: "12", cy: "12", r: "4" }), _jsx("path", { d: "M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41" })] }));
|
|
@@ -11,6 +11,7 @@ export declare function IconChart(props: IconProps): import("react").JSX.Element
|
|
|
11
11
|
export declare function IconChevronLeft(props: IconProps): import("react").JSX.Element;
|
|
12
12
|
export declare function IconSearch(props: IconProps): import("react").JSX.Element;
|
|
13
13
|
export declare function IconSync(props: IconProps): import("react").JSX.Element;
|
|
14
|
+
export declare function IconMenu(props: IconProps): import("react").JSX.Element;
|
|
14
15
|
export declare function IconAddon(props: IconProps): import("react").JSX.Element;
|
|
15
16
|
export declare function iconForNavKey(key: string): typeof IconHome;
|
|
16
17
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../../src/components/ui/icons.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEtC,KAAK,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC;AAiBzC,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,+BAMxC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,+BAO5C;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,+BAQ3C;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,+BAOzC;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,+BAOxC;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,+BAOzC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,+BAO5C;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,+BAMzC;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,+BAM/C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,+BAO1C;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,+BASxC;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,+BASzC;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../../src/components/ui/icons.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEtC,KAAK,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC;AAiBzC,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,+BAMxC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,+BAO5C;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,+BAQ3C;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,+BAOzC;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,+BAOxC;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,+BAOzC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,+BAO5C;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,+BAMzC;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,+BAM/C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,+BAO1C;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,+BASxC;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,+BAQxC;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,+BASzC;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,mBAYxC"}
|
|
@@ -44,7 +44,10 @@ export function IconSearch(props) {
|
|
|
44
44
|
return (_jsxs("svg", { ...base(props), children: [_jsx("circle", { cx: "9", cy: "9", r: "4.75" }), _jsx("path", { d: "M13 13l3.5 3.5" })] }));
|
|
45
45
|
}
|
|
46
46
|
export function IconSync(props) {
|
|
47
|
-
return (_jsxs("svg", { ...base(props), children: [_jsx("path", { d: "
|
|
47
|
+
return (_jsxs("svg", { ...base(props), children: [_jsx("path", { d: "M14.5 7.2A6 6 0 0 0 5.2 8.5" }), _jsx("path", { d: "M5 5.5v3.2h3.2" }), _jsx("path", { d: "M5.5 12.8A6 6 0 0 0 14.8 11.5" }), _jsx("path", { d: "M15 14.5v-3.2h-3.2" })] }));
|
|
48
|
+
}
|
|
49
|
+
export function IconMenu(props) {
|
|
50
|
+
return (_jsxs("svg", { ...base(props), children: [_jsx("path", { d: "M4 6.5h12" }), _jsx("path", { d: "M4 10h12" }), _jsx("path", { d: "M4 13.5h12" })] }));
|
|
48
51
|
}
|
|
49
52
|
export function IconAddon(props) {
|
|
50
53
|
return (_jsxs("svg", { ...base(props), children: [_jsx("path", { d: "M8 3.5h4v4H8z" }), _jsx("path", { d: "M3.5 8h4v4h-4z" }), _jsx("path", { d: "M12.5 8h4v4h-4z" }), _jsx("path", { d: "M8 12.5h4v4H8z" })] }));
|
|
@@ -52,6 +55,8 @@ export function IconAddon(props) {
|
|
|
52
55
|
export function iconForNavKey(key) {
|
|
53
56
|
if (key === "overview")
|
|
54
57
|
return IconHome;
|
|
58
|
+
if (key === "audit")
|
|
59
|
+
return IconChart;
|
|
55
60
|
if (key.startsWith("resource:"))
|
|
56
61
|
return IconProducts;
|
|
57
62
|
if (key === "gallery")
|
package/dist/index.d.ts
CHANGED
|
@@ -29,5 +29,6 @@ export { createVertebrCatalog, catalogHref, catalogMatch, } from "@vertebr/clien
|
|
|
29
29
|
export type { VertebrCatalog, VertebrCatalogOptions, PublicResourceResponse, } from "@vertebr/client";
|
|
30
30
|
export { VertebrCatalogProvider, useVertebrCatalog, useVertebrCatalogItem, } from "@vertebr/client/react";
|
|
31
31
|
export type { VertebrCatalogProviderProps, VertebrCatalogState, } from "@vertebr/client/react";
|
|
32
|
-
export type { VertebrClient, VertebrClientOptions, VertebrMetricsOptions, VertebrReadOptions, AdminEnvironment, BootstrapResponse, CatalogResponse, CatalogResource, CatalogConfig, CatalogConfigSection, EnvironmentAuthPublic, FieldSchema, FieldType, GalleryItem, GalleryMeta, GalleryResponse, MailPreviewResponse, MailLibraryTemplate, MailHistoryEntry, MailProductOption, MailDiscountOption, EmailsBoardResponse, MetricCard, MetricChart, MetricsResponse, ResourceListResponse, ResourceActionMeta, ResourceUploadMeta, ResourceUploadResponse, ResourceBulkUploadResponse, ConfigResponse, VertebrControlsMap, } from "@vertebr/client";
|
|
32
|
+
export type { VertebrClient, VertebrClientOptions, VertebrMetricsOptions, VertebrReadOptions, AdminEnvironment, AuditEntry, AuditListResponse, BootstrapResponse, CatalogResponse, CatalogResource, CatalogConfig, CatalogConfigSection, EnvironmentAuthPublic, FieldSchema, FieldType, GalleryItem, GalleryMeta, GalleryResponse, HealthCheck, HealthResponse, Job, JobsResponse, MailPreviewResponse, MailLibraryTemplate, MailHistoryEntry, MailProductOption, MailDiscountOption, EmailsBoardResponse, MetricCard, MetricChart, MetricsResponse, ResourceListResponse, ResourceActionMeta, ResourceUploadMeta, ResourceUploadResponse, ResourceBulkUploadResponse, Revision, RevisionMeta, ConfigResponse, VertebrControlsMap, } from "@vertebr/client";
|
|
33
|
+
export { hasCap } from "./lib/capabilities";
|
|
33
34
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -16,3 +16,4 @@ export { createVertebrClient, VERTEBR_ENV_HEADER, renderMarkdown, isVertebrPrevi
|
|
|
16
16
|
export { VertebrMarkdown } from "@vertebr/client/react";
|
|
17
17
|
export { createVertebrCatalog, catalogHref, catalogMatch, } from "@vertebr/client";
|
|
18
18
|
export { VertebrCatalogProvider, useVertebrCatalog, useVertebrCatalogItem, } from "@vertebr/client/react";
|
|
19
|
+
export { hasCap } from "./lib/capabilities";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CatalogResponse } from "@vertebr/client";
|
|
2
|
+
/** True when the catalog grants `cap` (or `*`). Missing capabilities ⇒ allow. */
|
|
3
|
+
export declare function hasCap(catalog: CatalogResponse | null | undefined, cap: string): boolean;
|
|
4
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../src/lib/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,iFAAiF;AACjF,wBAAgB,MAAM,CACpB,OAAO,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,EAC3C,GAAG,EAAE,MAAM,GACV,OAAO,CAKT"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** True when the catalog grants `cap` (or `*`). Missing capabilities ⇒ allow. */
|
|
2
|
+
export function hasCap(catalog, cap) {
|
|
3
|
+
const caps = catalog?.capabilities;
|
|
4
|
+
if (!caps?.length)
|
|
5
|
+
return true;
|
|
6
|
+
if (caps.includes("*"))
|
|
7
|
+
return true;
|
|
8
|
+
return caps.includes(cap);
|
|
9
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/* ── Audit board ─────────────────────────────────────── */
|
|
2
|
+
|
|
3
|
+
.vertebr-audit {
|
|
4
|
+
flex: 1 1 auto;
|
|
5
|
+
min-height: 0;
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
gap: 0.75rem;
|
|
9
|
+
overflow: hidden;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.vertebr-audit-table td {
|
|
13
|
+
white-space: nowrap;
|
|
14
|
+
max-width: 22rem;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.vertebr-audit-when {
|
|
18
|
+
font-family: var(--vb-mono);
|
|
19
|
+
font-size: 0.78rem;
|
|
20
|
+
color: var(--vb-text-subtle);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.vertebr-audit-action {
|
|
24
|
+
font-family: var(--vb-mono);
|
|
25
|
+
font-size: 0.72rem;
|
|
26
|
+
padding: 0.15rem 0.4rem;
|
|
27
|
+
border-radius: 4px;
|
|
28
|
+
background: var(--vb-surface-tint);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.vertebr-audit-target {
|
|
32
|
+
font-size: 0.82rem;
|
|
33
|
+
color: var(--vb-text-subtle);
|
|
34
|
+
}
|