@_tc/template-core 0.1.13 → 0.1.15
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/.skills/tc-component-usage-skills/SKILL.md +31 -9
- package/.skills/tc-component-usage-skills/reference/component-api.md +63 -42
- package/.skills/tc-component-usage-skills/reference/examples.md +34 -24
- package/.skills/tc-component-usage-skills/reference/patterns.md +52 -17
- package/.skills/tc-component-usage-skills/reference/template-core-frontend.md +104 -0
- package/.skills/tc-generator/SKILL.md +11 -3
- package/.skills/tc-generator/reference/example.md +1 -1
- package/.skills/tc-generator/reference/model-schema.md +4 -2
- package/.skills/tc-generator/reference/project-template/config/config.default.js +4 -0
- package/.skills/tc-generator/reference/project-template/index.js +1 -1
- package/.skills/tc-generator/reference/project-template/model/product/project/default.js +1 -0
- package/.skills/tc-generator/reference/project-template/package.json +16 -1
- package/.skills/tc-generator/reference/runtime-extensions.md +190 -0
- package/README.md +217 -2
- package/cjs/app/extend/db.js +20 -1
- package/cjs/bundler/utils.js +1 -1
- package/esm/app/extend/db.js +138 -3
- package/esm/bundler/utils.js +2 -1
- package/fe/frontend/apps/dash/Dashboard.js +3 -1
- package/fe/frontend/apps/dash/types.d.ts +8 -0
- package/fe/frontend/src/components/LanguageSwitch/LanguageSwitch.d.ts +14 -0
- package/fe/frontend/src/components/LanguageSwitch/LanguageSwitch.js +32 -0
- package/fe/frontend/src/components/LanguageSwitch/index.d.ts +4 -0
- package/fe/frontend/src/components/LanguageSwitch/index.js +3 -0
- package/fe/frontend/src/components/ThemeSwitch/ThemeSwitch.d.ts +15 -0
- package/fe/frontend/src/components/ThemeSwitch/ThemeSwitch.js +59 -0
- package/fe/frontend/src/components/ThemeSwitch/index.d.ts +4 -0
- package/fe/frontend/src/components/ThemeSwitch/index.js +3 -0
- package/fe/frontend/src/components/index.d.ts +11 -0
- package/fe/frontend/src/components/index.js +10 -0
- package/fe/frontend/src/index.d.ts +1 -0
- package/fe/frontend/src/index.js +1 -0
- package/fe/frontend/src/language/en-US.d.ts +13 -0
- package/fe/frontend/src/language/en-US.js +13 -0
- package/fe/frontend/src/language/index.d.ts +7 -0
- package/fe/frontend/src/language/index.js +7 -0
- package/fe/frontend/src/language/zh-CN.d.ts +13 -0
- package/fe/frontend/src/language/zh-CN.js +13 -0
- package/fe/packages/ui/react/components/Button/{SumbitButton.d.ts → SubmitButton.d.ts} +5 -5
- package/fe/packages/ui/react/components/Button/{SumbitButton.js → SubmitButton.js} +3 -3
- package/fe/packages/ui/react/components/Button/index.d.ts +1 -1
- package/fe/packages/ui/react/components/Button/index.js +1 -1
- package/fe/packages/ui/react/components/Modal/ModalManager.d.ts +3 -3
- package/fe/packages/ui/react/components/TableSearch/index.d.ts +1 -0
- package/package.json +1 -1
- package/types/app/extend/db.d.ts +54 -1
- package/types/config/config.default.d.ts +30 -0
- package/types/index.d.ts +1 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# TemplateCore Frontend Helpers
|
|
2
|
+
|
|
3
|
+
Use these when building business UI on top of TemplateCore, especially Dashboard header tools and project pages.
|
|
4
|
+
|
|
5
|
+
## Import Paths
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { AsyncSelect, LanguageSwitch, ThemeSwitch } from '@_tc/template-core/fe'
|
|
9
|
+
import { Button, DataTable, TableSearch } from '@_tc/template-core/fe/rc'
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Inside this repository, `@tc/ui-react` is also valid for the raw UI library. In published business projects, prefer `@_tc/template-core/fe/rc` for UI components and `@_tc/template-core/fe` for frontend runtime helpers.
|
|
13
|
+
|
|
14
|
+
## LanguageSwitch
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
<LanguageSwitch />
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Default languages are `zh-CN` and `en-US`. Pass `options` to replace the list. `onChange(language)` receives the selected language string. The component calls `i18nStore.getState().setLanguage()`, so it uses the same `tc_language` persistence as the UI i18n runtime.
|
|
21
|
+
|
|
22
|
+
Useful props:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
type LanguageSwitchValue = 'zh-CN' | 'en-US' | (string & {})
|
|
26
|
+
|
|
27
|
+
interface LanguageSwitchProps {
|
|
28
|
+
value?: LanguageSwitchValue
|
|
29
|
+
defaultValue?: LanguageSwitchValue
|
|
30
|
+
options?: Array<{ label: ReactNode; value: LanguageSwitchValue; searchText?: string }>
|
|
31
|
+
onChange?: (language: LanguageSwitchValue) => void
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## ThemeSwitch
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
<ThemeSwitch showLabel />
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Toggles `document.documentElement.classList` with the `dark` class and syncs `color-scheme`. By default it persists to `localStorage` key `tc_theme`.
|
|
42
|
+
|
|
43
|
+
Useful props:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
type ThemeSwitchMode = 'light' | 'dark'
|
|
47
|
+
|
|
48
|
+
interface ThemeSwitchProps {
|
|
49
|
+
value?: ThemeSwitchMode
|
|
50
|
+
defaultValue?: ThemeSwitchMode
|
|
51
|
+
onChange?: (mode: ThemeSwitchMode) => void
|
|
52
|
+
disabled?: boolean
|
|
53
|
+
showLabel?: boolean
|
|
54
|
+
persist?: boolean
|
|
55
|
+
storageKey?: string
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## AsyncSelect
|
|
60
|
+
|
|
61
|
+
Use `AsyncSelect` when options should be loaded from a TemplateCore API.
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
<AsyncSelect
|
|
65
|
+
fetchConfig={{ url: '/user/options', method: 'get' }}
|
|
66
|
+
placeholder="Select user"
|
|
67
|
+
/>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The options array shape is:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
Array<{ label: string; value: string | number; searchText?: string }>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The endpoint should return TemplateCore's normal response wrapper. In a controller, use:
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
this.success(ctx, [
|
|
80
|
+
{ label: "Alice", value: "u1" },
|
|
81
|
+
{ label: "Bob", value: "u2" },
|
|
82
|
+
]);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`AsyncSelect` reads `res.data.code === 0` and then maps `res.data.data`. It forwards most `Select` props except `options`; it owns option loading internally.
|
|
86
|
+
|
|
87
|
+
## Dashboard Header Tools
|
|
88
|
+
|
|
89
|
+
For a compact header user area, combine the helpers:
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
import { LanguageSwitch, ThemeSwitch } from '@_tc/template-core/fe'
|
|
93
|
+
|
|
94
|
+
export function HeaderTools() {
|
|
95
|
+
return (
|
|
96
|
+
<div className="flex items-center gap-2">
|
|
97
|
+
<LanguageSwitch className="w-32" />
|
|
98
|
+
<ThemeSwitch />
|
|
99
|
+
</div>
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Registering the header slot itself belongs to the generator/runtime extension docs. The supported Dashboard component key is `HeaderView.userArea`.
|
|
@@ -18,7 +18,8 @@ Use this skill to generate or update TemplateCore business code.
|
|
|
18
18
|
- optional `model/{modelKey}/project/{projectKey}.js`
|
|
19
19
|
2. Read only the reference needed:
|
|
20
20
|
- Model/menu/schema rules: `reference/model-schema.md`
|
|
21
|
-
-
|
|
21
|
+
- Runtime extensions (db, Dashboard slots/routes, frontend helpers): `reference/runtime-extensions.md`
|
|
22
|
+
- Standalone skeleton: `reference/project-template/`
|
|
22
23
|
- Complete product CRUD example: `reference/example.md`
|
|
23
24
|
3. Generate the smallest working slice first: config, entry, controller, router, model.
|
|
24
25
|
4. Keep keys stable. Array merge and project overrides depend on `key`.
|
|
@@ -27,8 +28,10 @@ Use this skill to generate or update TemplateCore business code.
|
|
|
27
28
|
## TemplateCore Conventions
|
|
28
29
|
|
|
29
30
|
- Start the app with `serverStart({ name, baseDir })` from `@_tc/template-core`.
|
|
30
|
-
- Start the built-in frontend with `buildFE("dev")` from `@_tc/template-core/bundler` when the user needs the admin UI.
|
|
31
|
+
- Start the built-in frontend with `buildFE("dev")` from `@_tc/template-core/bundler` when the user needs the admin UI. Do not `await` it; the current API starts the build/dev process and returns `void`.
|
|
32
|
+
- If `buildFE("dev")` is used in a standalone project, include the TemplateCore peer dependencies or use the package manager's peer dependency auto-install behavior.
|
|
31
33
|
- Business code lives under the user's `baseDir`, not inside TemplateCore framework folders.
|
|
34
|
+
- The framework provides `app.extends.db` as a default SQLite-backed KV/SQL helper. Use it for small framework/business settings; override `app/extend/db.js` only when the project needs a custom storage implementation.
|
|
32
35
|
- Backend loaders map filenames to camelCase fields:
|
|
33
36
|
- `app/controller/product.js` -> `app.controller.product`
|
|
34
37
|
- `app/service/user-profile.js` -> `app.service.userProfile`
|
|
@@ -43,12 +46,17 @@ Use this skill to generate or update TemplateCore business code.
|
|
|
43
46
|
|
|
44
47
|
## Output Rules
|
|
45
48
|
|
|
46
|
-
- Make generated code directly runnable.
|
|
49
|
+
- Make generated code directly runnable when package dependencies are installed.
|
|
47
50
|
- Include realistic in-memory data only for demos or scaffolds.
|
|
48
51
|
- Use `$i18n::...` only when also adding or pointing to language resources; otherwise write plain labels.
|
|
49
52
|
- For Schema CRUD, include `tableOption`, `createFormOption`, `editFormOption`, and `detailPanelOption` only where the field should appear.
|
|
50
53
|
- For edit/detail components, set `fetchKey` to the primary key field.
|
|
51
54
|
- For remove buttons, use `$schema::{field}` to pull values from the current row.
|
|
55
|
+
- Generate frontend extensions only when needed:
|
|
56
|
+
- Dashboard header UI: `frontend/extended/dash/components.tsx` with `HeaderView.userArea`
|
|
57
|
+
- Dashboard custom routes: `frontend/extended/dash/customRoutes.tsx`
|
|
58
|
+
- SchemaForm field types: `frontend/extended/SchemaForm/data.ts`
|
|
59
|
+
- SchemaPage custom call components: `frontend/extended/SchemaPage/CallCom/data.ts`
|
|
52
60
|
|
|
53
61
|
## Validation
|
|
54
62
|
|
|
@@ -45,7 +45,7 @@ module.exports = {
|
|
|
45
45
|
name: "Product Admin",
|
|
46
46
|
desc: "Product management",
|
|
47
47
|
icon: "",
|
|
48
|
-
homePage: "/_sidebar_/product
|
|
48
|
+
homePage: "/_sidebar_/product",
|
|
49
49
|
menuLayout: "left",
|
|
50
50
|
menu: [],
|
|
51
51
|
};
|
|
@@ -63,7 +63,7 @@ Fields:
|
|
|
63
63
|
| `menuLayout` | no | `"left"` default, or `"top"`. |
|
|
64
64
|
| `menu` | yes | Menu tree. |
|
|
65
65
|
|
|
66
|
-
For `left` layout, built-in menu routes are under `/_sidebar_/{menuKey}`. For `top` layout, built-in menu routes are `/{menuKey}`.
|
|
66
|
+
For `left` layout, built-in menu routes are under `/_sidebar_/{menuKey}`. For `top` layout, built-in menu routes are `/{menuKey}`. Keep shared model `homePage` project-neutral when multiple projects inherit the same model; put project-specific query values, such as `projk`, in the project override when they differ per project.
|
|
67
67
|
|
|
68
68
|
## Menu Types
|
|
69
69
|
|
|
@@ -173,6 +173,8 @@ Table list should return:
|
|
|
173
173
|
|
|
174
174
|
Framework response wrapper is handled by `this.success(ctx, data)`.
|
|
175
175
|
|
|
176
|
+
Controllers can use `app.extends.db` for simple persisted data instead of in-memory arrays. See `reference/runtime-extensions.md` for the default DB contract and override pattern.
|
|
177
|
+
|
|
176
178
|
## Field Schema
|
|
177
179
|
|
|
178
180
|
Each field is JSON Schema plus TemplateCore options:
|
|
@@ -5,6 +5,21 @@
|
|
|
5
5
|
"dev": "node index.js"
|
|
6
6
|
},
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@_tc/template-core": "
|
|
8
|
+
"@_tc/template-core": "latest",
|
|
9
|
+
"@vitejs/plugin-react": "6.0.1",
|
|
10
|
+
"clsx": "^2.1.0",
|
|
11
|
+
"date-fns": "^3.6.0",
|
|
12
|
+
"koa": "^2.15.0",
|
|
13
|
+
"koa-router": "^12.0.1",
|
|
14
|
+
"lodash": "^4.17.21",
|
|
15
|
+
"lucide-react": "^0.468.0",
|
|
16
|
+
"rc-field-form": "^1.44.0",
|
|
17
|
+
"react": "^19.0.0",
|
|
18
|
+
"react-dom": "^19.0.0",
|
|
19
|
+
"react-router-dom": "^6.28.0",
|
|
20
|
+
"tailwind-merge": "^2.4.0",
|
|
21
|
+
"vite": "8.0.10",
|
|
22
|
+
"xlsx": "^0.18.5",
|
|
23
|
+
"zustand": "^5.0.0"
|
|
9
24
|
}
|
|
10
25
|
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# TemplateCore Runtime Extensions
|
|
2
|
+
|
|
3
|
+
Use this reference when generating business code that needs persistence, Dashboard customization, or frontend helper components.
|
|
4
|
+
|
|
5
|
+
## Default DB
|
|
6
|
+
|
|
7
|
+
`app.extends.db` is available by default. It stores framework/business data in SQLite at:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
.template-core/template-core.sqlite
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The default path is relative to the business project `baseDir`. Configure it in `config/config.default.js`:
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
module.exports = {
|
|
17
|
+
port: 9000,
|
|
18
|
+
db: {
|
|
19
|
+
path: "data/app.sqlite",
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Prefer `db.path` for new projects. The current runtime also accepts `db` as a string and object aliases `filename`, `sqlitePath`, or `sqlite: string | { path, filename }` for compatibility.
|
|
25
|
+
|
|
26
|
+
Common methods:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
app.extends.db.dbPath
|
|
30
|
+
app.extends.db.getDBConnection()
|
|
31
|
+
app.extends.db.execDB(sql)
|
|
32
|
+
app.extends.db.getDBData(key, { namespace })
|
|
33
|
+
app.extends.db.getDBDataRecord(key, { namespace })
|
|
34
|
+
app.extends.db.setDBData(key, value, { namespace })
|
|
35
|
+
app.extends.db.hasDBData(key, { namespace })
|
|
36
|
+
app.extends.db.deleteDBData(key, { namespace })
|
|
37
|
+
app.extends.db.listDBData({ namespace, limit, offset })
|
|
38
|
+
app.extends.db.countDBData({ namespace })
|
|
39
|
+
app.extends.db.clearDBData({ namespace })
|
|
40
|
+
app.extends.db.queryDB(sql, params)
|
|
41
|
+
app.extends.db.runDB(sql, params)
|
|
42
|
+
app.extends.db.getDBFirst(sql, params)
|
|
43
|
+
app.extends.db.transactionDB((db) => ...)
|
|
44
|
+
app.extends.db.closeDB()
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
SQL safety rule: put user input in `params`; do not concatenate it into SQL strings. `execDB(sql)` is only for fixed SQL such as migrations.
|
|
48
|
+
|
|
49
|
+
Example controller storage:
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
const { baseFn } = require("@_tc/template-core");
|
|
53
|
+
|
|
54
|
+
module.exports = (app) => {
|
|
55
|
+
const BaseController = baseFn.baseControllerFn(app);
|
|
56
|
+
|
|
57
|
+
return class SettingController extends BaseController {
|
|
58
|
+
get = async (ctx) => {
|
|
59
|
+
const data = app.extends.db.getDBData("site-setting", {
|
|
60
|
+
namespace: "settings",
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
this.success(ctx, data || {});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
save = async (ctx) => {
|
|
67
|
+
app.extends.db.setDBData("site-setting", ctx.request.body, {
|
|
68
|
+
namespace: "settings",
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
this.success(ctx, {});
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
If the runtime does not support the built-in SQLite module or the project needs another store, generate `app/extend/db.js` or `app/extend/db.ts` and preserve the same method names so existing controllers keep working.
|
|
78
|
+
|
|
79
|
+
## Dashboard Component Slot
|
|
80
|
+
|
|
81
|
+
Use `frontend/extended/dash/components.tsx` to fill supported Dashboard slots. The current slot is:
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
HeaderView.userArea
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Example:
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
import { LanguageSwitch, ThemeSwitch } from '@_tc/template-core/fe'
|
|
91
|
+
import type { DashComponentsMap } from '@_tc/template-core/fe'
|
|
92
|
+
|
|
93
|
+
const components = {
|
|
94
|
+
'HeaderView.userArea': ({ projectInfo }) => {
|
|
95
|
+
return (
|
|
96
|
+
<div className="flex items-center gap-2">
|
|
97
|
+
<span className="max-w-32 truncate text-xs text-muted-foreground">
|
|
98
|
+
{projectInfo?.name}
|
|
99
|
+
</span>
|
|
100
|
+
<LanguageSwitch />
|
|
101
|
+
<ThemeSwitch />
|
|
102
|
+
</div>
|
|
103
|
+
)
|
|
104
|
+
},
|
|
105
|
+
} satisfies DashComponentsMap
|
|
106
|
+
|
|
107
|
+
export default components
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Keep header content compact; the default header already owns brand, title, and menu layout.
|
|
111
|
+
|
|
112
|
+
## Dashboard Custom Routes
|
|
113
|
+
|
|
114
|
+
Use `frontend/extended/dash/customRoutes.tsx` when a `custom` menu item needs a route inside the built-in Dashboard.
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
import type { DashRoutesExtender } from '@_tc/template-core/fe'
|
|
118
|
+
|
|
119
|
+
const extendDashRoutes: DashRoutesExtender = ({ topRoutes, sidebarRoutes }) => {
|
|
120
|
+
topRoutes.push({
|
|
121
|
+
path: '/custom-page',
|
|
122
|
+
component: <div>Custom Page</div>,
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
sidebarRoutes.push({
|
|
126
|
+
path: 'custom-sidebar-page',
|
|
127
|
+
component: <div>Custom Sidebar Page</div>,
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export default extendDashRoutes
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`topRoutes` are appended under `/dash`. `sidebarRoutes` are appended inside the default sidebar containers.
|
|
135
|
+
|
|
136
|
+
## Frontend Helpers
|
|
137
|
+
|
|
138
|
+
Import TemplateCore frontend helpers from `@_tc/template-core/fe`:
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
import { AsyncSelect, LanguageSwitch, ThemeSwitch } from '@_tc/template-core/fe'
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Import UI components from the published UI re-export:
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
import { Button, DataTable, TableSearch } from '@_tc/template-core/fe/rc'
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`LanguageSwitch` updates the shared i18n language and persists through `tc_language`. `ThemeSwitch` toggles the root `dark` class and persists through `tc_theme`. `AsyncSelect` loads options from a `fetchConfig` endpoint returning `{ label, value, searchText? }[]`.
|
|
151
|
+
|
|
152
|
+
## SchemaForm Extensions
|
|
153
|
+
|
|
154
|
+
TemplateCore already registers a framework SchemaForm type named `asyncSelect`. Use it in Schema CRUD model config when a field should fetch options from an API:
|
|
155
|
+
|
|
156
|
+
```js
|
|
157
|
+
owner_id: {
|
|
158
|
+
type: "string",
|
|
159
|
+
label: "Owner",
|
|
160
|
+
createFormOption: {
|
|
161
|
+
comType: "asyncSelect",
|
|
162
|
+
fetchConfig: {
|
|
163
|
+
url: "/user/options",
|
|
164
|
+
method: "get",
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
editFormOption: {
|
|
168
|
+
comType: "asyncSelect",
|
|
169
|
+
fetchConfig: {
|
|
170
|
+
url: "/user/options",
|
|
171
|
+
method: "get",
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The options controller should return the normal TemplateCore response wrapper:
|
|
178
|
+
|
|
179
|
+
```js
|
|
180
|
+
this.success(ctx, [
|
|
181
|
+
{ label: "Alice", value: "u1" },
|
|
182
|
+
{ label: "Bob", value: "u2" },
|
|
183
|
+
]);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
For project-specific field types, create `frontend/extended/SchemaForm/data.ts` and default-export a component map keyed by field type.
|
|
187
|
+
|
|
188
|
+
## SchemaPage CallCom Extensions
|
|
189
|
+
|
|
190
|
+
Use `frontend/extended/SchemaPage/CallCom/data.ts` when model `componentConfig` should open a custom runtime component instead of built-in create/edit/detail components. Custom components can import `schemaEventBus`, `eventsInfo`, and `merge` from `@_tc/template-core/fe` to close panels or refresh Schema tables.
|