@btst/plugin-cms 0.0.0-stage → 1.0.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 (204) hide show
  1. package/LICENSE.md +17 -0
  2. package/dist/api/getters.cjs +328 -0
  3. package/dist/api/getters.mjs +314 -0
  4. package/dist/api/index.cjs +29 -0
  5. package/dist/api/index.d.cts +209 -0
  6. package/dist/api/index.d.mts +209 -0
  7. package/dist/api/index.d.ts +209 -0
  8. package/dist/api/index.mjs +7 -0
  9. package/dist/api/lifecycle-migrations.cjs +13 -0
  10. package/dist/api/lifecycle-migrations.mjs +11 -0
  11. package/dist/api/mutations.cjs +59 -0
  12. package/dist/api/mutations.mjs +57 -0
  13. package/dist/api/operations.cjs +1769 -0
  14. package/dist/api/operations.mjs +1762 -0
  15. package/dist/api/plugin.cjs +337 -0
  16. package/dist/api/plugin.mjs +331 -0
  17. package/dist/api/query-key-defs.cjs +44 -0
  18. package/dist/api/query-key-defs.mjs +39 -0
  19. package/dist/api/relations.cjs +76 -0
  20. package/dist/api/relations.mjs +70 -0
  21. package/dist/client/components/forms/content-form.cjs +286 -0
  22. package/dist/client/components/forms/content-form.mjs +284 -0
  23. package/dist/client/components/forms/file-upload.cjs +160 -0
  24. package/dist/client/components/forms/file-upload.mjs +158 -0
  25. package/dist/client/components/forms/relation-field.cjs +237 -0
  26. package/dist/client/components/forms/relation-field.mjs +235 -0
  27. package/dist/client/components/index.cjs +14 -0
  28. package/dist/client/components/index.d.cts +20 -0
  29. package/dist/client/components/index.d.mts +20 -0
  30. package/dist/client/components/index.d.ts +20 -0
  31. package/dist/client/components/index.mjs +10 -0
  32. package/dist/client/components/inverse-relations-panel.cjs +272 -0
  33. package/dist/client/components/inverse-relations-panel.mjs +270 -0
  34. package/dist/client/components/loading/dashboard-skeleton.cjs +18 -0
  35. package/dist/client/components/loading/dashboard-skeleton.mjs +16 -0
  36. package/dist/client/components/loading/editor-skeleton.cjs +32 -0
  37. package/dist/client/components/loading/editor-skeleton.mjs +30 -0
  38. package/dist/client/components/loading/list-skeleton.cjs +32 -0
  39. package/dist/client/components/loading/list-skeleton.mjs +30 -0
  40. package/dist/client/components/pages/404-page.cjs +26 -0
  41. package/dist/client/components/pages/404-page.mjs +24 -0
  42. package/dist/client/components/pages/content-editor-page.cjs +84 -0
  43. package/dist/client/components/pages/content-editor-page.internal.cjs +170 -0
  44. package/dist/client/components/pages/content-editor-page.internal.mjs +168 -0
  45. package/dist/client/components/pages/content-editor-page.mjs +82 -0
  46. package/dist/client/components/pages/content-list-page.cjs +49 -0
  47. package/dist/client/components/pages/content-list-page.internal.cjs +334 -0
  48. package/dist/client/components/pages/content-list-page.internal.mjs +332 -0
  49. package/dist/client/components/pages/content-list-page.mjs +47 -0
  50. package/dist/client/components/pages/dashboard-page.cjs +42 -0
  51. package/dist/client/components/pages/dashboard-page.internal.cjs +102 -0
  52. package/dist/client/components/pages/dashboard-page.internal.mjs +100 -0
  53. package/dist/client/components/pages/dashboard-page.mjs +40 -0
  54. package/dist/client/components/shared/default-error.cjs +17 -0
  55. package/dist/client/components/shared/default-error.mjs +15 -0
  56. package/dist/client/components/shared/empty-state.cjs +16 -0
  57. package/dist/client/components/shared/empty-state.mjs +14 -0
  58. package/dist/client/components/shared/page-wrapper.cjs +29 -0
  59. package/dist/client/components/shared/page-wrapper.mjs +27 -0
  60. package/dist/client/constants.cjs +5 -0
  61. package/dist/client/constants.mjs +3 -0
  62. package/dist/client/hooks/cms-hooks.cjs +300 -0
  63. package/dist/client/hooks/cms-hooks.mjs +280 -0
  64. package/dist/client/hooks/cms-resource.cjs +13 -0
  65. package/dist/client/hooks/cms-resource.mjs +11 -0
  66. package/dist/client/hooks/index.cjs +25 -0
  67. package/dist/client/hooks/index.d.cts +693 -0
  68. package/dist/client/hooks/index.d.mts +693 -0
  69. package/dist/client/hooks/index.d.ts +693 -0
  70. package/dist/client/hooks/index.mjs +1 -0
  71. package/dist/client/index.cjs +15 -0
  72. package/dist/client/index.d.cts +654 -0
  73. package/dist/client/index.d.mts +654 -0
  74. package/dist/client/index.d.ts +654 -0
  75. package/dist/client/index.mjs +3 -0
  76. package/dist/client/overrides.cjs +26 -0
  77. package/dist/client/overrides.mjs +24 -0
  78. package/dist/client/plugin.cjs +316 -0
  79. package/dist/client/plugin.mjs +314 -0
  80. package/dist/client.css +3 -0
  81. package/dist/db.cjs +118 -0
  82. package/dist/db.mjs +116 -0
  83. package/dist/permissions.cjs +46 -0
  84. package/dist/permissions.d.cts +42 -0
  85. package/dist/permissions.d.mts +42 -0
  86. package/dist/permissions.d.ts +42 -0
  87. package/dist/permissions.mjs +44 -0
  88. package/dist/query-keys.cjs +229 -0
  89. package/dist/query-keys.d.cts +8 -0
  90. package/dist/query-keys.d.mts +8 -0
  91. package/dist/query-keys.d.ts +8 -0
  92. package/dist/query-keys.mjs +225 -0
  93. package/dist/schemas.cjs +81 -0
  94. package/dist/schemas.mjs +72 -0
  95. package/dist/shared/plugin-cms.BBshPRkb.d.cts +6 -0
  96. package/dist/shared/plugin-cms.BBshPRkb.d.mts +6 -0
  97. package/dist/shared/plugin-cms.BBshPRkb.d.ts +6 -0
  98. package/dist/shared/plugin-cms.DQLAoogy.d.ts +1749 -0
  99. package/dist/shared/plugin-cms.W4Le8D91.d.mts +1749 -0
  100. package/dist/shared/plugin-cms.c-GeWvTf.d.cts +1749 -0
  101. package/dist/style.css +6 -0
  102. package/dist/types.cjs +2 -0
  103. package/dist/types.d.cts +406 -0
  104. package/dist/types.d.mts +406 -0
  105. package/dist/types.d.ts +406 -0
  106. package/dist/types.mjs +1 -0
  107. package/dist/ui/src/components/accordion.cjs +81 -0
  108. package/dist/ui/src/components/accordion.mjs +62 -0
  109. package/dist/ui/src/components/alert-dialog.cjs +157 -0
  110. package/dist/ui/src/components/alert-dialog.mjs +132 -0
  111. package/dist/ui/src/components/auto-form/common/label.cjs +18 -0
  112. package/dist/ui/src/components/auto-form/common/label.mjs +16 -0
  113. package/dist/ui/src/components/auto-form/common/tooltip.cjs +9 -0
  114. package/dist/ui/src/components/auto-form/common/tooltip.mjs +7 -0
  115. package/dist/ui/src/components/auto-form/config.cjs +40 -0
  116. package/dist/ui/src/components/auto-form/config.mjs +37 -0
  117. package/dist/ui/src/components/auto-form/dependencies.cjs +48 -0
  118. package/dist/ui/src/components/auto-form/dependencies.mjs +46 -0
  119. package/dist/ui/src/components/auto-form/fields/array.cjs +266 -0
  120. package/dist/ui/src/components/auto-form/fields/array.mjs +264 -0
  121. package/dist/ui/src/components/auto-form/fields/checkbox.cjs +38 -0
  122. package/dist/ui/src/components/auto-form/fields/checkbox.mjs +36 -0
  123. package/dist/ui/src/components/auto-form/fields/date.cjs +67 -0
  124. package/dist/ui/src/components/auto-form/fields/date.mjs +65 -0
  125. package/dist/ui/src/components/auto-form/fields/enum.cjs +73 -0
  126. package/dist/ui/src/components/auto-form/fields/enum.mjs +71 -0
  127. package/dist/ui/src/components/auto-form/fields/input.cjs +32 -0
  128. package/dist/ui/src/components/auto-form/fields/input.mjs +30 -0
  129. package/dist/ui/src/components/auto-form/fields/number.cjs +31 -0
  130. package/dist/ui/src/components/auto-form/fields/number.mjs +29 -0
  131. package/dist/ui/src/components/auto-form/fields/object.cjs +233 -0
  132. package/dist/ui/src/components/auto-form/fields/object.mjs +217 -0
  133. package/dist/ui/src/components/auto-form/fields/radio-group.cjs +67 -0
  134. package/dist/ui/src/components/auto-form/fields/radio-group.mjs +65 -0
  135. package/dist/ui/src/components/auto-form/fields/switch.cjs +38 -0
  136. package/dist/ui/src/components/auto-form/fields/switch.mjs +36 -0
  137. package/dist/ui/src/components/auto-form/fields/textarea.cjs +31 -0
  138. package/dist/ui/src/components/auto-form/fields/textarea.mjs +29 -0
  139. package/dist/ui/src/components/auto-form/helpers.cjs +270 -0
  140. package/dist/ui/src/components/auto-form/helpers.mjs +259 -0
  141. package/dist/ui/src/components/auto-form/index.cjs +92 -0
  142. package/dist/ui/src/components/auto-form/index.mjs +86 -0
  143. package/dist/ui/src/components/auto-form/stepped-auto-form.cjs +374 -0
  144. package/dist/ui/src/components/auto-form/stepped-auto-form.mjs +368 -0
  145. package/dist/ui/src/components/auto-form/types.cjs +11 -0
  146. package/dist/ui/src/components/auto-form/types.mjs +9 -0
  147. package/dist/ui/src/components/badge.cjs +42 -0
  148. package/dist/ui/src/components/badge.mjs +39 -0
  149. package/dist/ui/src/components/button.cjs +56 -0
  150. package/dist/ui/src/components/button.mjs +53 -0
  151. package/dist/ui/src/components/calendar.cjs +207 -0
  152. package/dist/ui/src/components/calendar.mjs +190 -0
  153. package/dist/ui/src/components/card.cjs +56 -0
  154. package/dist/ui/src/components/card.mjs +51 -0
  155. package/dist/ui/src/components/checkbox.cjs +48 -0
  156. package/dist/ui/src/components/checkbox.mjs +32 -0
  157. package/dist/ui/src/components/command.cjs +78 -0
  158. package/dist/ui/src/components/command.mjs +73 -0
  159. package/dist/ui/src/components/date-picker.cjs +41 -0
  160. package/dist/ui/src/components/date-picker.mjs +39 -0
  161. package/dist/ui/src/components/dialog.cjs +119 -0
  162. package/dist/ui/src/components/dialog.mjs +97 -0
  163. package/dist/ui/src/components/form.cjs +120 -0
  164. package/dist/ui/src/components/form.mjs +98 -0
  165. package/dist/ui/src/components/input.cjs +23 -0
  166. package/dist/ui/src/components/input.mjs +21 -0
  167. package/dist/ui/src/components/label.cjs +39 -0
  168. package/dist/ui/src/components/label.mjs +23 -0
  169. package/dist/ui/src/components/multi-select.cjs +555 -0
  170. package/dist/ui/src/components/multi-select.mjs +540 -0
  171. package/dist/ui/src/components/page-layout.cjs +25 -0
  172. package/dist/ui/src/components/page-layout.mjs +23 -0
  173. package/dist/ui/src/components/page-wrapper.cjs +20 -0
  174. package/dist/ui/src/components/page-wrapper.mjs +18 -0
  175. package/dist/ui/src/components/popover.cjs +60 -0
  176. package/dist/ui/src/components/popover.mjs +42 -0
  177. package/dist/ui/src/components/radio-group.cjs +62 -0
  178. package/dist/ui/src/components/radio-group.mjs +45 -0
  179. package/dist/ui/src/components/select.cjs +161 -0
  180. package/dist/ui/src/components/select.mjs +139 -0
  181. package/dist/ui/src/components/separator.cjs +43 -0
  182. package/dist/ui/src/components/separator.mjs +27 -0
  183. package/dist/ui/src/components/skeleton.cjs +17 -0
  184. package/dist/ui/src/components/skeleton.mjs +15 -0
  185. package/dist/ui/src/components/stack-attribution.cjs +24 -0
  186. package/dist/ui/src/components/stack-attribution.mjs +22 -0
  187. package/dist/ui/src/components/switch.cjs +48 -0
  188. package/dist/ui/src/components/switch.mjs +32 -0
  189. package/dist/ui/src/components/table.cjs +89 -0
  190. package/dist/ui/src/components/table.mjs +82 -0
  191. package/dist/ui/src/components/textarea.cjs +20 -0
  192. package/dist/ui/src/components/textarea.mjs +18 -0
  193. package/dist/ui/src/hooks/use-debounce.cjs +16 -0
  194. package/dist/ui/src/hooks/use-debounce.mjs +14 -0
  195. package/dist/ui/src/hooks/use-route-lifecycle.cjs +31 -0
  196. package/dist/ui/src/hooks/use-route-lifecycle.mjs +29 -0
  197. package/dist/ui/src/lib/schema-converter.cjs +133 -0
  198. package/dist/ui/src/lib/schema-converter.mjs +127 -0
  199. package/dist/ui/src/lib/utils.cjs +10 -0
  200. package/dist/ui/src/lib/utils.mjs +8 -0
  201. package/dist/utils.cjs +19 -0
  202. package/dist/utils.mjs +12 -0
  203. package/package.json +170 -3
  204. package/README.md +0 -3
@@ -0,0 +1,30 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import { Skeleton } from '../../../ui/src/components/skeleton.mjs';
4
+ import { PageWrapper } from '../shared/page-wrapper.mjs';
5
+
6
+ function ListSkeleton() {
7
+ return /* @__PURE__ */ jsx(PageWrapper, { testId: "cms-list-skeleton", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-5xl space-y-6", children: [
8
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
9
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
10
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-48" }),
11
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" })
12
+ ] }),
13
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-28" })
14
+ ] }),
15
+ /* @__PURE__ */ jsxs("div", { className: "border rounded-lg", children: [
16
+ /* @__PURE__ */ jsx("div", { className: "border-b px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
17
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" }),
18
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" }),
19
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" })
20
+ ] }) }),
21
+ Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsx("div", { className: "px-4 py-3 border-b last:border-b-0", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
22
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" }),
23
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" }),
24
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" })
25
+ ] }) }, i))
26
+ ] })
27
+ ] }) });
28
+ }
29
+
30
+ export { ListSkeleton };
@@ -0,0 +1,26 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ const jsxRuntime = require('react/jsx-runtime');
5
+ const button = require('../../../ui/src/components/button.cjs');
6
+ const context = require('@btst/stack/context');
7
+ const constants = require('../../constants.cjs');
8
+
9
+ function NotFoundPage() {
10
+ const t = context.useTranslate();
11
+ const { localization } = context.usePluginOverrides(constants.CMS_PLUGIN_ID);
12
+ const { router, plugins, basePath: stackBasePath } = context.useStack();
13
+ const basePath = plugins?.[constants.CMS_PLUGIN_ID]?.site.basePath ?? stackBasePath;
14
+ const LinkComponent = router?.Link ?? "a";
15
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12 px-4 text-center", children: [
16
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-6xl font-bold text-muted-foreground mb-4", children: "404" }),
17
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-medium text-foreground mb-2", children: localization?.CMS_404_TITLE ?? t("cms.common.404Title", "Page not found") }),
18
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mb-6 max-w-sm", children: localization?.CMS_404_DESCRIPTION ?? t(
19
+ "cms.common.404Description",
20
+ "The page you're looking for doesn't exist or has been moved."
21
+ ) }),
22
+ /* @__PURE__ */ jsxRuntime.jsx(button.Button, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(LinkComponent, { href: context.joinBasePath(basePath, "/cms"), children: localization?.CMS_404_BACK ?? t("cms.common.404Back", "Back to CMS") }) })
23
+ ] });
24
+ }
25
+
26
+ exports.NotFoundPage = NotFoundPage;
@@ -0,0 +1,24 @@
1
+ 'use client';
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { Button } from '../../../ui/src/components/button.mjs';
4
+ import { useTranslate, usePluginOverrides, useStack, joinBasePath } from '@btst/stack/context';
5
+ import { CMS_PLUGIN_ID } from '../../constants.mjs';
6
+
7
+ function NotFoundPage() {
8
+ const t = useTranslate();
9
+ const { localization } = usePluginOverrides(CMS_PLUGIN_ID);
10
+ const { router, plugins, basePath: stackBasePath } = useStack();
11
+ const basePath = plugins?.[CMS_PLUGIN_ID]?.site.basePath ?? stackBasePath;
12
+ const LinkComponent = router?.Link ?? "a";
13
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-12 px-4 text-center", children: [
14
+ /* @__PURE__ */ jsx("h1", { className: "text-6xl font-bold text-muted-foreground mb-4", children: "404" }),
15
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-medium text-foreground mb-2", children: localization?.CMS_404_TITLE ?? t("cms.common.404Title", "Page not found") }),
16
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-6 max-w-sm", children: localization?.CMS_404_DESCRIPTION ?? t(
17
+ "cms.common.404Description",
18
+ "The page you're looking for doesn't exist or has been moved."
19
+ ) }),
20
+ /* @__PURE__ */ jsx(Button, { asChild: true, children: /* @__PURE__ */ jsx(LinkComponent, { href: joinBasePath(basePath, "/cms"), children: localization?.CMS_404_BACK ?? t("cms.common.404Back", "Back to CMS") }) })
21
+ ] });
22
+ }
23
+
24
+ export { NotFoundPage };
@@ -0,0 +1,84 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ const jsxRuntime = require('react/jsx-runtime');
5
+ const React = require('react');
6
+ const context = require('@btst/stack/context');
7
+ const constants = require('../../constants.cjs');
8
+ const components = require('@btst/stack/client/components');
9
+ const defaultError = require('../shared/default-error.cjs');
10
+ const _404Page = require('./404-page.cjs');
11
+ const permissions = require('../../../permissions.cjs');
12
+ const editorSkeleton = require('../loading/editor-skeleton.cjs');
13
+ const cmsHooks = require('../../hooks/cms-hooks.cjs');
14
+
15
+ const ContentEditorPageInternal = React.lazy(
16
+ () => import('./content-editor-page.internal.cjs').then((m) => ({
17
+ default: m.ContentEditorPage
18
+ }))
19
+ );
20
+ function ContentEditorPageComponent({
21
+ typeSlug,
22
+ id
23
+ }) {
24
+ const { onRouteError } = context.usePluginOverrides(constants.CMS_PLUGIN_ID);
25
+ const isNew = !id;
26
+ const path = isNew ? `/cms/${typeSlug}/new` : `/cms/${typeSlug}/${id}`;
27
+ return /* @__PURE__ */ jsxRuntime.jsx(
28
+ components.ComposedRoute,
29
+ {
30
+ path,
31
+ PageComponent: AuthorizedContentEditorPage,
32
+ ErrorComponent: defaultError.DefaultError,
33
+ LoadingComponent: editorSkeleton.EditorSkeleton,
34
+ NotFoundComponent: _404Page.NotFoundPage,
35
+ props: { typeSlug, id },
36
+ onError: (error) => {
37
+ if (onRouteError) {
38
+ onRouteError("contentEditor", error, {
39
+ path,
40
+ params: { typeSlug, id: id ?? "" },
41
+ isSSR: typeof window === "undefined"
42
+ });
43
+ }
44
+ }
45
+ }
46
+ );
47
+ }
48
+ function AuthorizedContentEditorPage({
49
+ typeSlug,
50
+ id
51
+ }) {
52
+ if (!id) {
53
+ return /* @__PURE__ */ jsxRuntime.jsx(
54
+ components.PermissionRouteAccess,
55
+ {
56
+ permission: permissions.cmsPermissions.record.create({ contentType: typeSlug }),
57
+ LoadingComponent: editorSkeleton.EditorSkeleton,
58
+ children: /* @__PURE__ */ jsxRuntime.jsx(ContentEditorPageInternal, { typeSlug })
59
+ }
60
+ );
61
+ }
62
+ return /* @__PURE__ */ jsxRuntime.jsx(AuthorizedExistingContentEditorPage, { typeSlug, id });
63
+ }
64
+ function AuthorizedExistingContentEditorPage({
65
+ typeSlug,
66
+ id
67
+ }) {
68
+ const { item } = cmsHooks.useSuspenseContentItem(typeSlug, id);
69
+ if (!item) return /* @__PURE__ */ jsxRuntime.jsx(ContentEditorPageInternal, { typeSlug, id });
70
+ return /* @__PURE__ */ jsxRuntime.jsx(
71
+ components.PermissionRouteAccess,
72
+ {
73
+ permission: permissions.cmsPermissions.record.update({
74
+ contentType: item.contentType?.slug ?? typeSlug,
75
+ recordId: item.id,
76
+ ...item.authorId ? { authorId: item.authorId } : {}
77
+ }),
78
+ LoadingComponent: editorSkeleton.EditorSkeleton,
79
+ children: /* @__PURE__ */ jsxRuntime.jsx(ContentEditorPageInternal, { typeSlug, id })
80
+ }
81
+ );
82
+ }
83
+
84
+ exports.ContentEditorPageComponent = ContentEditorPageComponent;
@@ -0,0 +1,170 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ const jsxRuntime = require('react/jsx-runtime');
5
+ const React = require('react');
6
+ const lucideReact = require('lucide-react');
7
+ const button = require('../../../ui/src/components/button.cjs');
8
+ const context = require('@btst/stack/context');
9
+ const overrides = require('../../overrides.cjs');
10
+ const constants = require('../../constants.cjs');
11
+ const contentForm = require('../forms/content-form.cjs');
12
+ const inverseRelationsPanel = require('../inverse-relations-panel.cjs');
13
+ const emptyState = require('../shared/empty-state.cjs');
14
+ const pageWrapper = require('../shared/page-wrapper.cjs');
15
+ const editorSkeleton = require('../loading/editor-skeleton.cjs');
16
+ const useRouteLifecycle = require('../../../ui/src/hooks/use-route-lifecycle.cjs');
17
+ const cmsHooks = require('../../hooks/cms-hooks.cjs');
18
+
19
+ function usePrefillParams() {
20
+ const [prefillData, setPrefillData] = React.useState({});
21
+ React.useEffect(() => {
22
+ if (typeof window === "undefined") {
23
+ return;
24
+ }
25
+ const parseAndSetPrefillData = () => {
26
+ const params = new URLSearchParams(window.location.search);
27
+ const data = {};
28
+ for (const [key, value] of params.entries()) {
29
+ if (key.startsWith("prefill_")) {
30
+ const fieldName = key.slice("prefill_".length);
31
+ if (fieldName) {
32
+ data[fieldName] = value;
33
+ }
34
+ }
35
+ }
36
+ setPrefillData(data);
37
+ };
38
+ parseAndSetPrefillData();
39
+ window.addEventListener("popstate", parseAndSetPrefillData);
40
+ return () => {
41
+ window.removeEventListener("popstate", parseAndSetPrefillData);
42
+ };
43
+ }, []);
44
+ return prefillData;
45
+ }
46
+ function convertPrefillToFormData(prefillParams, jsonSchema) {
47
+ const properties = jsonSchema.properties;
48
+ if (!properties) {
49
+ return prefillParams;
50
+ }
51
+ const result = {};
52
+ for (const [fieldName, value] of Object.entries(prefillParams)) {
53
+ const fieldSchema = properties[fieldName];
54
+ if (fieldSchema?.fieldType === "relation" && fieldSchema.relation) {
55
+ if (fieldSchema.relation.type === "belongsTo") {
56
+ result[fieldName] = { id: value };
57
+ } else {
58
+ result[fieldName] = [{ id: value }];
59
+ }
60
+ } else {
61
+ result[fieldName] = value;
62
+ }
63
+ }
64
+ return result;
65
+ }
66
+ function ContentEditorPage({ typeSlug, id }) {
67
+ const t = context.useTranslate();
68
+ const overrides$1 = context.usePluginOverrides(constants.CMS_PLUGIN_ID);
69
+ const { localization } = overrides$1;
70
+ const { router, plugins, basePath: stackBasePath } = context.useStack();
71
+ const navigate = router?.navigate;
72
+ const basePath = plugins?.[constants.CMS_PLUGIN_ID]?.site.basePath ?? stackBasePath;
73
+ const prefillParams = usePrefillParams();
74
+ useRouteLifecycle.useRouteLifecycle({
75
+ routeName: "contentEditor",
76
+ context: {
77
+ path: id ? `/cms/${typeSlug}/${id}` : `/cms/${typeSlug}/new`,
78
+ params: id ? { typeSlug, id } : { typeSlug },
79
+ isSSR: typeof window === "undefined"
80
+ },
81
+ overrides: overrides$1
82
+ });
83
+ const { contentTypes: serverContentTypes } = cmsHooks.useSuspenseContentTypes();
84
+ const contentTypes = overrides.orderCMSContentTypes(
85
+ serverContentTypes,
86
+ plugins?.[constants.CMS_PLUGIN_ID]?.config
87
+ );
88
+ const contentType = contentTypes.find((ct) => ct.slug === typeSlug);
89
+ const isEditing = !!id;
90
+ const { item, isLoading: isLoadingItem } = cmsHooks.useContentItem(typeSlug, id ?? "");
91
+ const resourceForm = cmsHooks.useContentItemForm({
92
+ action: isEditing ? "edit" : "create",
93
+ record: isEditing ? item : null,
94
+ successMessage: (_result, action) => action === "create" ? localization?.CMS_TOAST_CREATE_SUCCESS ?? t("cms.toasts.createSuccess", "Item created successfully") : localization?.CMS_TOAST_UPDATE_SUCCESS ?? t("cms.toasts.updateSuccess", "Item updated successfully"),
95
+ toCreateVars: (values) => ({
96
+ typeSlug,
97
+ slug: values.slug,
98
+ data: values.data
99
+ }),
100
+ toUpdateVars: (values) => ({
101
+ typeSlug,
102
+ id: id ?? "",
103
+ data: { slug: values.slug, data: values.data }
104
+ }),
105
+ onSuccess: () => {
106
+ void navigate?.(context.joinBasePath(basePath, `/cms/${typeSlug}`));
107
+ }
108
+ });
109
+ if (!contentType) {
110
+ return /* @__PURE__ */ jsxRuntime.jsx(pageWrapper.PageWrapper, { testId: "cms-editor-page", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsxRuntime.jsx(
111
+ emptyState.EmptyState,
112
+ {
113
+ title: localization?.CMS_ERROR_NOT_FOUND ?? t("cms.common.notFound", "Not found"),
114
+ description: localization?.CMS_ERROR_TYPE_NOT_FOUND_DESCRIPTION ?? t("cms.common.typeNotFoundDescription", "Content type not found")
115
+ }
116
+ ) }) });
117
+ }
118
+ if (isEditing && isLoadingItem) {
119
+ return /* @__PURE__ */ jsxRuntime.jsx(pageWrapper.PageWrapper, { testId: "cms-editor-page", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsxRuntime.jsx(editorSkeleton.EditorSkeleton, {}) }) });
120
+ }
121
+ if (isEditing && !item) {
122
+ return /* @__PURE__ */ jsxRuntime.jsx(pageWrapper.PageWrapper, { testId: "cms-editor-page", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsxRuntime.jsx(
123
+ emptyState.EmptyState,
124
+ {
125
+ title: localization?.CMS_ERROR_NOT_FOUND ?? t("cms.common.notFound", "Not found"),
126
+ description: localization?.CMS_ERROR_ITEM_NOT_FOUND_DESCRIPTION ?? t("cms.common.itemNotFoundDescription", "Content item not found")
127
+ }
128
+ ) }) });
129
+ }
130
+ const handleSubmit = async (data) => {
131
+ await resourceForm.submit(data);
132
+ };
133
+ const hasFieldErrors = Object.keys(resourceForm.fieldErrors).length > 0;
134
+ const title = isEditing ? (localization?.CMS_EDITOR_TITLE_EDIT ?? t("cms.editor.titleEdit", "Edit {typeName}")).replace("{typeName}", contentType.name) : (localization?.CMS_EDITOR_TITLE_NEW ?? t("cms.editor.titleNew", "New {typeName}")).replace("{typeName}", contentType.name);
135
+ return /* @__PURE__ */ jsxRuntime.jsx(pageWrapper.PageWrapper, { testId: "cms-editor-page", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-2xl space-y-6", children: [
136
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
137
+ /* @__PURE__ */ jsxRuntime.jsx(
138
+ button.Button,
139
+ {
140
+ variant: "ghost",
141
+ size: "icon",
142
+ onClick: () => void navigate?.(context.joinBasePath(basePath, `/cms/${typeSlug}`)),
143
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "h-4 w-4" })
144
+ }
145
+ ),
146
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-bold tracking-tight", children: title })
147
+ ] }),
148
+ /* @__PURE__ */ jsxRuntime.jsx(
149
+ contentForm.ContentForm,
150
+ {
151
+ contentType,
152
+ initialData: isEditing ? item?.parsedData ?? void 0 : Object.keys(prefillParams).length > 0 ? convertPrefillToFormData(
153
+ prefillParams,
154
+ JSON.parse(contentType.jsonSchema)
155
+ ) : void 0,
156
+ initialSlug: item?.slug,
157
+ isEditing,
158
+ onSubmit: handleSubmit,
159
+ onCancel: () => void navigate?.(context.joinBasePath(basePath, `/cms/${typeSlug}`)),
160
+ fieldErrors: resourceForm.fieldErrors,
161
+ errorMessage: hasFieldErrors ? void 0 : resourceForm.error?.message,
162
+ isSubmitting: resourceForm.isSubmitting
163
+ },
164
+ isEditing ? `edit-${id}` : "create"
165
+ ),
166
+ isEditing && id && /* @__PURE__ */ jsxRuntime.jsx(inverseRelationsPanel.InverseRelationsPanel, { contentTypeSlug: typeSlug, itemId: id })
167
+ ] }) });
168
+ }
169
+
170
+ exports.ContentEditorPage = ContentEditorPage;
@@ -0,0 +1,168 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import { useState, useEffect } from 'react';
4
+ import { ArrowLeft } from 'lucide-react';
5
+ import { Button } from '../../../ui/src/components/button.mjs';
6
+ import { useTranslate, usePluginOverrides, useStack, joinBasePath } from '@btst/stack/context';
7
+ import { orderCMSContentTypes } from '../../overrides.mjs';
8
+ import { CMS_PLUGIN_ID } from '../../constants.mjs';
9
+ import { ContentForm } from '../forms/content-form.mjs';
10
+ import { InverseRelationsPanel } from '../inverse-relations-panel.mjs';
11
+ import { EmptyState } from '../shared/empty-state.mjs';
12
+ import { PageWrapper } from '../shared/page-wrapper.mjs';
13
+ import { EditorSkeleton } from '../loading/editor-skeleton.mjs';
14
+ import { useRouteLifecycle } from '../../../ui/src/hooks/use-route-lifecycle.mjs';
15
+ import { useSuspenseContentTypes, useContentItem, useContentItemForm } from '../../hooks/cms-hooks.mjs';
16
+
17
+ function usePrefillParams() {
18
+ const [prefillData, setPrefillData] = useState({});
19
+ useEffect(() => {
20
+ if (typeof window === "undefined") {
21
+ return;
22
+ }
23
+ const parseAndSetPrefillData = () => {
24
+ const params = new URLSearchParams(window.location.search);
25
+ const data = {};
26
+ for (const [key, value] of params.entries()) {
27
+ if (key.startsWith("prefill_")) {
28
+ const fieldName = key.slice("prefill_".length);
29
+ if (fieldName) {
30
+ data[fieldName] = value;
31
+ }
32
+ }
33
+ }
34
+ setPrefillData(data);
35
+ };
36
+ parseAndSetPrefillData();
37
+ window.addEventListener("popstate", parseAndSetPrefillData);
38
+ return () => {
39
+ window.removeEventListener("popstate", parseAndSetPrefillData);
40
+ };
41
+ }, []);
42
+ return prefillData;
43
+ }
44
+ function convertPrefillToFormData(prefillParams, jsonSchema) {
45
+ const properties = jsonSchema.properties;
46
+ if (!properties) {
47
+ return prefillParams;
48
+ }
49
+ const result = {};
50
+ for (const [fieldName, value] of Object.entries(prefillParams)) {
51
+ const fieldSchema = properties[fieldName];
52
+ if (fieldSchema?.fieldType === "relation" && fieldSchema.relation) {
53
+ if (fieldSchema.relation.type === "belongsTo") {
54
+ result[fieldName] = { id: value };
55
+ } else {
56
+ result[fieldName] = [{ id: value }];
57
+ }
58
+ } else {
59
+ result[fieldName] = value;
60
+ }
61
+ }
62
+ return result;
63
+ }
64
+ function ContentEditorPage({ typeSlug, id }) {
65
+ const t = useTranslate();
66
+ const overrides = usePluginOverrides(CMS_PLUGIN_ID);
67
+ const { localization } = overrides;
68
+ const { router, plugins, basePath: stackBasePath } = useStack();
69
+ const navigate = router?.navigate;
70
+ const basePath = plugins?.[CMS_PLUGIN_ID]?.site.basePath ?? stackBasePath;
71
+ const prefillParams = usePrefillParams();
72
+ useRouteLifecycle({
73
+ routeName: "contentEditor",
74
+ context: {
75
+ path: id ? `/cms/${typeSlug}/${id}` : `/cms/${typeSlug}/new`,
76
+ params: id ? { typeSlug, id } : { typeSlug },
77
+ isSSR: typeof window === "undefined"
78
+ },
79
+ overrides
80
+ });
81
+ const { contentTypes: serverContentTypes } = useSuspenseContentTypes();
82
+ const contentTypes = orderCMSContentTypes(
83
+ serverContentTypes,
84
+ plugins?.[CMS_PLUGIN_ID]?.config
85
+ );
86
+ const contentType = contentTypes.find((ct) => ct.slug === typeSlug);
87
+ const isEditing = !!id;
88
+ const { item, isLoading: isLoadingItem } = useContentItem(typeSlug, id ?? "");
89
+ const resourceForm = useContentItemForm({
90
+ action: isEditing ? "edit" : "create",
91
+ record: isEditing ? item : null,
92
+ successMessage: (_result, action) => action === "create" ? localization?.CMS_TOAST_CREATE_SUCCESS ?? t("cms.toasts.createSuccess", "Item created successfully") : localization?.CMS_TOAST_UPDATE_SUCCESS ?? t("cms.toasts.updateSuccess", "Item updated successfully"),
93
+ toCreateVars: (values) => ({
94
+ typeSlug,
95
+ slug: values.slug,
96
+ data: values.data
97
+ }),
98
+ toUpdateVars: (values) => ({
99
+ typeSlug,
100
+ id: id ?? "",
101
+ data: { slug: values.slug, data: values.data }
102
+ }),
103
+ onSuccess: () => {
104
+ void navigate?.(joinBasePath(basePath, `/cms/${typeSlug}`));
105
+ }
106
+ });
107
+ if (!contentType) {
108
+ return /* @__PURE__ */ jsx(PageWrapper, { testId: "cms-editor-page", children: /* @__PURE__ */ jsx("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsx(
109
+ EmptyState,
110
+ {
111
+ title: localization?.CMS_ERROR_NOT_FOUND ?? t("cms.common.notFound", "Not found"),
112
+ description: localization?.CMS_ERROR_TYPE_NOT_FOUND_DESCRIPTION ?? t("cms.common.typeNotFoundDescription", "Content type not found")
113
+ }
114
+ ) }) });
115
+ }
116
+ if (isEditing && isLoadingItem) {
117
+ return /* @__PURE__ */ jsx(PageWrapper, { testId: "cms-editor-page", children: /* @__PURE__ */ jsx("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsx(EditorSkeleton, {}) }) });
118
+ }
119
+ if (isEditing && !item) {
120
+ return /* @__PURE__ */ jsx(PageWrapper, { testId: "cms-editor-page", children: /* @__PURE__ */ jsx("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsx(
121
+ EmptyState,
122
+ {
123
+ title: localization?.CMS_ERROR_NOT_FOUND ?? t("cms.common.notFound", "Not found"),
124
+ description: localization?.CMS_ERROR_ITEM_NOT_FOUND_DESCRIPTION ?? t("cms.common.itemNotFoundDescription", "Content item not found")
125
+ }
126
+ ) }) });
127
+ }
128
+ const handleSubmit = async (data) => {
129
+ await resourceForm.submit(data);
130
+ };
131
+ const hasFieldErrors = Object.keys(resourceForm.fieldErrors).length > 0;
132
+ const title = isEditing ? (localization?.CMS_EDITOR_TITLE_EDIT ?? t("cms.editor.titleEdit", "Edit {typeName}")).replace("{typeName}", contentType.name) : (localization?.CMS_EDITOR_TITLE_NEW ?? t("cms.editor.titleNew", "New {typeName}")).replace("{typeName}", contentType.name);
133
+ return /* @__PURE__ */ jsx(PageWrapper, { testId: "cms-editor-page", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-2xl space-y-6", children: [
134
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
135
+ /* @__PURE__ */ jsx(
136
+ Button,
137
+ {
138
+ variant: "ghost",
139
+ size: "icon",
140
+ onClick: () => void navigate?.(joinBasePath(basePath, `/cms/${typeSlug}`)),
141
+ children: /* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" })
142
+ }
143
+ ),
144
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold tracking-tight", children: title })
145
+ ] }),
146
+ /* @__PURE__ */ jsx(
147
+ ContentForm,
148
+ {
149
+ contentType,
150
+ initialData: isEditing ? item?.parsedData ?? void 0 : Object.keys(prefillParams).length > 0 ? convertPrefillToFormData(
151
+ prefillParams,
152
+ JSON.parse(contentType.jsonSchema)
153
+ ) : void 0,
154
+ initialSlug: item?.slug,
155
+ isEditing,
156
+ onSubmit: handleSubmit,
157
+ onCancel: () => void navigate?.(joinBasePath(basePath, `/cms/${typeSlug}`)),
158
+ fieldErrors: resourceForm.fieldErrors,
159
+ errorMessage: hasFieldErrors ? void 0 : resourceForm.error?.message,
160
+ isSubmitting: resourceForm.isSubmitting
161
+ },
162
+ isEditing ? `edit-${id}` : "create"
163
+ ),
164
+ isEditing && id && /* @__PURE__ */ jsx(InverseRelationsPanel, { contentTypeSlug: typeSlug, itemId: id })
165
+ ] }) });
166
+ }
167
+
168
+ export { ContentEditorPage };
@@ -0,0 +1,82 @@
1
+ 'use client';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { lazy } from 'react';
4
+ import { usePluginOverrides } from '@btst/stack/context';
5
+ import { CMS_PLUGIN_ID } from '../../constants.mjs';
6
+ import { ComposedRoute, PermissionRouteAccess } from '@btst/stack/client/components';
7
+ import { DefaultError } from '../shared/default-error.mjs';
8
+ import { NotFoundPage } from './404-page.mjs';
9
+ import { cmsPermissions } from '../../../permissions.mjs';
10
+ import { EditorSkeleton } from '../loading/editor-skeleton.mjs';
11
+ import { useSuspenseContentItem } from '../../hooks/cms-hooks.mjs';
12
+
13
+ const ContentEditorPageInternal = lazy(
14
+ () => import('./content-editor-page.internal.mjs').then((m) => ({
15
+ default: m.ContentEditorPage
16
+ }))
17
+ );
18
+ function ContentEditorPageComponent({
19
+ typeSlug,
20
+ id
21
+ }) {
22
+ const { onRouteError } = usePluginOverrides(CMS_PLUGIN_ID);
23
+ const isNew = !id;
24
+ const path = isNew ? `/cms/${typeSlug}/new` : `/cms/${typeSlug}/${id}`;
25
+ return /* @__PURE__ */ jsx(
26
+ ComposedRoute,
27
+ {
28
+ path,
29
+ PageComponent: AuthorizedContentEditorPage,
30
+ ErrorComponent: DefaultError,
31
+ LoadingComponent: EditorSkeleton,
32
+ NotFoundComponent: NotFoundPage,
33
+ props: { typeSlug, id },
34
+ onError: (error) => {
35
+ if (onRouteError) {
36
+ onRouteError("contentEditor", error, {
37
+ path,
38
+ params: { typeSlug, id: id ?? "" },
39
+ isSSR: typeof window === "undefined"
40
+ });
41
+ }
42
+ }
43
+ }
44
+ );
45
+ }
46
+ function AuthorizedContentEditorPage({
47
+ typeSlug,
48
+ id
49
+ }) {
50
+ if (!id) {
51
+ return /* @__PURE__ */ jsx(
52
+ PermissionRouteAccess,
53
+ {
54
+ permission: cmsPermissions.record.create({ contentType: typeSlug }),
55
+ LoadingComponent: EditorSkeleton,
56
+ children: /* @__PURE__ */ jsx(ContentEditorPageInternal, { typeSlug })
57
+ }
58
+ );
59
+ }
60
+ return /* @__PURE__ */ jsx(AuthorizedExistingContentEditorPage, { typeSlug, id });
61
+ }
62
+ function AuthorizedExistingContentEditorPage({
63
+ typeSlug,
64
+ id
65
+ }) {
66
+ const { item } = useSuspenseContentItem(typeSlug, id);
67
+ if (!item) return /* @__PURE__ */ jsx(ContentEditorPageInternal, { typeSlug, id });
68
+ return /* @__PURE__ */ jsx(
69
+ PermissionRouteAccess,
70
+ {
71
+ permission: cmsPermissions.record.update({
72
+ contentType: item.contentType?.slug ?? typeSlug,
73
+ recordId: item.id,
74
+ ...item.authorId ? { authorId: item.authorId } : {}
75
+ }),
76
+ LoadingComponent: EditorSkeleton,
77
+ children: /* @__PURE__ */ jsx(ContentEditorPageInternal, { typeSlug, id })
78
+ }
79
+ );
80
+ }
81
+
82
+ export { ContentEditorPageComponent };
@@ -0,0 +1,49 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ const jsxRuntime = require('react/jsx-runtime');
5
+ const React = require('react');
6
+ const context = require('@btst/stack/context');
7
+ const constants = require('../../constants.cjs');
8
+ const components = require('@btst/stack/client/components');
9
+ const defaultError = require('../shared/default-error.cjs');
10
+ const _404Page = require('./404-page.cjs');
11
+ const permissions = require('../../../permissions.cjs');
12
+ const listSkeleton = require('../loading/list-skeleton.cjs');
13
+
14
+ const ContentListPageInternal = React.lazy(
15
+ () => import('./content-list-page.internal.cjs').then((m) => ({
16
+ default: m.ContentListPage
17
+ }))
18
+ );
19
+ function ContentListPageComponent({
20
+ typeSlug
21
+ }) {
22
+ const { onRouteError } = context.usePluginOverrides(constants.CMS_PLUGIN_ID);
23
+ return /* @__PURE__ */ jsxRuntime.jsx(
24
+ components.ComposedRoute,
25
+ {
26
+ path: `/cms/${typeSlug}`,
27
+ permission: permissions.cmsPermissions.record.read({
28
+ contentType: typeSlug,
29
+ scope: "collection"
30
+ }),
31
+ PageComponent: ContentListPageInternal,
32
+ ErrorComponent: defaultError.DefaultError,
33
+ LoadingComponent: listSkeleton.ListSkeleton,
34
+ NotFoundComponent: _404Page.NotFoundPage,
35
+ props: { typeSlug },
36
+ onError: (error) => {
37
+ if (onRouteError) {
38
+ onRouteError("contentList", error, {
39
+ path: `/cms/${typeSlug}`,
40
+ params: { typeSlug },
41
+ isSSR: typeof window === "undefined"
42
+ });
43
+ }
44
+ }
45
+ }
46
+ );
47
+ }
48
+
49
+ exports.ContentListPageComponent = ContentListPageComponent;