@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.
Files changed (66) hide show
  1. package/dist/components/admin/AddonEditor.d.ts +3 -2
  2. package/dist/components/admin/AddonEditor.d.ts.map +1 -1
  3. package/dist/components/admin/AddonEditor.js +4 -2
  4. package/dist/components/admin/AdminContent.d.ts +4 -1
  5. package/dist/components/admin/AdminContent.d.ts.map +1 -1
  6. package/dist/components/admin/AdminContent.js +25 -11
  7. package/dist/components/admin/AdminTopBar.d.ts +6 -2
  8. package/dist/components/admin/AdminTopBar.d.ts.map +1 -1
  9. package/dist/components/admin/AdminTopBar.js +27 -4
  10. package/dist/components/admin/AuditBoard.d.ts +7 -0
  11. package/dist/components/admin/AuditBoard.d.ts.map +1 -0
  12. package/dist/components/admin/AuditBoard.js +43 -0
  13. package/dist/components/admin/HealthModal.d.ts +9 -0
  14. package/dist/components/admin/HealthModal.d.ts.map +1 -0
  15. package/dist/components/admin/HealthModal.js +59 -0
  16. package/dist/components/admin/VertebrAdmin.d.ts.map +1 -1
  17. package/dist/components/admin/VertebrAdmin.js +88 -22
  18. package/dist/components/admin/adminSearch.d.ts.map +1 -1
  19. package/dist/components/admin/adminSearch.js +9 -0
  20. package/dist/components/admin/breadcrumbs.d.ts.map +1 -1
  21. package/dist/components/admin/breadcrumbs.js +2 -0
  22. package/dist/components/admin/routes.d.ts.map +1 -1
  23. package/dist/components/admin/routes.js +13 -1
  24. package/dist/components/admin/types.d.ts +2 -0
  25. package/dist/components/admin/types.d.ts.map +1 -1
  26. package/dist/components/config/ReferenceInput.d.ts +11 -0
  27. package/dist/components/config/ReferenceInput.d.ts.map +1 -0
  28. package/dist/components/config/ReferenceInput.js +99 -0
  29. package/dist/components/config/RevisionHistory.d.ts +8 -0
  30. package/dist/components/config/RevisionHistory.d.ts.map +1 -0
  31. package/dist/components/config/RevisionHistory.js +84 -0
  32. package/dist/components/config/form/ConfigField.d.ts +3 -2
  33. package/dist/components/config/form/ConfigField.d.ts.map +1 -1
  34. package/dist/components/config/form/ConfigField.js +3 -2
  35. package/dist/components/config/form/ConfigForm.d.ts +1 -1
  36. package/dist/components/config/form/ConfigForm.d.ts.map +1 -1
  37. package/dist/components/config/form/ConfigForm.js +13 -6
  38. package/dist/components/config/form/RecordConfigForm.d.ts +3 -2
  39. package/dist/components/config/form/RecordConfigForm.d.ts.map +1 -1
  40. package/dist/components/config/form/RecordConfigForm.js +2 -1
  41. package/dist/components/config/form/SettingsConfigForm.d.ts +3 -2
  42. package/dist/components/config/form/SettingsConfigForm.d.ts.map +1 -1
  43. package/dist/components/config/form/SettingsConfigForm.js +2 -2
  44. package/dist/components/config/form/types.d.ts +5 -1
  45. package/dist/components/config/form/types.d.ts.map +1 -1
  46. package/dist/components/resources/ResourceTable.d.ts +7 -1
  47. package/dist/components/resources/ResourceTable.d.ts.map +1 -1
  48. package/dist/components/resources/ResourceTable.js +56 -6
  49. package/dist/components/theme/ThemeToggle.d.ts +3 -1
  50. package/dist/components/theme/ThemeToggle.d.ts.map +1 -1
  51. package/dist/components/theme/ThemeToggle.js +2 -2
  52. package/dist/components/ui/icons.d.ts +1 -0
  53. package/dist/components/ui/icons.d.ts.map +1 -1
  54. package/dist/components/ui/icons.js +6 -1
  55. package/dist/index.d.ts +2 -1
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +1 -0
  58. package/dist/lib/capabilities.d.ts +4 -0
  59. package/dist/lib/capabilities.d.ts.map +1 -0
  60. package/dist/lib/capabilities.js +9 -0
  61. package/dist/styles/audit.css +34 -0
  62. package/dist/styles/form.css +143 -0
  63. package/dist/styles/index.css +1 -0
  64. package/dist/styles/modal.css +111 -0
  65. package/dist/styles/shell.css +234 -18
  66. 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: status ?? undefined,
69
- tone,
70
- onSave: () => void onSubmit(),
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
- void onSubmit();
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;AAYvE,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,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,QAAQ,EACR,OAAO,EACP,MAAM,EACN,IAAI,EACJ,SAAS,EACT,WAAW,EACX,WAAW,GACZ,EAAE,qBAAqB,+BAsJvB"}
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;AAIvE,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAEhF,MAAM,MAAM,uBAAuB,GAAG,eAAe,GACnD,mBAAmB,GAAG;IACtB,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,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,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,QAAQ,EACR,OAAO,EACP,MAAM,EACN,IAAI,EACJ,SAAS,EACT,WAAW,EACX,WAAW,GACZ,EAAE,uBAAuB,+BA8FzB"}
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,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErG,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;CACvB,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"}
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":"AASA,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAazB,KAAK,kBAAkB,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACjC,WAAW,CAAC,EAAE;QACZ,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC3B,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1C,aAAa,CAAC,EAAE,CACd,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACvD,kBAAkB,CAAC,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,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,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACpD,CAAC;AAuIF,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,KAAK,EACL,WAAW,EACX,OAAY,EACZ,KAAK,EACL,OAAO,EACP,SAA0C,EAC1C,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,iBAAsB,EACtB,kBAAkB,EAClB,QAAQ,EACR,aAAa,EACb,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,EAAE,kBAAkB,+BA25BpB;AAED,uCAAuC;AACvC,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;CAClC,+BAEA"}
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 recordsHead = (_jsxs("div", { className: "vertebr-panel-head", children: [_jsx("h2", { children: "Records" }), _jsxs("div", { className: "vertebr-panel-head-actions", children: [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: items.length })] })] }));
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;CACpC,CAAC;AAEF,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,gBAAgB,+BA+BhE"}
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,mBAWxC"}
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: "M4 7h8" }), _jsx("path", { d: "M10 5l2 2-2 2" }), _jsx("path", { d: "M16 13H8" }), _jsx("path", { d: "M10 11l-2 2 2 2" })] }));
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
@@ -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
+ }