create-cundi-app 1.0.1 → 1.0.3
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 +40 -31
- package/index.js +7 -1
- package/package.json +4 -1
- package/template/package.json.template +1 -1
- package/template/src/App.tsx +114 -110
- package/template/vite.config.ts +11 -0
- package/template/src/contexts/color-mode/index.tsx +0 -2
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# create-cundi-app
|
|
2
2
|
|
|
3
|
-
Create a new Cundi
|
|
3
|
+
Create a new Cundi web application with React + Refine + Ant Design.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/create-cundi-app)
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
10
|
# Using npm
|
|
@@ -22,48 +24,55 @@ pnpm create cundi-app my-app
|
|
|
22
24
|
|
|
23
25
|
The generated project includes:
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
| Category | Technology |
|
|
28
|
+
|----------|------------|
|
|
29
|
+
| Framework | React 19 + TypeScript |
|
|
30
|
+
| Build Tool | Vite |
|
|
31
|
+
| UI Library | Ant Design |
|
|
32
|
+
| Metasystem | [Refine](https://refine.dev/) |
|
|
33
|
+
| Core SDK | [@cundi/refine-xaf](https://www.npmjs.com/package/@cundi/refine-xaf) |
|
|
30
34
|
|
|
31
35
|
### Features
|
|
32
36
|
|
|
33
|
-
- 🔐 Authentication
|
|
34
|
-
- 👤 User Management
|
|
35
|
-
- 🛡️ Role-based Access Control
|
|
36
|
-
- 🌍
|
|
37
|
-
- 🌙 Dark Mode
|
|
38
|
-
- 📊 Dashboard
|
|
37
|
+
- 🔐 **Dual Authentication**: Local login + Keycloak SSO
|
|
38
|
+
- 👤 **User Management**: Pre-built user CRUD pages
|
|
39
|
+
- 🛡️ **RBAC**: Role-based Access Control
|
|
40
|
+
- 🌍 **i18n**: English and Traditional Chinese
|
|
41
|
+
- 🌙 **Dark Mode**: Theme toggle support
|
|
42
|
+
- 📊 **Dashboard**: Starter template
|
|
39
43
|
|
|
40
44
|
## After Creating
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
```bash
|
|
47
|
+
cd my-app
|
|
48
|
+
npm install
|
|
49
|
+
cp .env.example .env # Configure your API URL
|
|
50
|
+
npm run dev
|
|
51
|
+
```
|
|
46
52
|
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
npm install
|
|
50
|
-
```
|
|
53
|
+
### Environment Variables
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
cp .env.example .env
|
|
55
|
-
# Edit .env with your API URL and Keycloak settings
|
|
56
|
-
```
|
|
55
|
+
Edit `.env` to configure:
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
```env
|
|
58
|
+
VITE_API_URL=http://localhost:5000/api
|
|
59
|
+
|
|
60
|
+
# Keycloak (Optional)
|
|
61
|
+
VITE_KEYCLOAK_URL=http://localhost:8080
|
|
62
|
+
VITE_KEYCLOAK_REALM=your-realm
|
|
63
|
+
VITE_KEYCLOAK_CLIENT_ID=your-client-id
|
|
64
|
+
VITE_REDIRECT_URI=http://localhost:5173/auth/callback
|
|
65
|
+
```
|
|
62
66
|
|
|
63
67
|
## Documentation
|
|
64
68
|
|
|
65
|
-
- [
|
|
69
|
+
- [Cundi Development Guide](https://github.com/antonylu0826/Cundi/blob/main/Development_Guide.md)
|
|
66
70
|
- [@cundi/refine-xaf SDK](https://www.npmjs.com/package/@cundi/refine-xaf)
|
|
71
|
+
- [Refine Documentation](https://refine.dev/docs/)
|
|
72
|
+
|
|
73
|
+
## Related
|
|
74
|
+
|
|
75
|
+
- [cundiapi](https://www.nuget.org/packages/Cundi.Api.Template) - Backend template for .NET
|
|
67
76
|
|
|
68
77
|
## License
|
|
69
78
|
|
package/index.js
CHANGED
|
@@ -114,13 +114,19 @@ VITE_REDIRECT_URI=http://localhost:5173/auth/callback
|
|
|
114
114
|
await fs.rename(gitignoreSrc, gitignoreDest);
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
// Create .env from .env.example
|
|
118
|
+
const envPath = path.join(targetDir, ".env");
|
|
119
|
+
if (fs.existsSync(envExamplePath) && !fs.existsSync(envPath)) {
|
|
120
|
+
await fs.copy(envExamplePath, envPath);
|
|
121
|
+
}
|
|
122
|
+
|
|
117
123
|
console.log(kleur.green("✔ Project created successfully!"));
|
|
118
124
|
console.log();
|
|
119
125
|
console.log(kleur.cyan("Next steps:"));
|
|
120
126
|
console.log();
|
|
121
127
|
console.log(` ${kleur.gray("$")} cd ${projectName}`);
|
|
122
128
|
console.log(` ${kleur.gray("$")} npm install`);
|
|
123
|
-
console.log(` ${kleur.gray("$")} cp .env.example .env ${kleur.gray("# Configure your environment")}`);
|
|
129
|
+
// console.log(` ${kleur.gray("$")} cp .env.example .env ${kleur.gray("# Configure your environment")}`);
|
|
124
130
|
console.log(` ${kleur.gray("$")} npm run dev`);
|
|
125
131
|
console.log();
|
|
126
132
|
console.log(kleur.gray("────────────────────────────────────"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-cundi-app",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Create a new Cundi app with React + Refine + Ant Design",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
"index.js",
|
|
11
11
|
"template"
|
|
12
12
|
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"pack": "npm pack --pack-destination ../../output/npm"
|
|
15
|
+
},
|
|
13
16
|
"keywords": [
|
|
14
17
|
"create",
|
|
15
18
|
"cundi",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@ant-design/icons": "^5.5.1",
|
|
26
26
|
"@ant-design/v5-patch-for-react-19": "^1.0.3",
|
|
27
|
-
"@cundi/refine-xaf": "^1.0.
|
|
27
|
+
"@cundi/refine-xaf": "^1.0.6",
|
|
28
28
|
"@refinedev/antd": "^6.0.3",
|
|
29
29
|
"@refinedev/cli": "^2.16.50",
|
|
30
30
|
"@refinedev/core": "^5.0.6",
|
package/template/src/App.tsx
CHANGED
|
@@ -6,13 +6,13 @@ import {
|
|
|
6
6
|
useNotificationProvider,
|
|
7
7
|
ThemedLayout,
|
|
8
8
|
ErrorComponent,
|
|
9
|
-
RefineThemes,
|
|
10
9
|
} from "@refinedev/antd";
|
|
11
10
|
import {
|
|
12
11
|
DashboardOutlined,
|
|
13
12
|
UserOutlined,
|
|
14
13
|
SettingOutlined,
|
|
15
14
|
TeamOutlined,
|
|
15
|
+
FieldTimeOutlined,
|
|
16
16
|
} from "@ant-design/icons";
|
|
17
17
|
|
|
18
18
|
import routerProvider, {
|
|
@@ -22,7 +22,7 @@ import routerProvider, {
|
|
|
22
22
|
DocumentTitleHandler,
|
|
23
23
|
} from "@refinedev/react-router";
|
|
24
24
|
import { BrowserRouter, Routes, Route, Outlet } from "react-router";
|
|
25
|
-
import { App as AntdApp
|
|
25
|
+
import { App as AntdApp } from "antd";
|
|
26
26
|
import { useTranslation } from "react-i18next";
|
|
27
27
|
import "./i18n";
|
|
28
28
|
|
|
@@ -43,15 +43,15 @@ import {
|
|
|
43
43
|
RoleList,
|
|
44
44
|
RoleCreate,
|
|
45
45
|
RoleEdit,
|
|
46
|
+
ColorModeContextProvider,
|
|
47
|
+
BackgroundJobList,
|
|
46
48
|
} from "@cundi/refine-xaf";
|
|
47
49
|
|
|
48
|
-
import { ColorModeContextProvider, useColorMode } from "./contexts/color-mode";
|
|
49
50
|
import { accessControlProvider } from "./accessControlProvider";
|
|
50
51
|
|
|
51
52
|
const API_URL = import.meta.env.VITE_API_URL + "/odata";
|
|
52
53
|
|
|
53
54
|
const InnerApp: React.FC = () => {
|
|
54
|
-
const { mode } = useColorMode();
|
|
55
55
|
const { t, i18n } = useTranslation();
|
|
56
56
|
|
|
57
57
|
const i18nProvider = {
|
|
@@ -62,121 +62,125 @@ const InnerApp: React.FC = () => {
|
|
|
62
62
|
|
|
63
63
|
return (
|
|
64
64
|
<BrowserRouter>
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
{
|
|
80
|
-
name: "dashboard",
|
|
81
|
-
list: "/",
|
|
82
|
-
meta: {
|
|
83
|
-
label: t("sider.dashboard"),
|
|
84
|
-
icon: <DashboardOutlined />,
|
|
85
|
-
},
|
|
65
|
+
<AntdApp>
|
|
66
|
+
<Refine
|
|
67
|
+
authProvider={authProvider}
|
|
68
|
+
accessControlProvider={accessControlProvider}
|
|
69
|
+
dataProvider={dataProvider(API_URL)}
|
|
70
|
+
i18nProvider={i18nProvider}
|
|
71
|
+
routerProvider={routerProvider}
|
|
72
|
+
resources={[
|
|
73
|
+
{
|
|
74
|
+
name: "dashboard",
|
|
75
|
+
list: "/",
|
|
76
|
+
meta: {
|
|
77
|
+
label: t("sider.dashboard"),
|
|
78
|
+
icon: <DashboardOutlined />,
|
|
86
79
|
},
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "ApplicationUser",
|
|
83
|
+
list: "/ApplicationUsers",
|
|
84
|
+
create: "/ApplicationUsers/create",
|
|
85
|
+
edit: "/ApplicationUsers/edit/:id",
|
|
86
|
+
meta: {
|
|
87
|
+
label: t("sider.users"),
|
|
88
|
+
icon: <UserOutlined />,
|
|
89
|
+
parent: t("sider.settings"),
|
|
97
90
|
},
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "PermissionPolicyRole",
|
|
94
|
+
list: "/PermissionPolicyRoles",
|
|
95
|
+
create: "/PermissionPolicyRoles/create",
|
|
96
|
+
edit: "/PermissionPolicyRoles/edit/:id",
|
|
97
|
+
meta: {
|
|
98
|
+
label: t("sider.roles"),
|
|
99
|
+
parent: t("sider.settings"),
|
|
100
|
+
icon: <TeamOutlined />,
|
|
108
101
|
},
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "BackgroundJobs",
|
|
105
|
+
list: "/background-jobs",
|
|
106
|
+
meta: {
|
|
107
|
+
label: t("sider.backgroundJobs"),
|
|
108
|
+
icon: <FieldTimeOutlined />,
|
|
109
|
+
parent: t("sider.settings"),
|
|
115
110
|
},
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: "Settings",
|
|
114
|
+
meta: {
|
|
115
|
+
label: t("sider.settings"),
|
|
116
|
+
icon: <SettingOutlined />,
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
]}
|
|
120
|
+
notificationProvider={useNotificationProvider}
|
|
121
|
+
options={{
|
|
122
|
+
syncWithLocation: true,
|
|
123
|
+
warnWhenUnsavedChanges: true,
|
|
124
|
+
}}
|
|
125
|
+
>
|
|
126
|
+
<Routes>
|
|
127
|
+
<Route
|
|
128
|
+
element={
|
|
129
|
+
<Authenticated
|
|
130
|
+
key="authenticated-routes"
|
|
131
|
+
fallback={<CatchAllNavigate to="/login" />}
|
|
132
|
+
>
|
|
133
|
+
<ThemedLayout Header={Header}>
|
|
134
|
+
<Outlet />
|
|
135
|
+
</ThemedLayout>
|
|
136
|
+
</Authenticated>
|
|
137
|
+
}
|
|
138
|
+
>
|
|
139
|
+
<Route index element={<DashboardPage />} />
|
|
143
140
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
</Route>
|
|
141
|
+
<Route path="/ApplicationUsers">
|
|
142
|
+
<Route index element={<ApplicationUserList />} />
|
|
143
|
+
<Route path="create" element={<ApplicationUserCreate />} />
|
|
144
|
+
<Route path="edit/:id" element={<ApplicationUserEdit />} />
|
|
149
145
|
</Route>
|
|
150
146
|
|
|
151
|
-
<Route
|
|
152
|
-
element={
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
</Authenticated>
|
|
156
|
-
}
|
|
157
|
-
>
|
|
158
|
-
<Route path="/login" element={<KeycloakLoginPage />} />
|
|
159
|
-
<Route path="/login/api" element={<LoginPage />} />
|
|
160
|
-
<Route path="/auth/callback" element={<AuthCallback />} />
|
|
147
|
+
<Route path="/PermissionPolicyRoles">
|
|
148
|
+
<Route index element={<RoleList />} />
|
|
149
|
+
<Route path="create" element={<RoleCreate />} />
|
|
150
|
+
<Route path="edit/:id" element={<RoleEdit />} />
|
|
161
151
|
</Route>
|
|
162
152
|
|
|
163
|
-
<Route
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
153
|
+
<Route path="/background-jobs" element={<BackgroundJobList title={t("sider.backgroundJobs")} />} />
|
|
154
|
+
</Route>
|
|
155
|
+
|
|
156
|
+
<Route
|
|
157
|
+
element={
|
|
158
|
+
<Authenticated key="auth-pages" fallback={<Outlet />}>
|
|
159
|
+
<NavigateToResource resource="dashboard" />
|
|
160
|
+
</Authenticated>
|
|
161
|
+
}
|
|
162
|
+
>
|
|
163
|
+
<Route path="/login" element={<KeycloakLoginPage />} />
|
|
164
|
+
<Route path="/login/api" element={<LoginPage />} />
|
|
165
|
+
<Route path="/auth/callback" element={<AuthCallback />} />
|
|
166
|
+
</Route>
|
|
167
|
+
|
|
168
|
+
<Route
|
|
169
|
+
element={
|
|
170
|
+
<Authenticated key="catch-all">
|
|
171
|
+
<ThemedLayout Header={Header}>
|
|
172
|
+
<Outlet />
|
|
173
|
+
</ThemedLayout>
|
|
174
|
+
</Authenticated>
|
|
175
|
+
}
|
|
176
|
+
>
|
|
177
|
+
<Route path="*" element={<ErrorComponent />} />
|
|
178
|
+
</Route>
|
|
179
|
+
</Routes>
|
|
180
|
+
<UnsavedChangesNotifier />
|
|
181
|
+
<DocumentTitleHandler />
|
|
182
|
+
</Refine>
|
|
183
|
+
</AntdApp>
|
|
180
184
|
</BrowserRouter>
|
|
181
185
|
);
|
|
182
186
|
};
|
package/template/vite.config.ts
CHANGED
|
@@ -4,6 +4,17 @@ import react from "@vitejs/plugin-react";
|
|
|
4
4
|
export default defineConfig({
|
|
5
5
|
plugins: [react()],
|
|
6
6
|
resolve: {
|
|
7
|
+
alias: {
|
|
8
|
+
"antd/lib": "antd",
|
|
9
|
+
},
|
|
7
10
|
dedupe: ["react", "react-dom", "antd", "@refinedev/core", "@refinedev/antd", "@tanstack/react-query"],
|
|
8
11
|
},
|
|
12
|
+
server: {
|
|
13
|
+
proxy: {
|
|
14
|
+
"/api": {
|
|
15
|
+
target: "http://localhost:5000",
|
|
16
|
+
changeOrigin: true,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
9
20
|
});
|