@nocobase/portal-template-default 1.0.0 → 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 (194) hide show
  1. package/README.MD +90 -1
  2. package/components.json +3 -1
  3. package/package.json +21 -5
  4. package/registry/nocobase-acl/README.md +19 -0
  5. package/registry/nocobase-acl/components/acl-boundary.tsx +106 -0
  6. package/registry/nocobase-acl/components/index.ts +3 -0
  7. package/registry/nocobase-acl/components/role-options.ts +36 -0
  8. package/registry/nocobase-acl/components/role-switcher.tsx +135 -0
  9. package/registry/nocobase-acl/demo/boundary-api.tsx +186 -0
  10. package/registry/nocobase-acl/demo/components.tsx +231 -0
  11. package/registry/nocobase-acl/demo/index.tsx +505 -0
  12. package/registry/nocobase-acl/demo/lazy-route.tsx +10 -0
  13. package/registry/nocobase-acl/demo/prompt-generator.tsx +134 -0
  14. package/registry/nocobase-acl/demo/role-switcher-prompt-generator.tsx +198 -0
  15. package/registry/nocobase-acl/demo/scenario-section.tsx +37 -0
  16. package/registry/nocobase-acl/extension.tsx +71 -0
  17. package/registry/nocobase-acl/index.ts +1 -0
  18. package/registry/nocobase-acl/tests/acl-regression.mjs +314 -0
  19. package/registry/nocobase-ai/README.md +70 -0
  20. package/registry/nocobase-ai/adapters/react-hook-form.ts +20 -0
  21. package/registry/nocobase-ai/assets/nocobase-ai-chat.svg +50 -0
  22. package/registry/nocobase-ai/components/ai-root-provider.tsx +32 -0
  23. package/registry/nocobase-ai/components/chat/ai-employee-avatar.tsx +31 -0
  24. package/registry/nocobase-ai/components/chat/chat-attachment.tsx +92 -0
  25. package/registry/nocobase-ai/components/chat/chat-compact.tsx +90 -0
  26. package/registry/nocobase-ai/components/chat/chat-composer.tsx +429 -0
  27. package/registry/nocobase-ai/components/chat/chat-empty-state.tsx +51 -0
  28. package/registry/nocobase-ai/components/chat/chat-header.tsx +88 -0
  29. package/registry/nocobase-ai/components/chat/chat-history-dialog.tsx +77 -0
  30. package/registry/nocobase-ai/components/chat/chat-message.tsx +252 -0
  31. package/registry/nocobase-ai/components/chat/chat-messages.tsx +173 -0
  32. package/registry/nocobase-ai/components/chat/chat-window.tsx +118 -0
  33. package/registry/nocobase-ai/components/chat/conversation-list.tsx +343 -0
  34. package/registry/nocobase-ai/components/chat/markdown-message.tsx +165 -0
  35. package/registry/nocobase-ai/components/chat/model-select-options.tsx +30 -0
  36. package/registry/nocobase-ai/components/chat/reasoning-panel.tsx +29 -0
  37. package/registry/nocobase-ai/components/chat/sub-agent-conversation.tsx +142 -0
  38. package/registry/nocobase-ai/components/chat/tool-call-card.tsx +316 -0
  39. package/registry/nocobase-ai/components/chat/user-prompt-editor.tsx +99 -0
  40. package/registry/nocobase-ai/components/chat/work-context-chip.tsx +114 -0
  41. package/registry/nocobase-ai/components/index.ts +59 -0
  42. package/registry/nocobase-ai/components/page-elements/ai-form.tsx +44 -0
  43. package/registry/nocobase-ai/components/page-elements/page-element-provider.tsx +469 -0
  44. package/registry/nocobase-ai/components/surfaces/chat-dialog.tsx +31 -0
  45. package/registry/nocobase-ai/components/surfaces/chat-inline.tsx +18 -0
  46. package/registry/nocobase-ai/components/surfaces/chat-page.tsx +18 -0
  47. package/registry/nocobase-ai/components/surfaces/chat-side-panel-layout.tsx +54 -0
  48. package/registry/nocobase-ai/components/surfaces/chat-side-panel.tsx +74 -0
  49. package/registry/nocobase-ai/components/surfaces/chat-surface-actions.tsx +54 -0
  50. package/registry/nocobase-ai/components/tools/builtin-tool-renderers.tsx +31 -0
  51. package/registry/nocobase-ai/components/tools/business-report-dialog.tsx +364 -0
  52. package/registry/nocobase-ai/components/tools/business-report-renderer.tsx +122 -0
  53. package/registry/nocobase-ai/components/tools/business-report-utils.tsx +282 -0
  54. package/registry/nocobase-ai/components/tools/chart-renderer.tsx +99 -0
  55. package/registry/nocobase-ai/components/tools/echarts-preview.tsx +59 -0
  56. package/registry/nocobase-ai/components/tools/echarts-runtime-advanced.ts +18 -0
  57. package/registry/nocobase-ai/components/tools/echarts-runtime-common.ts +20 -0
  58. package/registry/nocobase-ai/components/tools/echarts-runtime-components.ts +34 -0
  59. package/registry/nocobase-ai/components/tools/echarts-runtime-hierarchy.ts +24 -0
  60. package/registry/nocobase-ai/components/tools/echarts-runtime.ts +138 -0
  61. package/registry/nocobase-ai/components/tools/sub-agent-renderer.tsx +67 -0
  62. package/registry/nocobase-ai/components/tools/suggestions-renderer.tsx +59 -0
  63. package/registry/nocobase-ai/components/tools/tool-renderer-provider.tsx +55 -0
  64. package/registry/nocobase-ai/components/tools/tool-renderer-utils.ts +18 -0
  65. package/registry/nocobase-ai/components/tools/workflow-renderer.tsx +108 -0
  66. package/registry/nocobase-ai/components/triggers/ai-chat-floating-trigger.tsx +73 -0
  67. package/registry/nocobase-ai/components/triggers/ai-employee-shortcut.tsx +149 -0
  68. package/registry/nocobase-ai/demo/configuration-gate.tsx +49 -0
  69. package/registry/nocobase-ai/demo/container-showcase.tsx +210 -0
  70. package/registry/nocobase-ai/demo/floating.tsx +134 -0
  71. package/registry/nocobase-ai/demo/index.tsx +346 -0
  72. package/registry/nocobase-ai/demo/interaction-showcase.tsx +151 -0
  73. package/registry/nocobase-ai/demo/page-context-prompt-generator.tsx +355 -0
  74. package/registry/nocobase-ai/demo/page-context.tsx +884 -0
  75. package/registry/nocobase-ai/demo/page-element-showcase.tsx +197 -0
  76. package/registry/nocobase-ai/demo/prompt-card.tsx +41 -0
  77. package/registry/nocobase-ai/demo/prompt-generator.tsx +452 -0
  78. package/registry/nocobase-ai/demo/shortcut.tsx +1207 -0
  79. package/registry/nocobase-ai/demo/tool-cards.tsx +530 -0
  80. package/registry/nocobase-ai/extension.tsx +158 -0
  81. package/registry/nocobase-ai/global-ai-chat.tsx +213 -0
  82. package/registry/nocobase-ai/index.ts +3 -0
  83. package/registry/nocobase-ai/providers/ai-provider.tsx +323 -0
  84. package/registry/nocobase-ai/providers/avatars.ts +817 -0
  85. package/registry/nocobase-ai/providers/chat-context.tsx +109 -0
  86. package/registry/nocobase-ai/providers/chat-controller.ts +84 -0
  87. package/registry/nocobase-ai/providers/chat-message-utils.ts +198 -0
  88. package/registry/nocobase-ai/providers/chat-provider.tsx +871 -0
  89. package/registry/nocobase-ai/providers/chat-reducer.ts +147 -0
  90. package/registry/nocobase-ai/providers/chat-task-utils.ts +105 -0
  91. package/registry/nocobase-ai/providers/chat-transport.ts +184 -0
  92. package/registry/nocobase-ai/providers/form-registry.tsx +271 -0
  93. package/registry/nocobase-ai/providers/frontend-tool-registry.tsx +231 -0
  94. package/registry/nocobase-ai/providers/index.ts +61 -0
  95. package/registry/nocobase-ai/providers/model.ts +32 -0
  96. package/registry/nocobase-ai/providers/page-context.tsx +136 -0
  97. package/registry/nocobase-ai/providers/stream-coalescer.ts +60 -0
  98. package/registry/nocobase-ai/providers/stream-event-utils.ts +82 -0
  99. package/registry/nocobase-ai/providers/stream-parser.ts +61 -0
  100. package/registry/nocobase-ai/providers/sub-agent-stream.ts +316 -0
  101. package/registry/nocobase-ai/providers/types.ts +183 -0
  102. package/registry/nocobase-ai/providers/ui-message-stream.ts +463 -0
  103. package/registry/nocobase-ai/providers/use-automatic-tool-approval.ts +94 -0
  104. package/registry/nocobase-ai/providers/use-chat-attachments.ts +206 -0
  105. package/registry/nocobase-ai/providers/use-chat-message-actions.ts +554 -0
  106. package/registry/nocobase-ai/providers/use-chat-runtime.ts +210 -0
  107. package/registry/nocobase-ai/providers/use-chat-work-context.ts +93 -0
  108. package/registry/nocobase-ai/providers/use-conversation-catalog.ts +108 -0
  109. package/registry/nocobase-ai/providers/use-conversation-history.ts +178 -0
  110. package/registry/nocobase-ai/services/index.ts +7 -0
  111. package/registry/nocobase-ai/services/nocobase-ai-service.ts +454 -0
  112. package/registry/nocobase-ai/services/types.ts +82 -0
  113. package/registry/nocobase-ai/tests/business-report-regression.mjs +70 -0
  114. package/registry/nocobase-ai/tests/form-filler-regression.mjs +129 -0
  115. package/registry/nocobase-ai/tests/frontend-tool-regression.mjs +128 -0
  116. package/registry/nocobase-ai/tests/page-context-regression.mjs +48 -0
  117. package/registry/nocobase-ai/tests/stream-regression.mjs +207 -0
  118. package/registry/nocobase-i18n/README.md +53 -0
  119. package/registry/nocobase-i18n/components/index.ts +1 -0
  120. package/registry/nocobase-i18n/components/language-switcher.tsx +138 -0
  121. package/registry/nocobase-i18n/demo/index.tsx +209 -0
  122. package/registry/nocobase-i18n/demo/prompt-generator.tsx +155 -0
  123. package/registry/nocobase-i18n/extension.tsx +46 -0
  124. package/registry/nocobase-i18n/i18n-provider.ts +9 -0
  125. package/registry/nocobase-i18n/index.ts +6 -0
  126. package/registry/nocobase-i18n/locale-store.ts +134 -0
  127. package/registry/nocobase-i18n/locales/en-US.ts +89 -0
  128. package/registry/nocobase-i18n/locales/zh-CN.ts +85 -0
  129. package/registry/nocobase-i18n/provider.tsx +32 -0
  130. package/registry/nocobase-i18n/runtime.ts +118 -0
  131. package/registry/nocobase-i18n/server-resources.ts +184 -0
  132. package/registry/nocobase-i18n/tests/i18n-regression.mjs +42 -0
  133. package/registry.config.json +163 -0
  134. package/scripts/registry.mjs +164 -0
  135. package/src/App.css +95 -0
  136. package/src/App.tsx +87 -69
  137. package/src/app/extension.ts +11 -0
  138. package/src/app/extensions.tsx +49 -0
  139. package/src/components/access-control/access-denied.tsx +30 -0
  140. package/src/components/access-control/acl-bootstrap.tsx +9 -0
  141. package/src/components/access-control/acl-gate.tsx +36 -0
  142. package/src/components/access-control/navigate-to-accessible-resource.tsx +17 -0
  143. package/src/components/access-control/resource-access-guard.tsx +21 -0
  144. package/src/components/access-control/use-acl-runtime.ts +28 -0
  145. package/src/components/app-shell/breadcrumb.tsx +39 -3
  146. package/src/components/app-shell/document-title-handler.tsx +11 -20
  147. package/src/components/app-shell/header.tsx +22 -4
  148. package/src/components/app-shell/loading-overlay.tsx +2 -4
  149. package/src/components/app-shell/loading-state.tsx +15 -0
  150. package/src/components/app-shell/sidebar.tsx +103 -45
  151. package/src/components/data-table/data-table-pagination.tsx +27 -7
  152. package/src/components/data-table/data-table-styles.ts +57 -0
  153. package/src/components/data-table/data-table.tsx +14 -59
  154. package/src/components/resources/resource-label.ts +101 -0
  155. package/src/components/resources/views/create-view.tsx +17 -14
  156. package/src/components/resources/views/edit-view.tsx +17 -15
  157. package/src/components/resources/views/list-view.tsx +20 -10
  158. package/src/components/resources/views/show-view.tsx +20 -18
  159. package/src/index.tsx +2 -3
  160. package/src/lib/i18n.ts +161 -0
  161. package/src/lib/nocobase/acl/action.ts +147 -0
  162. package/src/lib/nocobase/acl/data-source.ts +24 -0
  163. package/src/lib/nocobase/acl/index.ts +6 -0
  164. package/src/lib/nocobase/acl/menu.ts +41 -0
  165. package/src/lib/nocobase/acl/record-permissions.ts +111 -0
  166. package/src/lib/nocobase/acl/store.ts +182 -0
  167. package/src/lib/nocobase/acl/types.ts +96 -0
  168. package/src/lib/nocobase/client.ts +279 -0
  169. package/src/lib/nocobase/error.ts +32 -0
  170. package/src/locales/en-US.ts +82 -0
  171. package/src/locales/index.ts +13 -0
  172. package/src/locales/zh-CN.ts +79 -0
  173. package/src/pages/users/create.tsx +98 -0
  174. package/src/pages/users/edit.tsx +92 -0
  175. package/src/pages/users/form-context.ts +57 -0
  176. package/src/pages/users/form-fields.tsx +211 -0
  177. package/src/pages/users/list.tsx +205 -0
  178. package/src/pages/users/show.tsx +187 -0
  179. package/src/pages/users/types.ts +20 -0
  180. package/src/providers/access-control.ts +34 -0
  181. package/src/providers/auth.ts +74 -60
  182. package/src/providers/constants.ts +3 -37
  183. package/src/providers/data.ts +242 -85
  184. package/vite.config.ts +17 -0
  185. package/src/pages/blog-posts/create.tsx +0 -177
  186. package/src/pages/blog-posts/edit.tsx +0 -197
  187. package/src/pages/blog-posts/list.tsx +0 -131
  188. package/src/pages/blog-posts/show.tsx +0 -81
  189. package/src/pages/categories/create.tsx +0 -73
  190. package/src/pages/categories/edit.tsx +0 -73
  191. package/src/pages/categories/index.ts +0 -4
  192. package/src/pages/categories/list.tsx +0 -86
  193. package/src/pages/categories/show.tsx +0 -37
  194. /package/src/pages/{blog-posts → users}/index.ts +0 -0
@@ -1,197 +0,0 @@
1
- import { useForm } from "@refinedev/react-hook-form";
2
- import { useSelect } from "@refinedev/core";
3
- import { useEffect } from "react";
4
- import { useNavigate } from "react-router";
5
- import { Textarea } from "@/components/ui/textarea";
6
-
7
- import { EditView } from "@/components/resources/views/edit-view";
8
- import { Button } from "@/components/ui/button";
9
- import { Input } from "@/components/ui/input";
10
- import {
11
- Select,
12
- SelectContent,
13
- SelectItem,
14
- SelectTrigger,
15
- SelectValue,
16
- } from "@/components/ui/select";
17
- import {
18
- Form,
19
- FormControl,
20
- FormField,
21
- FormItem,
22
- FormLabel,
23
- FormMessage,
24
- } from "@/components/ui/form";
25
-
26
- export const BlogPostEdit = () => {
27
- const navigate = useNavigate();
28
-
29
- const {
30
- refineCore: { onFinish, query },
31
- ...form
32
- } = useForm({
33
- refineCoreProps: {
34
- meta: {
35
- appends: ["category"],
36
- },
37
- },
38
- });
39
-
40
- const blogPostsData = query?.data?.data;
41
- const defaultCategoryId =
42
- blogPostsData?.categoryId ?? blogPostsData?.category?.id;
43
-
44
- useEffect(() => {
45
- if (defaultCategoryId != null && !form.getValues("categoryId")) {
46
- form.setValue("categoryId", defaultCategoryId.toString(), {
47
- shouldDirty: false,
48
- });
49
- }
50
- }, [defaultCategoryId, form]);
51
-
52
- const { options: categoryOptions } = useSelect({
53
- resource: "categories",
54
- defaultValue: defaultCategoryId?.toString(),
55
- optionLabel: "title",
56
- optionValue: "id",
57
- pagination: {
58
- currentPage: 1,
59
- pageSize: 100,
60
- },
61
- });
62
-
63
- function onSubmit(values: Record<string, string>) {
64
- onFinish(values);
65
- }
66
-
67
- return (
68
- <EditView>
69
- <Form {...form}>
70
- <form onSubmit={form.handleSubmit(onSubmit)} className="resource-form">
71
- <FormField
72
- control={form.control}
73
- name="title"
74
- rules={{ required: "Title is required" }}
75
- render={({ field }) => (
76
- <FormItem>
77
- <FormLabel>Title</FormLabel>
78
- <FormControl
79
- render={<Input
80
- {...field}
81
- value={field.value || ""}
82
- placeholder="Enter title"
83
- />}
84
- />
85
- <FormMessage />
86
- </FormItem>
87
- )}
88
- />
89
-
90
- <FormField
91
- control={form.control}
92
- name="content"
93
- rules={{ required: "Content is required" }}
94
- render={({ field }) => (
95
- <FormItem>
96
- <FormLabel>Content</FormLabel>
97
- <FormControl
98
- render={<Textarea
99
- {...field}
100
- value={field.value || ""}
101
- placeholder="Enter content"
102
- rows={10}
103
- />}
104
- />
105
- <FormMessage />
106
- </FormItem>
107
- )}
108
- />
109
-
110
- <FormField
111
- control={form.control}
112
- name="categoryId"
113
- rules={{ required: "Category is required" }}
114
- render={({ field }) => {
115
- const selectedCategoryId = field.value ?? defaultCategoryId;
116
-
117
- return <FormItem>
118
- <FormLabel>Category</FormLabel>
119
- <Select
120
- items={categoryOptions?.map((option) => ({
121
- label: option.label,
122
- value: option.value.toString(),
123
- }))}
124
- onValueChange={field.onChange}
125
- value={selectedCategoryId?.toString() || ""}
126
- >
127
- <FormControl
128
- render={<SelectTrigger>
129
- <SelectValue placeholder="Select a category" />
130
- </SelectTrigger>}
131
- />
132
- <SelectContent>
133
- {categoryOptions?.map((option) => (
134
- <SelectItem key={option.value} value={option.value.toString()}>
135
- {option.label}
136
- </SelectItem>
137
- ))}
138
- </SelectContent>
139
- </Select>
140
- <FormMessage />
141
- </FormItem>;
142
- }}
143
- />
144
-
145
- <FormField
146
- control={form.control}
147
- name="status"
148
- rules={{ required: "Status is required" }}
149
- render={({ field }) => (
150
- <FormItem>
151
- <FormLabel>Status</FormLabel>
152
- <Select
153
- items={{
154
- draft: "Draft",
155
- published: "Published",
156
- rejected: "Rejected",
157
- }}
158
- onValueChange={field.onChange}
159
- value={field.value || ""}
160
- >
161
- <FormControl
162
- render={<SelectTrigger>
163
- <SelectValue placeholder="Select status" />
164
- </SelectTrigger>}
165
- />
166
- <SelectContent>
167
- <SelectItem value="draft">Draft</SelectItem>
168
- <SelectItem value="published">Published</SelectItem>
169
- <SelectItem value="rejected">Rejected</SelectItem>
170
- </SelectContent>
171
- </Select>
172
- <FormMessage />
173
- </FormItem>
174
- )}
175
- />
176
-
177
- <div className="flex gap-2">
178
- <Button
179
- type="submit"
180
- {...form.saveButtonProps}
181
- disabled={form.formState.isSubmitting}
182
- >
183
- {form.formState.isSubmitting ? "Updating..." : "Update"}
184
- </Button>
185
- <Button
186
- type="button"
187
- variant="outline"
188
- onClick={() => navigate(-1)}
189
- >
190
- Cancel
191
- </Button>
192
- </div>
193
- </form>
194
- </Form>
195
- </EditView>
196
- );
197
- };
@@ -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