@btst/stack 2.5.5 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/dist/client/components/index.d.cts +9 -9
- package/dist/client/components/index.d.mts +9 -9
- package/dist/client/components/index.d.ts +9 -9
- package/dist/packages/stack/src/plugins/ai-chat/client/components/shared/default-error.cjs +1 -1
- package/dist/packages/stack/src/plugins/ai-chat/client/components/shared/default-error.mjs +1 -1
- package/dist/packages/stack/src/plugins/ai-chat/client/plugin.cjs +44 -35
- package/dist/packages/stack/src/plugins/ai-chat/client/plugin.mjs +44 -35
- package/dist/packages/stack/src/plugins/blog/client/components/shared/default-error.cjs +1 -1
- package/dist/packages/stack/src/plugins/blog/client/components/shared/default-error.mjs +1 -1
- package/dist/packages/stack/src/plugins/blog/client/hooks/use-debounce.cjs +22 -0
- package/dist/packages/stack/src/plugins/blog/client/hooks/use-debounce.mjs +23 -2
- package/dist/packages/stack/src/plugins/blog/client/plugin.cjs +12 -6
- package/dist/packages/stack/src/plugins/blog/client/plugin.mjs +12 -6
- package/dist/packages/stack/src/plugins/cms/client/components/shared/default-error.cjs +1 -1
- package/dist/packages/stack/src/plugins/cms/client/components/shared/default-error.mjs +1 -1
- package/dist/packages/stack/src/plugins/cms/client/plugin.cjs +38 -26
- package/dist/packages/stack/src/plugins/cms/client/plugin.mjs +38 -26
- package/dist/packages/stack/src/plugins/form-builder/client/components/shared/default-error.cjs +1 -1
- package/dist/packages/stack/src/plugins/form-builder/client/components/shared/default-error.mjs +1 -1
- package/dist/packages/stack/src/plugins/form-builder/client/plugin.cjs +32 -20
- package/dist/packages/stack/src/plugins/form-builder/client/plugin.mjs +32 -20
- package/dist/packages/stack/src/plugins/kanban/client/components/shared/default-error.cjs +1 -1
- package/dist/packages/stack/src/plugins/kanban/client/components/shared/default-error.mjs +1 -1
- package/dist/packages/stack/src/plugins/kanban/client/plugin.cjs +6 -3
- package/dist/packages/stack/src/plugins/kanban/client/plugin.mjs +6 -3
- package/dist/packages/stack/src/plugins/ui-builder/client/components/page-renderer.cjs +1 -1
- package/dist/packages/stack/src/plugins/ui-builder/client/components/page-renderer.mjs +1 -1
- package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.cjs +3 -1
- package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.mjs +3 -1
- package/dist/packages/stack/src/plugins/ui-builder/client/components/shared/default-error.cjs +1 -1
- package/dist/packages/stack/src/plugins/ui-builder/client/components/shared/default-error.mjs +1 -1
- package/dist/packages/stack/src/plugins/ui-builder/client/plugin.cjs +24 -15
- package/dist/packages/stack/src/plugins/ui-builder/client/plugin.mjs +24 -15
- package/dist/packages/ui/src/components/search-select.cjs +13 -3
- package/dist/packages/ui/src/components/search-select.mjs +14 -4
- package/dist/plugins/ai-chat/client/index.d.cts +17 -4
- package/dist/plugins/ai-chat/client/index.d.mts +17 -4
- package/dist/plugins/ai-chat/client/index.d.ts +17 -4
- package/dist/plugins/blog/client/hooks/index.cjs +3 -0
- package/dist/plugins/blog/client/hooks/index.d.cts +7 -226
- package/dist/plugins/blog/client/hooks/index.d.mts +7 -226
- package/dist/plugins/blog/client/hooks/index.d.ts +7 -226
- package/dist/plugins/blog/client/hooks/index.mjs +1 -0
- package/dist/plugins/blog/client/index.d.cts +45 -21
- package/dist/plugins/blog/client/index.d.mts +45 -21
- package/dist/plugins/blog/client/index.d.ts +45 -21
- package/dist/plugins/cms/client/index.d.cts +35 -14
- package/dist/plugins/cms/client/index.d.mts +35 -14
- package/dist/plugins/cms/client/index.d.ts +35 -14
- package/dist/plugins/form-builder/client/components/index.d.cts +1 -1
- package/dist/plugins/form-builder/client/components/index.d.mts +1 -1
- package/dist/plugins/form-builder/client/components/index.d.ts +1 -1
- package/dist/plugins/form-builder/client/index.d.cts +32 -14
- package/dist/plugins/form-builder/client/index.d.mts +32 -14
- package/dist/plugins/form-builder/client/index.d.ts +32 -14
- package/dist/plugins/kanban/api/index.d.cts +1 -1
- package/dist/plugins/kanban/api/index.d.mts +1 -1
- package/dist/plugins/kanban/api/index.d.ts +1 -1
- package/dist/plugins/kanban/client/components/index.d.cts +5 -5
- package/dist/plugins/kanban/client/components/index.d.mts +5 -5
- package/dist/plugins/kanban/client/components/index.d.ts +5 -5
- package/dist/plugins/kanban/client/index.d.cts +25 -10
- package/dist/plugins/kanban/client/index.d.mts +25 -10
- package/dist/plugins/kanban/client/index.d.ts +25 -10
- package/dist/plugins/kanban/query-keys.d.cts +1 -1
- package/dist/plugins/kanban/query-keys.d.mts +1 -1
- package/dist/plugins/kanban/query-keys.d.ts +1 -1
- package/dist/plugins/route-docs/client/index.d.cts +4 -4
- package/dist/plugins/route-docs/client/index.d.mts +4 -4
- package/dist/plugins/route-docs/client/index.d.ts +4 -4
- package/dist/plugins/ui-builder/client/components/index.d.cts +1 -1
- package/dist/plugins/ui-builder/client/components/index.d.mts +1 -1
- package/dist/plugins/ui-builder/client/components/index.d.ts +1 -1
- package/dist/plugins/ui-builder/client/index.d.cts +35 -16
- package/dist/plugins/ui-builder/client/index.d.mts +35 -16
- package/dist/plugins/ui-builder/client/index.d.ts +35 -16
- package/dist/shared/stack.CNLHlv7r.d.mts +228 -0
- package/dist/shared/stack.CQAZwXhV.d.cts +228 -0
- package/dist/shared/stack.D3BsrpAz.d.ts +228 -0
- package/package.json +19 -2
- package/src/__tests__/page-component-overrides.test.tsx +147 -0
- package/src/plugins/ai-chat/client/components/shared/default-error.tsx +1 -1
- package/src/plugins/ai-chat/client/plugin.tsx +60 -32
- package/src/plugins/blog/client/components/shared/default-error.tsx +2 -1
- package/src/plugins/blog/client/hooks/index.tsx +1 -0
- package/src/plugins/blog/client/plugin.tsx +41 -6
- package/src/plugins/cms/client/components/shared/default-error.tsx +3 -2
- package/src/plugins/cms/client/plugin.tsx +65 -32
- package/src/plugins/form-builder/client/components/shared/default-error.tsx +3 -2
- package/src/plugins/form-builder/client/plugin.tsx +56 -23
- package/src/plugins/kanban/client/components/shared/default-error.tsx +3 -2
- package/src/plugins/kanban/client/plugin.tsx +23 -3
- package/src/plugins/ui-builder/client/components/page-renderer.tsx +5 -3
- package/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.tsx +2 -0
- package/src/plugins/ui-builder/client/components/shared/default-error.tsx +3 -2
- package/src/plugins/ui-builder/client/overrides.ts +10 -1
- package/src/plugins/ui-builder/client/plugin.tsx +41 -15
- package/dist/shared/{stack.CxNeGV2z.d.mts → stack.Ba_Ks8qi.d.mts} +9 -9
- package/dist/shared/{stack.DSxTDZBQ.d.cts → stack.CFqqZUes.d.cts} +9 -9
- package/dist/shared/{stack.BFcg0tDz.d.ts → stack.DMobugrZ.d.ts} +9 -9
|
@@ -4,7 +4,7 @@ import { AlertCircle } from "lucide-react";
|
|
|
4
4
|
import { Button } from "@workspace/ui/components/button";
|
|
5
5
|
|
|
6
6
|
interface DefaultErrorProps {
|
|
7
|
-
error:
|
|
7
|
+
error: unknown;
|
|
8
8
|
resetErrorBoundary?: () => void;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -18,7 +18,8 @@ export function DefaultError({ error, resetErrorBoundary }: DefaultErrorProps) {
|
|
|
18
18
|
Something went wrong
|
|
19
19
|
</h3>
|
|
20
20
|
<p className="text-sm text-muted-foreground mb-4 max-w-sm">
|
|
21
|
-
{error
|
|
21
|
+
{(error instanceof Error ? error.message : undefined) ||
|
|
22
|
+
"An unexpected error occurred"}
|
|
22
23
|
</p>
|
|
23
24
|
{resetErrorBoundary && (
|
|
24
25
|
<Button variant="outline" onClick={resetErrorBoundary}>
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
runClientHookWithShim,
|
|
7
7
|
} from "@btst/stack/plugins/client";
|
|
8
8
|
import { createRoute } from "@btst/yar";
|
|
9
|
+
import type { ComponentType } from "react";
|
|
9
10
|
import type { QueryClient } from "@tanstack/react-query";
|
|
10
11
|
import type { CMSApiRouter } from "../api";
|
|
11
12
|
import { createCMSQueryKeys } from "../query-keys";
|
|
@@ -129,6 +130,22 @@ export interface CMSClientConfig {
|
|
|
129
130
|
headers?: Headers;
|
|
130
131
|
/** Optional hooks for customizing behavior (authorization, redirects, etc.) */
|
|
131
132
|
hooks?: CMSClientHooks;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Optional page component overrides.
|
|
136
|
+
* Replace any plugin page with a custom React component.
|
|
137
|
+
* The built-in component is used as the fallback when not provided.
|
|
138
|
+
*/
|
|
139
|
+
pageComponents?: {
|
|
140
|
+
/** Replaces the CMS dashboard page */
|
|
141
|
+
dashboard?: ComponentType;
|
|
142
|
+
/** Replaces the content list page */
|
|
143
|
+
contentList?: ComponentType<{ typeSlug: string }>;
|
|
144
|
+
/** Replaces the new content editor page */
|
|
145
|
+
newContent?: ComponentType<{ typeSlug: string }>;
|
|
146
|
+
/** Replaces the edit content editor page */
|
|
147
|
+
editContent?: ComponentType<{ typeSlug: string; id: string }>;
|
|
148
|
+
};
|
|
132
149
|
}
|
|
133
150
|
|
|
134
151
|
/**
|
|
@@ -469,38 +486,54 @@ export const cmsClientPlugin = (config: CMSClientConfig) =>
|
|
|
469
486
|
name: "cms",
|
|
470
487
|
|
|
471
488
|
routes: () => ({
|
|
472
|
-
dashboard: createRoute("/cms", () =>
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
})
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
typeSlug={params.typeSlug}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
})
|
|
489
|
+
dashboard: createRoute("/cms", () => {
|
|
490
|
+
const CustomDashboard = config.pageComponents?.dashboard;
|
|
491
|
+
return {
|
|
492
|
+
PageComponent: CustomDashboard ?? (() => <DashboardPageComponent />),
|
|
493
|
+
loader: createDashboardLoader(config),
|
|
494
|
+
meta: createDashboardMeta(),
|
|
495
|
+
};
|
|
496
|
+
}),
|
|
497
|
+
|
|
498
|
+
contentList: createRoute("/cms/:typeSlug", ({ params }) => {
|
|
499
|
+
const CustomContentList = config.pageComponents?.contentList;
|
|
500
|
+
return {
|
|
501
|
+
PageComponent: CustomContentList
|
|
502
|
+
? () => <CustomContentList typeSlug={params.typeSlug} />
|
|
503
|
+
: () => <ContentListPageComponent typeSlug={params.typeSlug} />,
|
|
504
|
+
loader: createContentListLoader(params.typeSlug, config),
|
|
505
|
+
meta: createContentListMeta(params.typeSlug, config),
|
|
506
|
+
};
|
|
507
|
+
}),
|
|
508
|
+
|
|
509
|
+
newContent: createRoute("/cms/:typeSlug/new", ({ params }) => {
|
|
510
|
+
const CustomNewContent = config.pageComponents?.newContent;
|
|
511
|
+
return {
|
|
512
|
+
PageComponent: CustomNewContent
|
|
513
|
+
? () => <CustomNewContent typeSlug={params.typeSlug} />
|
|
514
|
+
: () => <ContentEditorPageComponent typeSlug={params.typeSlug} />,
|
|
515
|
+
loader: createContentEditorLoader(params.typeSlug, undefined, config),
|
|
516
|
+
meta: createContentEditorMeta(params.typeSlug, undefined, config),
|
|
517
|
+
};
|
|
518
|
+
}),
|
|
519
|
+
|
|
520
|
+
editContent: createRoute("/cms/:typeSlug/:id", ({ params }) => {
|
|
521
|
+
const CustomEditContent = config.pageComponents?.editContent;
|
|
522
|
+
return {
|
|
523
|
+
PageComponent: CustomEditContent
|
|
524
|
+
? () => (
|
|
525
|
+
<CustomEditContent typeSlug={params.typeSlug} id={params.id} />
|
|
526
|
+
)
|
|
527
|
+
: () => (
|
|
528
|
+
<ContentEditorPageComponent
|
|
529
|
+
typeSlug={params.typeSlug}
|
|
530
|
+
id={params.id}
|
|
531
|
+
/>
|
|
532
|
+
),
|
|
533
|
+
loader: createContentEditorLoader(params.typeSlug, params.id, config),
|
|
534
|
+
meta: createContentEditorMeta(params.typeSlug, params.id, config),
|
|
535
|
+
};
|
|
536
|
+
}),
|
|
504
537
|
}),
|
|
505
538
|
|
|
506
539
|
sitemap: async () => {
|
|
@@ -4,7 +4,7 @@ import { AlertCircle } from "lucide-react";
|
|
|
4
4
|
import { Button } from "@workspace/ui/components/button";
|
|
5
5
|
|
|
6
6
|
interface DefaultErrorProps {
|
|
7
|
-
error:
|
|
7
|
+
error: unknown;
|
|
8
8
|
resetErrorBoundary?: () => void;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -18,7 +18,8 @@ export function DefaultError({ error, resetErrorBoundary }: DefaultErrorProps) {
|
|
|
18
18
|
Something went wrong
|
|
19
19
|
</h3>
|
|
20
20
|
<p className="text-sm text-muted-foreground mb-4 max-w-sm">
|
|
21
|
-
{error
|
|
21
|
+
{(error instanceof Error ? error.message : undefined) ||
|
|
22
|
+
"An unexpected error occurred"}
|
|
22
23
|
</p>
|
|
23
24
|
{resetErrorBoundary && (
|
|
24
25
|
<Button variant="outline" onClick={resetErrorBoundary}>
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
runClientHookWithShim,
|
|
8
8
|
} from "@btst/stack/plugins/client";
|
|
9
9
|
import { createRoute } from "@btst/yar";
|
|
10
|
+
import type { ComponentType } from "react";
|
|
10
11
|
import type { QueryClient } from "@tanstack/react-query";
|
|
11
12
|
import type { FormBuilderApiRouter } from "../api";
|
|
12
13
|
import { createFormBuilderQueryKeys } from "../query-keys";
|
|
@@ -126,6 +127,22 @@ export interface FormBuilderClientConfig {
|
|
|
126
127
|
headers?: Headers;
|
|
127
128
|
/** Optional hooks for customizing behavior (authorization, redirects, etc.) */
|
|
128
129
|
hooks?: FormBuilderClientHooks;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Optional page component overrides.
|
|
133
|
+
* Replace any plugin page with a custom React component.
|
|
134
|
+
* The built-in component is used as the fallback when not provided.
|
|
135
|
+
*/
|
|
136
|
+
pageComponents?: {
|
|
137
|
+
/** Replaces the form list page */
|
|
138
|
+
formList?: ComponentType;
|
|
139
|
+
/** Replaces the new form page */
|
|
140
|
+
newForm?: ComponentType;
|
|
141
|
+
/** Replaces the form editor page */
|
|
142
|
+
editForm?: ComponentType<{ id: string }>;
|
|
143
|
+
/** Replaces the form submissions page */
|
|
144
|
+
submissions?: ComponentType<{ formId: string }>;
|
|
145
|
+
};
|
|
129
146
|
}
|
|
130
147
|
|
|
131
148
|
/**
|
|
@@ -476,29 +493,45 @@ export const formBuilderClientPlugin = (config: FormBuilderClientConfig) =>
|
|
|
476
493
|
name: "form-builder",
|
|
477
494
|
|
|
478
495
|
routes: () => ({
|
|
479
|
-
formList: createRoute("/forms", () =>
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
})
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
496
|
+
formList: createRoute("/forms", () => {
|
|
497
|
+
const CustomFormList = config.pageComponents?.formList;
|
|
498
|
+
return {
|
|
499
|
+
PageComponent: CustomFormList ?? (() => <FormListPageComponent />),
|
|
500
|
+
loader: createFormListLoader(config),
|
|
501
|
+
meta: createFormListMeta(),
|
|
502
|
+
};
|
|
503
|
+
}),
|
|
504
|
+
|
|
505
|
+
newForm: createRoute("/forms/new", () => {
|
|
506
|
+
const CustomNewForm = config.pageComponents?.newForm;
|
|
507
|
+
return {
|
|
508
|
+
PageComponent: CustomNewForm ?? (() => <FormBuilderPageComponent />),
|
|
509
|
+
loader: createFormBuilderLoader(undefined, config),
|
|
510
|
+
meta: createFormBuilderMeta(undefined, config),
|
|
511
|
+
};
|
|
512
|
+
}),
|
|
513
|
+
|
|
514
|
+
editForm: createRoute("/forms/:id/edit", ({ params }) => {
|
|
515
|
+
const CustomEditForm = config.pageComponents?.editForm;
|
|
516
|
+
return {
|
|
517
|
+
PageComponent: CustomEditForm
|
|
518
|
+
? () => <CustomEditForm id={params.id} />
|
|
519
|
+
: () => <FormBuilderPageComponent id={params.id} />,
|
|
520
|
+
loader: createFormBuilderLoader(params.id, config),
|
|
521
|
+
meta: createFormBuilderMeta(params.id, config),
|
|
522
|
+
};
|
|
523
|
+
}),
|
|
524
|
+
|
|
525
|
+
submissions: createRoute("/forms/:id/submissions", ({ params }) => {
|
|
526
|
+
const CustomSubmissions = config.pageComponents?.submissions;
|
|
527
|
+
return {
|
|
528
|
+
PageComponent: CustomSubmissions
|
|
529
|
+
? () => <CustomSubmissions formId={params.id} />
|
|
530
|
+
: () => <SubmissionsPageComponent formId={params.id} />,
|
|
531
|
+
loader: createSubmissionsLoader(params.id, config),
|
|
532
|
+
meta: createSubmissionsMeta(params.id, config),
|
|
533
|
+
};
|
|
534
|
+
}),
|
|
502
535
|
}),
|
|
503
536
|
|
|
504
537
|
sitemap: async () => {
|
|
@@ -4,7 +4,7 @@ import { AlertCircle, RefreshCw } from "lucide-react";
|
|
|
4
4
|
import { Button } from "@workspace/ui/components/button";
|
|
5
5
|
|
|
6
6
|
interface DefaultErrorProps {
|
|
7
|
-
error?:
|
|
7
|
+
error?: unknown;
|
|
8
8
|
reset?: () => void;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -19,7 +19,8 @@ export function DefaultError({ error, reset }: DefaultErrorProps) {
|
|
|
19
19
|
</div>
|
|
20
20
|
<h3 className="text-lg font-semibold mb-2">Something went wrong</h3>
|
|
21
21
|
<p className="text-muted-foreground max-w-md mb-4">
|
|
22
|
-
{error
|
|
22
|
+
{(error instanceof Error ? error.message : undefined) ||
|
|
23
|
+
"An unexpected error occurred. Please try again."}
|
|
23
24
|
</p>
|
|
24
25
|
{reset && (
|
|
25
26
|
<Button onClick={reset} variant="outline">
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
runClientHookWithShim,
|
|
6
6
|
} from "@btst/stack/plugins/client";
|
|
7
7
|
import { createRoute } from "@btst/yar";
|
|
8
|
+
import type { ComponentType } from "react";
|
|
8
9
|
import type { QueryClient } from "@tanstack/react-query";
|
|
9
10
|
import type { KanbanApiRouter } from "../api";
|
|
10
11
|
import { createKanbanQueryKeys } from "../query-keys";
|
|
@@ -79,6 +80,20 @@ export interface KanbanClientConfig {
|
|
|
79
80
|
|
|
80
81
|
/** Optional headers for SSR (e.g., forwarding cookies) */
|
|
81
82
|
headers?: Headers;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Optional page component overrides.
|
|
86
|
+
* Replace any plugin page with a custom React component.
|
|
87
|
+
* The built-in component is used as the fallback when not provided.
|
|
88
|
+
*/
|
|
89
|
+
pageComponents?: {
|
|
90
|
+
/** Replaces the boards list page */
|
|
91
|
+
boards?: ComponentType;
|
|
92
|
+
/** Replaces the new board page */
|
|
93
|
+
newBoard?: ComponentType;
|
|
94
|
+
/** Replaces the board detail page */
|
|
95
|
+
board?: ComponentType<{ boardId: string }>;
|
|
96
|
+
};
|
|
82
97
|
}
|
|
83
98
|
|
|
84
99
|
/**
|
|
@@ -407,22 +422,27 @@ export const kanbanClientPlugin = (config: KanbanClientConfig) =>
|
|
|
407
422
|
|
|
408
423
|
routes: () => ({
|
|
409
424
|
boards: createRoute("/kanban", () => {
|
|
425
|
+
const CustomBoards = config.pageComponents?.boards;
|
|
410
426
|
return {
|
|
411
|
-
PageComponent: () => <BoardsListPageComponent
|
|
427
|
+
PageComponent: CustomBoards ?? (() => <BoardsListPageComponent />),
|
|
412
428
|
loader: createBoardsLoader(config),
|
|
413
429
|
meta: createBoardsListMeta(config),
|
|
414
430
|
};
|
|
415
431
|
}),
|
|
416
432
|
newBoard: createRoute("/kanban/new", () => {
|
|
433
|
+
const CustomNewBoard = config.pageComponents?.newBoard;
|
|
417
434
|
return {
|
|
418
|
-
PageComponent: NewBoardPageComponent,
|
|
435
|
+
PageComponent: CustomNewBoard ?? NewBoardPageComponent,
|
|
419
436
|
loader: createNewBoardLoader(config),
|
|
420
437
|
meta: createNewBoardMeta(config),
|
|
421
438
|
};
|
|
422
439
|
}),
|
|
423
440
|
board: createRoute("/kanban/:boardId", ({ params: { boardId } }) => {
|
|
441
|
+
const CustomBoard = config.pageComponents?.board;
|
|
424
442
|
return {
|
|
425
|
-
PageComponent:
|
|
443
|
+
PageComponent: CustomBoard
|
|
444
|
+
? () => <CustomBoard boardId={boardId} />
|
|
445
|
+
: () => <BoardPageComponent boardId={boardId} />,
|
|
426
446
|
loader: createBoardLoader(boardId, config),
|
|
427
447
|
meta: createBoardMeta(boardId, config),
|
|
428
448
|
};
|
|
@@ -29,13 +29,15 @@ function DefaultLoadingComponent(): ReactNode {
|
|
|
29
29
|
/**
|
|
30
30
|
* Default error component for PageRenderer
|
|
31
31
|
*/
|
|
32
|
-
function DefaultErrorComponent({ error }: { error:
|
|
32
|
+
function DefaultErrorComponent({ error }: { error: unknown }): ReactNode {
|
|
33
33
|
return (
|
|
34
34
|
<div className="flex flex-col items-center justify-center min-h-[200px] p-4">
|
|
35
35
|
<div className="text-destructive font-medium">
|
|
36
36
|
{uiBuilderLocalization.pageRenderer.error}
|
|
37
37
|
</div>
|
|
38
|
-
<div className="text-sm text-muted-foreground mt-2">
|
|
38
|
+
<div className="text-sm text-muted-foreground mt-2">
|
|
39
|
+
{error instanceof Error ? error.message : String(error)}
|
|
40
|
+
</div>
|
|
39
41
|
</div>
|
|
40
42
|
);
|
|
41
43
|
}
|
|
@@ -65,7 +67,7 @@ export interface PageRendererProps {
|
|
|
65
67
|
/** Custom loading component */
|
|
66
68
|
LoadingComponent?: ComponentType;
|
|
67
69
|
/** Custom error component */
|
|
68
|
-
ErrorComponent?: ComponentType<{ error:
|
|
70
|
+
ErrorComponent?: ComponentType<{ error: unknown }>;
|
|
69
71
|
/** Custom not found component */
|
|
70
72
|
NotFoundComponent?: ComponentType;
|
|
71
73
|
/** Additional className for the container */
|
|
@@ -215,6 +215,7 @@ function PageBuilderPageContent({
|
|
|
215
215
|
navigate,
|
|
216
216
|
Link,
|
|
217
217
|
componentRegistry: customRegistry,
|
|
218
|
+
functionRegistry,
|
|
218
219
|
} = usePluginOverrides<UIBuilderPluginOverrides>("ui-builder");
|
|
219
220
|
const basePath = useBasePath();
|
|
220
221
|
|
|
@@ -463,6 +464,7 @@ function PageBuilderPageContent({
|
|
|
463
464
|
}
|
|
464
465
|
onVariablesChange={handleVariablesChange}
|
|
465
466
|
componentRegistry={componentRegistry}
|
|
467
|
+
functionRegistry={functionRegistry}
|
|
466
468
|
persistLayerStore={false}
|
|
467
469
|
allowVariableEditing={true}
|
|
468
470
|
allowPagesCreation={false}
|
|
@@ -4,7 +4,7 @@ import { AlertCircle } from "lucide-react";
|
|
|
4
4
|
import { Button } from "@workspace/ui/components/button";
|
|
5
5
|
|
|
6
6
|
interface DefaultErrorProps {
|
|
7
|
-
error:
|
|
7
|
+
error: unknown;
|
|
8
8
|
resetErrorBoundary?: () => void;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -18,7 +18,8 @@ export function DefaultError({ error, resetErrorBoundary }: DefaultErrorProps) {
|
|
|
18
18
|
Something went wrong
|
|
19
19
|
</h3>
|
|
20
20
|
<p className="text-sm text-muted-foreground mb-4 max-w-sm">
|
|
21
|
-
{error
|
|
21
|
+
{(error instanceof Error ? error.message : undefined) ||
|
|
22
|
+
"An unexpected error occurred"}
|
|
22
23
|
</p>
|
|
23
24
|
{resetErrorBoundary && (
|
|
24
25
|
<Button variant="outline" onClick={resetErrorBoundary}>
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { ComponentType } from "react";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
ComponentRegistry,
|
|
4
|
+
FunctionRegistry,
|
|
5
|
+
} from "@workspace/ui/components/ui-builder/types";
|
|
3
6
|
import type { UIBuilderClientHooks } from "../types";
|
|
4
7
|
|
|
5
8
|
/**
|
|
@@ -63,6 +66,12 @@ export interface UIBuilderPluginOverrides {
|
|
|
63
66
|
*/
|
|
64
67
|
componentRegistry?: ComponentRegistry;
|
|
65
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Function registry for resolving bindable event handlers (onClick, onSubmit, etc.)
|
|
71
|
+
* in the preview modal and layer renderer.
|
|
72
|
+
*/
|
|
73
|
+
functionRegistry?: FunctionRegistry;
|
|
74
|
+
|
|
66
75
|
/**
|
|
67
76
|
* Base path for UI Builder admin pages (default: /pages/ui-builder)
|
|
68
77
|
*/
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
runClientHookWithShim,
|
|
7
7
|
} from "@btst/stack/plugins/client";
|
|
8
8
|
import { createRoute } from "@btst/yar";
|
|
9
|
+
import type { ComponentType } from "react";
|
|
9
10
|
import type { QueryClient } from "@tanstack/react-query";
|
|
10
11
|
import type { CMSApiRouter } from "../../cms/api";
|
|
11
12
|
import { createCMSQueryKeys } from "../../cms/query-keys";
|
|
@@ -48,6 +49,20 @@ export interface UIBuilderClientConfig {
|
|
|
48
49
|
hooks?: UIBuilderClientHooks;
|
|
49
50
|
/** Component registry to use for the UI Builder */
|
|
50
51
|
componentRegistry?: ComponentRegistry;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Optional page component overrides.
|
|
55
|
+
* Replace any plugin page with a custom React component.
|
|
56
|
+
* The built-in component is used as the fallback when not provided.
|
|
57
|
+
*/
|
|
58
|
+
pageComponents?: {
|
|
59
|
+
/** Replaces the page list page */
|
|
60
|
+
pageList?: ComponentType;
|
|
61
|
+
/** Replaces the new page builder page */
|
|
62
|
+
newPage?: ComponentType;
|
|
63
|
+
/** Replaces the edit page builder page */
|
|
64
|
+
editPage?: ComponentType<{ id: string }>;
|
|
65
|
+
};
|
|
51
66
|
}
|
|
52
67
|
|
|
53
68
|
/**
|
|
@@ -290,23 +305,34 @@ export const uiBuilderClientPlugin = (config: UIBuilderClientConfig) =>
|
|
|
290
305
|
name: "ui-builder",
|
|
291
306
|
|
|
292
307
|
routes: () => ({
|
|
293
|
-
pageList: createRoute("/ui-builder", () =>
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
308
|
+
pageList: createRoute("/ui-builder", () => {
|
|
309
|
+
const CustomPageList = config.pageComponents?.pageList;
|
|
310
|
+
return {
|
|
311
|
+
PageComponent: CustomPageList ?? (() => <PageListPageComponent />),
|
|
312
|
+
loader: createPageListLoader(config),
|
|
313
|
+
meta: createPageListMeta(),
|
|
314
|
+
};
|
|
315
|
+
}),
|
|
298
316
|
|
|
299
|
-
newPage: createRoute("/ui-builder/new", () =>
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
317
|
+
newPage: createRoute("/ui-builder/new", () => {
|
|
318
|
+
const CustomNewPage = config.pageComponents?.newPage;
|
|
319
|
+
return {
|
|
320
|
+
PageComponent: CustomNewPage ?? (() => <PageBuilderPageComponent />),
|
|
321
|
+
loader: createPageBuilderLoader(undefined, config),
|
|
322
|
+
meta: createPageBuilderMeta(undefined, config),
|
|
323
|
+
};
|
|
324
|
+
}),
|
|
304
325
|
|
|
305
|
-
editPage: createRoute("/ui-builder/:id/edit", ({ params }) =>
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
326
|
+
editPage: createRoute("/ui-builder/:id/edit", ({ params }) => {
|
|
327
|
+
const CustomEditPage = config.pageComponents?.editPage;
|
|
328
|
+
return {
|
|
329
|
+
PageComponent: CustomEditPage
|
|
330
|
+
? () => <CustomEditPage id={params.id} />
|
|
331
|
+
: () => <PageBuilderPageComponent id={params.id} />,
|
|
332
|
+
loader: createPageBuilderLoader(params.id, config),
|
|
333
|
+
meta: createPageBuilderMeta(params.id, config),
|
|
334
|
+
};
|
|
335
|
+
}),
|
|
310
336
|
}),
|
|
311
337
|
|
|
312
338
|
sitemap: async () => {
|
|
@@ -8,11 +8,11 @@ import { QueryClient } from '@tanstack/react-query';
|
|
|
8
8
|
declare const createBoardSchema: z.ZodObject<{
|
|
9
9
|
description: z.ZodOptional<z.ZodString>;
|
|
10
10
|
name: z.ZodString;
|
|
11
|
+
createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
12
|
+
updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
11
13
|
slug: z.ZodOptional<z.ZodString>;
|
|
12
14
|
ownerId: z.ZodOptional<z.ZodString>;
|
|
13
15
|
organizationId: z.ZodOptional<z.ZodString>;
|
|
14
|
-
createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
15
|
-
updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
16
16
|
}, z.core.$strip>;
|
|
17
17
|
declare const updateBoardSchema: z.ZodObject<{
|
|
18
18
|
createdAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
@@ -26,9 +26,9 @@ declare const updateBoardSchema: z.ZodObject<{
|
|
|
26
26
|
}, z.core.$strip>;
|
|
27
27
|
declare const createColumnSchema: z.ZodObject<{
|
|
28
28
|
title: z.ZodString;
|
|
29
|
-
boardId: z.ZodString;
|
|
30
29
|
createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
31
30
|
updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
31
|
+
boardId: z.ZodString;
|
|
32
32
|
order: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
33
33
|
}, z.core.$strip>;
|
|
34
34
|
declare const updateColumnSchema: z.ZodObject<{
|
|
@@ -324,11 +324,11 @@ declare const kanbanBackendPlugin: (hooks?: KanbanBackendHooks) => _btst_stack_p
|
|
|
324
324
|
body: z.ZodObject<{
|
|
325
325
|
description: z.ZodOptional<z.ZodString>;
|
|
326
326
|
name: z.ZodString;
|
|
327
|
+
createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
328
|
+
updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
327
329
|
slug: z.ZodOptional<z.ZodString>;
|
|
328
330
|
ownerId: z.ZodOptional<z.ZodString>;
|
|
329
331
|
organizationId: z.ZodOptional<z.ZodString>;
|
|
330
|
-
createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
331
|
-
updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
332
332
|
}, z.core.$strip>;
|
|
333
333
|
}, {
|
|
334
334
|
columns: ColumnWithTasks[];
|
|
@@ -346,11 +346,11 @@ declare const kanbanBackendPlugin: (hooks?: KanbanBackendHooks) => _btst_stack_p
|
|
|
346
346
|
body: z.ZodObject<{
|
|
347
347
|
description: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
348
348
|
name: z.ZodOptional<z.ZodString>;
|
|
349
|
+
createdAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
350
|
+
updatedAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
349
351
|
slug: z.ZodOptional<z.ZodString>;
|
|
350
352
|
ownerId: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
351
353
|
organizationId: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
352
|
-
createdAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
353
|
-
updatedAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
354
354
|
}, z.core.$strip>;
|
|
355
355
|
}, Board>;
|
|
356
356
|
readonly deleteBoard: better_call.StrictEndpoint<"/boards/:id", {
|
|
@@ -362,9 +362,9 @@ declare const kanbanBackendPlugin: (hooks?: KanbanBackendHooks) => _btst_stack_p
|
|
|
362
362
|
method: "POST";
|
|
363
363
|
body: z.ZodObject<{
|
|
364
364
|
title: z.ZodString;
|
|
365
|
-
boardId: z.ZodString;
|
|
366
365
|
createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
367
366
|
updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
367
|
+
boardId: z.ZodString;
|
|
368
368
|
order: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
369
369
|
}, z.core.$strip>;
|
|
370
370
|
}, Column>;
|
|
@@ -372,9 +372,9 @@ declare const kanbanBackendPlugin: (hooks?: KanbanBackendHooks) => _btst_stack_p
|
|
|
372
372
|
method: "PUT";
|
|
373
373
|
body: z.ZodObject<{
|
|
374
374
|
title: z.ZodOptional<z.ZodString>;
|
|
375
|
-
boardId: z.ZodOptional<z.ZodString>;
|
|
376
375
|
createdAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
377
376
|
updatedAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
377
|
+
boardId: z.ZodOptional<z.ZodString>;
|
|
378
378
|
order: z.ZodOptional<z.ZodDefault<z.ZodOptional<z.ZodNumber>>>;
|
|
379
379
|
}, z.core.$strip>;
|
|
380
380
|
}, Column>;
|
|
@@ -8,11 +8,11 @@ import { QueryClient } from '@tanstack/react-query';
|
|
|
8
8
|
declare const createBoardSchema: z.ZodObject<{
|
|
9
9
|
description: z.ZodOptional<z.ZodString>;
|
|
10
10
|
name: z.ZodString;
|
|
11
|
+
createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
12
|
+
updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
11
13
|
slug: z.ZodOptional<z.ZodString>;
|
|
12
14
|
ownerId: z.ZodOptional<z.ZodString>;
|
|
13
15
|
organizationId: z.ZodOptional<z.ZodString>;
|
|
14
|
-
createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
15
|
-
updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
16
16
|
}, z.core.$strip>;
|
|
17
17
|
declare const updateBoardSchema: z.ZodObject<{
|
|
18
18
|
createdAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
@@ -26,9 +26,9 @@ declare const updateBoardSchema: z.ZodObject<{
|
|
|
26
26
|
}, z.core.$strip>;
|
|
27
27
|
declare const createColumnSchema: z.ZodObject<{
|
|
28
28
|
title: z.ZodString;
|
|
29
|
-
boardId: z.ZodString;
|
|
30
29
|
createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
31
30
|
updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
31
|
+
boardId: z.ZodString;
|
|
32
32
|
order: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
33
33
|
}, z.core.$strip>;
|
|
34
34
|
declare const updateColumnSchema: z.ZodObject<{
|
|
@@ -324,11 +324,11 @@ declare const kanbanBackendPlugin: (hooks?: KanbanBackendHooks) => _btst_stack_p
|
|
|
324
324
|
body: z.ZodObject<{
|
|
325
325
|
description: z.ZodOptional<z.ZodString>;
|
|
326
326
|
name: z.ZodString;
|
|
327
|
+
createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
328
|
+
updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
327
329
|
slug: z.ZodOptional<z.ZodString>;
|
|
328
330
|
ownerId: z.ZodOptional<z.ZodString>;
|
|
329
331
|
organizationId: z.ZodOptional<z.ZodString>;
|
|
330
|
-
createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
331
|
-
updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
332
332
|
}, z.core.$strip>;
|
|
333
333
|
}, {
|
|
334
334
|
columns: ColumnWithTasks[];
|
|
@@ -346,11 +346,11 @@ declare const kanbanBackendPlugin: (hooks?: KanbanBackendHooks) => _btst_stack_p
|
|
|
346
346
|
body: z.ZodObject<{
|
|
347
347
|
description: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
348
348
|
name: z.ZodOptional<z.ZodString>;
|
|
349
|
+
createdAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
350
|
+
updatedAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
349
351
|
slug: z.ZodOptional<z.ZodString>;
|
|
350
352
|
ownerId: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
351
353
|
organizationId: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
352
|
-
createdAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
353
|
-
updatedAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
354
354
|
}, z.core.$strip>;
|
|
355
355
|
}, Board>;
|
|
356
356
|
readonly deleteBoard: better_call.StrictEndpoint<"/boards/:id", {
|
|
@@ -362,9 +362,9 @@ declare const kanbanBackendPlugin: (hooks?: KanbanBackendHooks) => _btst_stack_p
|
|
|
362
362
|
method: "POST";
|
|
363
363
|
body: z.ZodObject<{
|
|
364
364
|
title: z.ZodString;
|
|
365
|
-
boardId: z.ZodString;
|
|
366
365
|
createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
367
366
|
updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
367
|
+
boardId: z.ZodString;
|
|
368
368
|
order: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
369
369
|
}, z.core.$strip>;
|
|
370
370
|
}, Column>;
|
|
@@ -372,9 +372,9 @@ declare const kanbanBackendPlugin: (hooks?: KanbanBackendHooks) => _btst_stack_p
|
|
|
372
372
|
method: "PUT";
|
|
373
373
|
body: z.ZodObject<{
|
|
374
374
|
title: z.ZodOptional<z.ZodString>;
|
|
375
|
-
boardId: z.ZodOptional<z.ZodString>;
|
|
376
375
|
createdAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
377
376
|
updatedAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
377
|
+
boardId: z.ZodOptional<z.ZodString>;
|
|
378
378
|
order: z.ZodOptional<z.ZodDefault<z.ZodOptional<z.ZodNumber>>>;
|
|
379
379
|
}, z.core.$strip>;
|
|
380
380
|
}, Column>;
|