@nocobase/portal-template-default 1.0.1 → 1.0.2

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 (78) hide show
  1. package/README.MD +22 -3
  2. package/package.json +4 -2
  3. package/registry/nocobase-acl/components/role-options.ts +7 -0
  4. package/registry/nocobase-acl/components/role-switcher.tsx +9 -4
  5. package/registry/nocobase-acl/demo/boundary-api.tsx +87 -16
  6. package/registry/nocobase-acl/demo/components.tsx +32 -11
  7. package/registry/nocobase-acl/demo/index.tsx +45 -14
  8. package/registry/nocobase-acl/demo/lazy-route.tsx +2 -7
  9. package/registry/nocobase-acl/demo/prompt-generator.tsx +52 -33
  10. package/registry/nocobase-acl/demo/role-switcher-prompt-generator.tsx +28 -9
  11. package/registry/nocobase-acl/extension.tsx +1 -1
  12. package/registry/nocobase-acl/tests/acl-regression.mjs +7 -6
  13. package/registry/nocobase-ai/components/chat/chat-messages.tsx +3 -4
  14. package/registry/nocobase-ai/components/chat/conversation-list.tsx +2 -4
  15. package/registry/nocobase-ai/components/tools/business-report-dialog.tsx +16 -19
  16. package/registry/nocobase-ai/components/tools/chart-renderer.tsx +3 -14
  17. package/registry/nocobase-ai/components/tools/echarts-preview.tsx +2 -5
  18. package/registry/nocobase-ai/demo/configuration-gate.tsx +9 -12
  19. package/registry/nocobase-ai/extension.tsx +2 -7
  20. package/registry/nocobase-i18n/README.md +53 -0
  21. package/registry/nocobase-i18n/components/index.ts +1 -0
  22. package/registry/nocobase-i18n/components/language-switcher.tsx +138 -0
  23. package/registry/nocobase-i18n/demo/index.tsx +209 -0
  24. package/registry/nocobase-i18n/demo/prompt-generator.tsx +155 -0
  25. package/registry/nocobase-i18n/extension.tsx +46 -0
  26. package/registry/nocobase-i18n/i18n-provider.ts +9 -0
  27. package/registry/nocobase-i18n/index.ts +6 -0
  28. package/registry/nocobase-i18n/locale-store.ts +134 -0
  29. package/registry/nocobase-i18n/locales/en-US.ts +89 -0
  30. package/registry/nocobase-i18n/locales/zh-CN.ts +85 -0
  31. package/registry/nocobase-i18n/provider.tsx +32 -0
  32. package/registry/nocobase-i18n/runtime.ts +118 -0
  33. package/registry/nocobase-i18n/server-resources.ts +184 -0
  34. package/registry/nocobase-i18n/tests/i18n-regression.mjs +42 -0
  35. package/registry.config.json +34 -14
  36. package/scripts/registry.mjs +3 -0
  37. package/src/App.tsx +27 -86
  38. package/src/app/extension.ts +3 -1
  39. package/src/app/extensions.tsx +21 -0
  40. package/src/components/access-control/acl-gate.tsx +4 -10
  41. package/src/components/app-shell/breadcrumb.tsx +39 -3
  42. package/src/components/app-shell/document-title-handler.tsx +11 -20
  43. package/src/components/app-shell/header.tsx +18 -3
  44. package/src/components/app-shell/loading-overlay.tsx +2 -4
  45. package/src/components/app-shell/loading-state.tsx +15 -0
  46. package/src/components/app-shell/sidebar.tsx +75 -47
  47. package/src/components/data-table/data-table-pagination.tsx +27 -7
  48. package/src/components/data-table/data-table-styles.ts +57 -0
  49. package/src/components/data-table/data-table.tsx +14 -59
  50. package/src/components/resources/resource-label.ts +101 -0
  51. package/src/components/resources/views/create-view.tsx +17 -14
  52. package/src/components/resources/views/edit-view.tsx +17 -15
  53. package/src/components/resources/views/list-view.tsx +20 -10
  54. package/src/components/resources/views/show-view.tsx +20 -18
  55. package/src/index.tsx +2 -3
  56. package/src/lib/i18n.ts +161 -0
  57. package/src/lib/nocobase/client.ts +19 -2
  58. package/src/locales/en-US.ts +82 -0
  59. package/src/locales/index.ts +13 -0
  60. package/src/locales/zh-CN.ts +79 -0
  61. package/src/pages/users/create.tsx +98 -0
  62. package/src/pages/users/edit.tsx +92 -0
  63. package/src/pages/users/form-context.ts +57 -0
  64. package/src/pages/users/form-fields.tsx +211 -0
  65. package/src/pages/users/list.tsx +205 -0
  66. package/src/pages/users/show.tsx +187 -0
  67. package/src/pages/users/types.ts +20 -0
  68. package/src/providers/constants.ts +1 -0
  69. package/src/pages/blog-posts/create.tsx +0 -177
  70. package/src/pages/blog-posts/edit.tsx +0 -197
  71. package/src/pages/blog-posts/list.tsx +0 -131
  72. package/src/pages/blog-posts/show.tsx +0 -81
  73. package/src/pages/categories/create.tsx +0 -73
  74. package/src/pages/categories/edit.tsx +0 -73
  75. package/src/pages/categories/index.ts +0 -4
  76. package/src/pages/categories/list.tsx +0 -86
  77. package/src/pages/categories/show.tsx +0 -37
  78. /package/src/pages/{blog-posts → users}/index.ts +0 -0
@@ -1,131 +0,0 @@
1
- import { useTable } from "@refinedev/react-table";
2
- import { createColumnHelper } from "@tanstack/react-table";
3
- import { Eye, Pencil, Trash2 } from "lucide-react";
4
- import React from "react";
5
-
6
- import { DataTable } from "@/components/data-table/data-table";
7
- import { StatusBadge } from "@/components/resources/status-badge";
8
- import { ListView } from "@/components/resources/views/list-view";
9
- import { EditButton } from "@/components/resources/buttons/edit";
10
- import { ShowButton } from "@/components/resources/buttons/show";
11
- import { DeleteButton } from "@/components/resources/buttons/delete";
12
-
13
- type BlogPost = {
14
- id: string;
15
- title: string;
16
- content: string;
17
- status: string;
18
- createdAt: string;
19
- category: { id: string; title: string };
20
- };
21
-
22
- export const BlogPostList = () => {
23
- const columns = React.useMemo(() => {
24
- const columnHelper = createColumnHelper<BlogPost>();
25
-
26
- return [
27
- columnHelper.accessor("id", {
28
- id: "id",
29
- header: "ID",
30
- enableSorting: false,
31
- }),
32
- columnHelper.accessor("title", {
33
- id: "title",
34
- header: "Title",
35
- enableSorting: true,
36
- }),
37
- columnHelper.accessor("content", {
38
- id: "content",
39
- header: "Content",
40
- enableSorting: false,
41
- cell: ({ getValue }) => {
42
- const content = getValue();
43
- if (!content) return "-";
44
- return (
45
- <div className="max-w-xs truncate">{content.slice(0, 80)}...</div>
46
- );
47
- },
48
- }),
49
- columnHelper.accessor("category.title", {
50
- id: "category",
51
- header: "Category",
52
- enableSorting: false,
53
- cell: ({ row }) => {
54
- return row.original.category?.title || "-";
55
- },
56
- }),
57
- columnHelper.accessor("status", {
58
- id: "status",
59
- header: "Status",
60
- enableSorting: true,
61
- cell: ({ getValue }) => {
62
- const status = getValue();
63
- return <StatusBadge status={status} />;
64
- },
65
- }),
66
- columnHelper.accessor("createdAt", {
67
- id: "createdAt",
68
- header: "Created At",
69
- enableSorting: true,
70
- cell: ({ getValue }) => {
71
- const date = getValue();
72
- return date ? new Date(date).toLocaleDateString() : "-";
73
- },
74
- }),
75
- columnHelper.display({
76
- id: "actions",
77
- header: "Actions",
78
- cell: ({ row }) => (
79
- <div className="flex items-center gap-1">
80
- <EditButton
81
- recordItemId={row.original.id}
82
- variant="ghost"
83
- size="icon"
84
- aria-label="Edit post"
85
- title="Edit"
86
- >
87
- <Pencil />
88
- </EditButton>
89
- <ShowButton
90
- recordItemId={row.original.id}
91
- variant="ghost"
92
- size="icon"
93
- aria-label="View post"
94
- title="View"
95
- >
96
- <Eye />
97
- </ShowButton>
98
- <DeleteButton
99
- recordItemId={row.original.id}
100
- variant="ghost"
101
- size="icon"
102
- className="text-destructive hover:text-destructive"
103
- aria-label="Delete post"
104
- title="Delete"
105
- >
106
- <Trash2 />
107
- </DeleteButton>
108
- </div>
109
- ),
110
- enableSorting: false,
111
- size: 144,
112
- }),
113
- ];
114
- }, []);
115
-
116
- const table = useTable({
117
- columns,
118
- refineCoreProps: {
119
- syncWithLocation: true,
120
- meta: {
121
- appends: ["category"],
122
- },
123
- },
124
- });
125
-
126
- return (
127
- <ListView>
128
- <DataTable table={table} />
129
- </ListView>
130
- );
131
- };
@@ -1,81 +0,0 @@
1
- import { useOne, useShow } from "@refinedev/core";
2
- import React from "react";
3
-
4
- import { ShowView } from "@/components/resources/views/show-view";
5
- import { StatusBadge } from "@/components/resources/status-badge";
6
- import {
7
- Card,
8
- CardContent,
9
- CardDescription,
10
- CardHeader,
11
- CardTitle,
12
- } from "@/components/ui/card";
13
- import { Separator } from "@/components/ui/separator";
14
-
15
- export const BlogPostShow = () => {
16
- const { result: record, query } = useShow({});
17
-
18
- const {
19
- result: category,
20
- query: { isLoading: categoryIsLoading },
21
- } = useOne({
22
- resource: "categories",
23
- id: record?.category?.id || "",
24
- queryOptions: {
25
- enabled: !!record,
26
- },
27
- });
28
- const { isLoading } = query;
29
-
30
- return (
31
- <ShowView>
32
- <div className="max-w-4xl space-y-6">
33
- <Card className="resource-detail-card">
34
- <CardHeader>
35
- <CardTitle>{record?.title}</CardTitle>
36
- <CardDescription>
37
- <div className="flex items-center gap-4">
38
- <StatusBadge status={record?.status} />
39
- <span className="text-sm text-muted-foreground">
40
- ID: {record?.id}
41
- </span>
42
- </div>
43
- </CardDescription>
44
- </CardHeader>
45
- <CardContent className="space-y-4">
46
- <div>
47
- <h4 className="text-sm font-medium mb-2">Category</h4>
48
- <p className="text-sm text-muted-foreground">
49
- {categoryIsLoading ? "Loading..." : category?.title || "-"}
50
- </p>
51
- </div>
52
-
53
- <Separator />
54
-
55
- <div>
56
- <h4 className="text-sm font-medium mb-2">Created At</h4>
57
- <p className="text-sm text-muted-foreground">
58
- {record?.createdAt
59
- ? new Date(record.createdAt).toLocaleDateString()
60
- : "-"}
61
- </p>
62
- </div>
63
-
64
- <Separator />
65
-
66
- <div>
67
- <h4 className="text-sm font-medium mb-4">Content</h4>
68
- <div className="prose prose-sm max-w-none">
69
- {record?.content ? (
70
- <div dangerouslySetInnerHTML={{ __html: record.content }} />
71
- ) : (
72
- <p className="text-muted-foreground">No content available</p>
73
- )}
74
- </div>
75
- </div>
76
- </CardContent>
77
- </Card>
78
- </div>
79
- </ShowView>
80
- );
81
- };
@@ -1,73 +0,0 @@
1
- import { useForm } from "@refinedev/react-hook-form";
2
- import { useNavigate } from "react-router";
3
-
4
- import { CreateView } from "@/components/resources/views/create-view";
5
- import { Button } from "@/components/ui/button";
6
- import { Input } from "@/components/ui/input";
7
- import {
8
- Form,
9
- FormControl,
10
- FormField,
11
- FormItem,
12
- FormLabel,
13
- FormMessage,
14
- } from "@/components/ui/form";
15
-
16
- export const CategoryCreate = () => {
17
- const navigate = useNavigate();
18
-
19
- const {
20
- refineCore: { onFinish },
21
- ...form
22
- } = useForm({
23
- refineCoreProps: {},
24
- });
25
-
26
- function onSubmit(values: Record<string, string>) {
27
- onFinish(values);
28
- }
29
-
30
- return (
31
- <CreateView>
32
- <Form {...form}>
33
- <form onSubmit={form.handleSubmit(onSubmit)} className="resource-form">
34
- <FormField
35
- control={form.control}
36
- name="title"
37
- rules={{ required: "Title is required" }}
38
- render={({ field }) => (
39
- <FormItem>
40
- <FormLabel>Title</FormLabel>
41
- <FormControl
42
- render={<Input
43
- {...field}
44
- value={field.value || ""}
45
- placeholder="Enter category title"
46
- />}
47
- />
48
- <FormMessage />
49
- </FormItem>
50
- )}
51
- />
52
-
53
- <div className="flex gap-2">
54
- <Button
55
- type="submit"
56
- {...form.saveButtonProps}
57
- disabled={form.formState.isSubmitting}
58
- >
59
- {form.formState.isSubmitting ? "Creating..." : "Create"}
60
- </Button>
61
- <Button
62
- type="button"
63
- variant="outline"
64
- onClick={() => navigate(-1)}
65
- >
66
- Cancel
67
- </Button>
68
- </div>
69
- </form>
70
- </Form>
71
- </CreateView>
72
- );
73
- };
@@ -1,73 +0,0 @@
1
- import { useForm } from "@refinedev/react-hook-form";
2
- import { useNavigate } from "react-router";
3
-
4
- import { EditView } from "@/components/resources/views/edit-view";
5
- import { Button } from "@/components/ui/button";
6
- import { Input } from "@/components/ui/input";
7
- import {
8
- Form,
9
- FormControl,
10
- FormField,
11
- FormItem,
12
- FormLabel,
13
- FormMessage,
14
- } from "@/components/ui/form";
15
-
16
- export const CategoryEdit = () => {
17
- const navigate = useNavigate();
18
-
19
- const {
20
- refineCore: { onFinish },
21
- ...form
22
- } = useForm({
23
- refineCoreProps: {},
24
- });
25
-
26
- function onSubmit(values: Record<string, string>) {
27
- onFinish(values);
28
- }
29
-
30
- return (
31
- <EditView>
32
- <Form {...form}>
33
- <form onSubmit={form.handleSubmit(onSubmit)} className="resource-form">
34
- <FormField
35
- control={form.control}
36
- name="title"
37
- rules={{ required: "Title is required" }}
38
- render={({ field }) => (
39
- <FormItem>
40
- <FormLabel>Title</FormLabel>
41
- <FormControl
42
- render={<Input
43
- {...field}
44
- value={field.value || ""}
45
- placeholder="Enter category title"
46
- />}
47
- />
48
- <FormMessage />
49
- </FormItem>
50
- )}
51
- />
52
-
53
- <div className="flex gap-2">
54
- <Button
55
- type="submit"
56
- {...form.saveButtonProps}
57
- disabled={form.formState.isSubmitting}
58
- >
59
- {form.formState.isSubmitting ? "Updating..." : "Update"}
60
- </Button>
61
- <Button
62
- type="button"
63
- variant="outline"
64
- onClick={() => navigate(-1)}
65
- >
66
- Cancel
67
- </Button>
68
- </div>
69
- </form>
70
- </Form>
71
- </EditView>
72
- );
73
- };
@@ -1,4 +0,0 @@
1
- export * from "./create";
2
- export * from "./edit";
3
- export * from "./list";
4
- export * from "./show";
@@ -1,86 +0,0 @@
1
- import { type BaseRecord } from "@refinedev/core";
2
- import { useTable } from "@refinedev/react-table";
3
- import { createColumnHelper } from "@tanstack/react-table";
4
- import { Eye, Pencil, Trash2 } from "lucide-react";
5
- import React from "react";
6
-
7
- import { DataTable } from "@/components/data-table/data-table";
8
- import { ListView } from "@/components/resources/views/list-view";
9
- import { EditButton } from "@/components/resources/buttons/edit";
10
- import { ShowButton } from "@/components/resources/buttons/show";
11
- import { DeleteButton } from "@/components/resources/buttons/delete";
12
-
13
- type Category = {
14
- id: string;
15
- title: string;
16
- };
17
-
18
- export const CategoryList = () => {
19
- const columns = React.useMemo(() => {
20
- const columnHelper = createColumnHelper<Category>();
21
-
22
- return [
23
- columnHelper.accessor("id", {
24
- id: "id",
25
- header: "ID",
26
- enableSorting: false,
27
- }),
28
- columnHelper.accessor("title", {
29
- id: "title",
30
- header: "Title",
31
- enableSorting: true,
32
- }),
33
- columnHelper.display({
34
- id: "actions",
35
- header: "Actions",
36
- cell: ({ row }) => (
37
- <div className="flex items-center gap-1">
38
- <EditButton
39
- recordItemId={row.original.id}
40
- variant="ghost"
41
- size="icon"
42
- aria-label="Edit category"
43
- title="Edit"
44
- >
45
- <Pencil />
46
- </EditButton>
47
- <ShowButton
48
- recordItemId={row.original.id}
49
- variant="ghost"
50
- size="icon"
51
- aria-label="View category"
52
- title="View"
53
- >
54
- <Eye />
55
- </ShowButton>
56
- <DeleteButton
57
- recordItemId={row.original.id}
58
- variant="ghost"
59
- size="icon"
60
- className="text-destructive hover:text-destructive"
61
- aria-label="Delete category"
62
- title="Delete"
63
- >
64
- <Trash2 />
65
- </DeleteButton>
66
- </div>
67
- ),
68
- enableSorting: false,
69
- size: 144,
70
- }),
71
- ];
72
- }, []);
73
-
74
- const table = useTable({
75
- columns,
76
- refineCoreProps: {
77
- syncWithLocation: true,
78
- },
79
- });
80
-
81
- return (
82
- <ListView>
83
- <DataTable table={table} />
84
- </ListView>
85
- );
86
- };
@@ -1,37 +0,0 @@
1
- import { useShow } from "@refinedev/core";
2
- import React from "react";
3
-
4
- import { ShowView } from "@/components/resources/views/show-view";
5
- import {
6
- Card,
7
- CardContent,
8
- CardDescription,
9
- CardHeader,
10
- CardTitle,
11
- } from "@/components/ui/card";
12
-
13
- export const CategoryShow = () => {
14
- const { result: record, query } = useShow({});
15
- const { isLoading } = query;
16
-
17
- return (
18
- <ShowView>
19
- <Card className="resource-detail-card max-w-3xl">
20
- <CardHeader>
21
- <CardTitle>{record?.title}</CardTitle>
22
- <CardDescription>Category ID: {record?.id}</CardDescription>
23
- </CardHeader>
24
- <CardContent>
25
- <div className="space-y-4">
26
- <div>
27
- <h4 className="text-sm font-medium mb-2">Title</h4>
28
- <p className="text-sm text-muted-foreground">
29
- {record?.title || "-"}
30
- </p>
31
- </div>
32
- </div>
33
- </CardContent>
34
- </Card>
35
- </ShowView>
36
- );
37
- };
File without changes