fix: update doc demos (#4262)

* fix: update doc demos

* fix: change docs demo

* fix: bug

* fix: build bug

* fix: add english docs

* fix: add component english doc

* fix: lang change
This commit is contained in:
jack zhang 2024-05-09 09:21:36 +08:00 committed by GitHub
parent cafaa82a94
commit 1e5e015b73
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
378 changed files with 10212 additions and 7637 deletions

View File

@ -1,6 +1,5 @@
const { exec } = require('child_process'); const { exec } = require('child_process');
const fs = require('fs'); const fs = require('fs');
const path = require('path');
const commercialLicense = ` const commercialLicense = `
/** /**
@ -59,6 +58,7 @@ exec('git diff --cached --name-only --diff-filter=ACM', (error, stdout, stderr)
.split('\n') .split('\n')
.filter(Boolean) .filter(Boolean)
.filter((file) => file.includes('/src/')) // 只检查 src 目录下的文件 .filter((file) => file.includes('/src/')) // 只检查 src 目录下的文件
.filter((file) => !file.includes('/demos/')) // 忽略 demos 目录
.filter((file) => file.endsWith('.js') || file.endsWith('.jsx') || file.endsWith('.ts') || file.endsWith('.tsx')); .filter((file) => file.endsWith('.js') || file.endsWith('.jsx') || file.endsWith('.ts') || file.endsWith('.tsx'));
const validFiles = files.filter((file) => addLicenseToFile(file)); const validFiles = files.filter((file) => addLicenseToFile(file));

View File

@ -228,6 +228,9 @@ exports.genTsConfigPaths = function genTsConfigPaths() {
paths[`${packageJsonName}/e2e`] = [`${relativePath}/src/e2e`]; paths[`${packageJsonName}/e2e`] = [`${relativePath}/src/e2e`];
paths[`${packageJsonName}/web`] = [`${relativePath}/src/web`]; paths[`${packageJsonName}/web`] = [`${relativePath}/src/web`];
} }
if (packageJsonName === '@nocobase/client') {
paths[`${packageJsonName}/demo-utils`] = [`${relativePath}/src/demo-utils`];
}
if (packageJsonName === '@nocobase/plugin-workflow-test') { if (packageJsonName === '@nocobase/plugin-workflow-test') {
paths[`${packageJsonName}/e2e`] = [`${relativePath}/src/e2e`]; paths[`${packageJsonName}/e2e`] = [`${relativePath}/src/e2e`];
} }

View File

@ -45,6 +45,10 @@ export default defineConfig({
{ {
title: 'Components', title: 'Components',
link: '/components/action', link: '/components/action',
},
{
title: 'Home site',
link: 'https://docs.nocobase.com/welcome/introduction/',
} }
// { // {
// title: 'UI Schema', // title: 'UI Schema',
@ -667,5 +671,9 @@ export default defineConfig({
// }, // },
// ], // ],
}, },
localesEnhance: [
{ id: 'zh-CN', switchPrefix: '中', hostname: 'client-cn.docs.nocobase.com' },
{ id: 'en-US', switchPrefix: 'en', hostname: 'client.docs.nocobase.com' }
],
}), }),
}); });

View File

@ -2,9 +2,9 @@
## new Application(options) ## new Application(options)
创建一个 NocoBase 应用。 Creates an instance of a NocoBase application.
- 类型 - Type
```tsx | pure ```tsx | pure
export interface ApplicationOptions { export interface ApplicationOptions {
@ -23,19 +23,20 @@ export interface ApplicationOptions {
} }
``` ```
- 详细信息 ## Details
- apiClientAPI 请求实例,具体说明请参见:[https://docs.nocobase.com/api/sdk](https://docs.nocobase.com/api/sdk) - `apiClient`: API request instance. For more details, refer to: [NocoBase API SDK Documentation](https://docs.nocobase.com/api/sdk)
- i18n国际化具体请参考[https://www.i18next.com/overview/api#createinstance](https://www.i18next.com/overview/api#createinstance) - `i18n`: Internationalization. For specifics, see: [i18next API Documentation](https://www.i18next.com/overview/api#createinstance)
- providers上下文 - `providers`: Context providers
- components全局组件 - `components`: Global components
- scopes全局 scopes - `scopes`: Global scopes
- router配置路由具体请参考[RouterManager](/core/application/router-manager) - `router`: Route configuration. Refer to: [RouterManager](/core/application/router-manager)
- pluginSettings: [PluginSettingsManager](/core/application/plugin-settings-manager) - `pluginSettings`: [PluginSettingsManager](/core/application/plugin-settings-manager)
- schemaSettingsSchema 设置工具,具体参考:[SchemaSettingsManager](/core/ui-schema/schema-initializer-manager) - `schemaSettings`: Schema settings tool. For more information, refer to: [SchemaSettingsManager](/core/ui-schema/schema-initializer-manager)
- schemaInitializersSchema 添加工具,具体参考:[SchemaInitializerManager](/core/ui-schema/schema-initializer-manager) - `schemaInitializers`: Schema addition tool. For more information, refer to: [SchemaInitializerManager](/core/ui-schema/schema-initializer-manager)
- loadRemotePlugins用于控制是否加载远程插件默认为 `false`,即不加载远程插件(方便单测和 DEMO 环境)。 - `loadRemotePlugins`: Used to control whether to load remote plugins. Default is `false`, meaning remote plugins are not loaded (convenient for unit testing and DEMO environments).
- dataSourceManager数据源管理器具体参考[DataSourceManager](/core/data-source/data-source-manager) - `dataSourceManager`: Data source manager. For more details, refer to: [DataSourceManager](/core/data-source/data-source-manager)
- 示例
## Example
```tsx ```tsx
/** /**
@ -71,7 +72,7 @@ const app = new Application({
export default app.getRootComponent(); export default app.getRootComponent();
``` ```
## 实例属性 ## Instance Properties
### app.i18n ### app.i18n
@ -81,7 +82,7 @@ class Application {
} }
``` ```
详细介绍,请参考:[i18next](https://www.i18next.com/overview/api#createinstance) For a detailed introduction, please refer to: [i18next](https://www.i18next.com/overview/api#createinstance)
### app.apiClient ### app.apiClient
@ -91,35 +92,35 @@ class Application {
} }
``` ```
详细介绍,请参考:[APIClient](https://docs.nocobase.com/api/sdk) For a detailed introduction, please refer to: [APIClient](https://docs.nocobase.com/api/sdk)
### app.router ### app.router
详细介绍,请参考:[RouterManager](/core/application/router-manager) For a detailed introduction, please refer to: [RouterManager](/core/application/router-manager)
### app.pluginSettingsManager ### app.pluginSettingsManager
详细介绍,请参考:[PluginSettingsManager](/core/application/plugin-settings-manager) For a detailed introduction, please refer to: [PluginSettingsManager](/core/application/plugin-settings-manager)
### app.schemaSettingsManager ### app.schemaSettingsManager
详细介绍,请参考:[SchemaSettingsManager](/core/ui-schema/schema-initializer-manager) For a detailed introduction, please refer to: [SchemaSettingsManager](/core/ui-schema/schema-initializer-manager)
### app.schemaInitializerManager ### app.schemaInitializerManager
详细介绍,请参考:[SchemaInitializerManager](/core/ui-schema/schema-initializer-manager) For a detailed introduction, please refer to: [SchemaInitializerManager](/core/ui-schema/schema-initializer-manager)
### app.dataSourceManager ### app.dataSourceManager
详细介绍,请参考:[dataSourceManager](/core/data-source/data-source-manager) For a detailed introduction, please refer to: [dataSourceManager](/core/data-source/data-source-manager)
## 实例方法 ## Instance Methods
### app.getRootComponent() ### app.getRootComponent()
获取应用的根组件。 Get the root component of the application.
- 类型 - Type
```tsx | pure ```tsx | pure
class Application { class Application {
@ -127,7 +128,7 @@ class Application {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
import { Application } from '@nocobase/client'; import { Application } from '@nocobase/client';
@ -139,9 +140,9 @@ const App = app.getRootComponent();
### app.mount() ### app.mount()
将应用实例挂载在一个容器元素中。 Mount the application instance in a container element.
- 类型 - Type
```tsx | pure ```tsx | pure
class Application { class Application {
@ -149,7 +150,7 @@ class Application {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
import { Application } from '@nocobase/client'; import { Application } from '@nocobase/client';
@ -161,9 +162,9 @@ app.mount('#root');
### app.addProvider() ### app.addProvider()
添加 `Provider` 上下文。 Add `Provider` context.
- 类型 - Type
```tsx | pure ```tsx | pure
class Application { class Application {
@ -171,14 +172,14 @@ class Application {
} }
``` ```
- 详细信息 - Details
第一个参数是组件,第二个参数是组件的参数。注意 `Provider` 一定要渲染 `children` The first parameter is the component, and the second parameter is the component's props. Note that the `Provider` must render its `children`.
- 示例 - Example
```tsx | pure ```tsx | pure
// 场景1第三方库或者自己创建的 Context // Scenario 1: Third-party library or self-created Context
const MyContext = createContext({}); const MyContext = createContext({});
app.addProvider(MyContext.provider, { value: { color: 'red' } }); app.addProvider(MyContext.provider, { value: { color: 'red' } });
``` ```
@ -216,7 +217,7 @@ export default app.getRootComponent();
``` ```
```tsx | pure ```tsx | pure
// 场景2自定义的组件注意 children // Scenario 2: Custom component, pay attention to children
const GlobalDemo = ({ name, children }) => { const GlobalDemo = ({ name, children }) => {
return <div> return <div>
<div>hello, { name }</div> <div>hello, { name }</div>
@ -261,9 +262,9 @@ export default app.getRootComponent();
### app.addProviders() ### app.addProviders()
添加多个 `Provider` 上下文。 Add multiple `Provider` contexts.
- 类型 - Type
```tsx | pure ```tsx | pure
class Application { class Application {
@ -271,11 +272,11 @@ class Application {
} }
``` ```
- 详细信息 - Details
一次添加多个 `Provider` Add multiple `Provider` contexts at once.
- 示例 - Example
```tsx | pure ```tsx | pure
app.addProviders([[MyContext.provider, { value: { color: 'red' } }], [GlobalDemo, { name: 'nocobase' }]]) app.addProviders([[MyContext.provider, { value: { color: 'red' } }], [GlobalDemo, { name: 'nocobase' }]])
@ -283,11 +284,11 @@ app.addProviders([[MyContext.provider, { value: { color: 'red' } }], [GlobalDemo
### app.addComponents() ### app.addComponents()
添加全局组件。 Add global components.
全局组件可以使用在 [RouterManager](/core/application/router-manager) 和 [UI Schema](/core/ui-schema/schema-component)上。 Global components can be used in [RouterManager](/core/application/router-manager) and [UI Schema](/core/ui-schema/schema-component).
- 类型 - Type
```tsx | pure ```tsx | pure
class Application { class Application {
@ -295,7 +296,7 @@ class Application {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
app.addComponents({ Demo, Foo, Bar }) app.addComponents({ Demo, Foo, Bar })
@ -303,11 +304,11 @@ app.addComponents({ Demo, Foo, Bar })
### app.addScopes() ### app.addScopes()
添加全局的 scope。 Add global scopes.
全局组 scope 可以 [UI Schema](/core/ui-schema/schema-component) 上。 Global scopes can be used in [UI Schema](/core/ui-schema/schema-component).
- 类型 - Type
```tsx | pure ```tsx | pure
class Application { class Application {
@ -315,7 +316,7 @@ class Application {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
function useSomeThing() {} function useSomeThing() {}
@ -328,15 +329,15 @@ app.addScopes({ useSomeThing, anyVar })
### useApp() ### useApp()
获取当前应用的实例。 Get the instance of the current application.
- 类型 - Type
```tsx | pure ```tsx | pure
const useApp: () => Application const useApp: () => Application
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const Demo = () => { const Demo = () => {

View File

@ -1,6 +1,6 @@
# PluginManager # PluginManager
用于管理插件。 Used for managing plugins.
```tsx | pure ```tsx | pure
class PluginManager { class PluginManager {
@ -11,13 +11,13 @@ class PluginManager {
} }
``` ```
## 实例方法 ## Instance Methods
### pluginManager.add() ### pluginManager.add()
将插件添加到应用中。 Add plugins to the application.
- 类型 - Type
```tsx | pure ```tsx | pure
class PluginManager { class PluginManager {
@ -25,13 +25,13 @@ class PluginManager {
} }
``` ```
- 详细信息 - Details
第一个参数是插件类,第二个则是实例化时传递的参数。前面已经讲过会在添加插件后,立即调用 `afterAdd` 钩子函数,所以返回的是 `Promise<void>` The first parameter is the plugin class, and the second parameter is the options passed during instantiation. As mentioned earlier, the `afterAdd` hook function will be immediately called after adding the plugin, so it returns a `Promise<void>`.
对于远程组件而言,会自动传递一个 `name` 参数。 For remote components, an additional name parameter will be automatically passed.
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPluginA extends Plugin { class MyPluginA extends Plugin {
@ -43,9 +43,9 @@ class MyPluginA extends Plugin {
} }
class MyPluginB extends Plugin { class MyPluginB extends Plugin {
// 需要在 afterAdd 执行添加的方法 // The method to be executed after adding needs to be placed in afterAdd
async afterAdd() { async afterAdd() {
// 通过 `app.pluginManager.add()` 添加插件时,第一个参数是插件类,第二个参数是实例化时传递的参数 // When adding a plugin through `app.pluginManager.add()`, the first parameter is the plugin class, and the second parameter is the options passed during instantiation.
this.app.pluginManager.add(MyPluginA, { name: 'MyPluginA', hello: 'world' }) this.app.pluginManager.add(MyPluginA, { name: 'MyPluginA', hello: 'world' })
} }
} }
@ -57,9 +57,9 @@ const app = new Application({
### pluginManager.get() ### pluginManager.get()
获取插件实例。 Get the plugin instance.
- 类型 - Type
```tsx | pure ```tsx | pure
class PluginManager { class PluginManager {
@ -68,23 +68,23 @@ class PluginManager {
} }
``` ```
- 详细信息 - Details
可以通过 Class 获取插件示例,如果在插件注册的时候有 name也可以通过字符串的 name 获取。 You can get the plugin instance by using the class, or you can also get it by providing the name if it was specified during plugin registration.
如果是远程插件,会自动传入 name值为 package 的 name。 For remote plugins, the name will be automatically passed and it will be the same as the package name.
- 示例 - Example
```tsx | pure ```tsx | pure
import MyPluginA from 'xxx'; import MyPluginA from 'xxx';
class MyPluginB extends Plugin { class MyPluginB extends Plugin {
async load() { async load() {
// 方式1通过 Class 获取 // 方式1: 通过 Class 获取
const myPluginA = this.app.pluginManager.get(MyPluginA); const myPluginA = this.app.pluginManager.get(MyPluginA);
// 方式2通过 name 获取(添加的时候要传递 name 参数) // 方式2: 通过 name 获取(添加的时候要传递 name 参数)
const myPluginA = this.app.pluginManager.get('MyPluginA'); const myPluginA = this.app.pluginManager.get('MyPluginA');
} }
} }
@ -92,7 +92,7 @@ class MyPluginB extends Plugin {
## Hooks ## Hooks
获取插件实例,等同于 `pluginManager.get()` Get the plugin instance, equivalent to `pluginManager.get()`.
### usePlugin() ### usePlugin()
@ -101,20 +101,20 @@ function usePlugin<T extends typeof Plugin>(plugin: T): InstanceType<T>;
function usePlugin<T extends {}>(name: string): T; function usePlugin<T extends {}>(name: string): T;
``` ```
- 详细信息 - Details
可以通过 Class 获取插件示例,如果在插件注册的时候有 name也可以通过字符串的 name 获取。 You can get the plugin instance by using the class, or you can also get it by providing the name if it was specified during plugin registration.
- 示例 - Example
```tsx | pure ```tsx | pure
import { usePlugin } from '@nocobase/client'; import { usePlugin } from '@nocobase/client';
const Demo = () => { const Demo = () => {
// 通过 Class 获取 // Get by Class
const myPlugin = usePlugin(MyPlugin); const myPlugin = usePlugin(MyPlugin);
// 通过 name 获取(添加的时候要传递 name 参数) // Get by name (name parameter must be passed during plugin registration)
const myPlugin = usePlugin('MyPlugin'); const myPlugin = usePlugin('MyPlugin');
return <div></div> return <div></div>

View File

@ -2,7 +2,7 @@
![](../static/plugin-settings.jpg) ![](../static/plugin-settings.jpg)
用于管理插件配置页面,其底层对应着 [RouterManager](/core/application/router-manager)。 Used to manage plugin configuration pages, which correspond to [RouterManager](/core/application/router-manager) at the underlying level.
```tsx | pure ```tsx | pure
interface PluginSettingOptionsType { interface PluginSettingOptionsType {
@ -46,13 +46,13 @@ class PluginSettingsManager {
} }
``` ```
## 实例方法 ## Instance Methods
### pluginSettingsManager.add() ### pluginSettingsManager.add()
添加插件配置页。 Add plugin configuration pages.
- 类型 - Type
```tsx | pure ```tsx | pure
class PluginSettingsManager { class PluginSettingsManager {
@ -60,15 +60,15 @@ class PluginSettingsManager {
} }
``` ```
- 详细解释 - Details
第一个参数 `name`,是路由唯一标识,用于后续的删改查,并且 `name` 支持 `.` 用于分割层级,不过需要注意当使用 `.` 分层的时候,父级要使用 [Outlet](https://reactrouter.com/en/main/components/outlet),让子元素能正常渲染。 The first parameter `name` is the unique identifier for the route, used for subsequent operations such as deletion and modification. The `name` also supports using `.` to separate hierarchical levels. However, when using `.` for hierarchy, the parent level should use [Outlet](https://reactrouter.com/en/main/components/outlet) to ensure proper rendering of child elements.
第二个参数中 `Component` 支持组件形式和字符串形式,如果是字符串组件,要先通过 [app.addComponents](/core/application/application#appaddcomponents) 进行注册,具体参考 [RouterManager](/core/application/router-manager)。 In the second parameter, the `Component` supports both component form and string form. If it is a string component, it needs to be registered through [app.addComponents](/core/application/application#appaddcomponents) first, please refer to [RouterManager](/core/application/router-manager) for more details.
- 示例 - Example
单层级配置。 Single-level configuration.
```tsx | pure ```tsx | pure
const HelloSettingPage = () => { const HelloSettingPage = () => {
@ -86,7 +86,7 @@ class MyPlugin extends Plugin {
} }
``` ```
多层级配置。 Multi-level configuration.
```tsx | pure ```tsx | pure
// 多层级配置页 // 多层级配置页
@ -114,9 +114,9 @@ class MyPlugin extends Plugin {
### pluginSettingsManager.get() ### pluginSettingsManager.get()
获取配置信息。 Get configuration information.
- 类型 - Type
```tsx | pure ```tsx | pure
class PluginSettingsManager { class PluginSettingsManager {
@ -124,13 +124,13 @@ class PluginSettingsManager {
} }
``` ```
- 详细解释 - Details
第一个是在添加时的 name 参数,第二个参数是是否在获取的时候进行权限过滤。 The first parameter is the `name` parameter when adding, and the second parameter is whether to filter permissions when getting.
- 示例 - Example
在组件中获取。 Get in the component.
```tsx | pure ```tsx | pure
const Demo = () => { const Demo = () => {
@ -139,7 +139,7 @@ const Demo = () => {
} }
``` ```
在插件中获取。 Get in the plugin.
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -154,9 +154,9 @@ class MyPlugin extends Plugin {
### pluginSettingsManager.getList() ### pluginSettingsManager.getList()
获取插件配置页列表。 Get the list of plugin settings pages.
- 类型 - Type
```tsx | pure ```tsx | pure
class PluginSettingsManager { class PluginSettingsManager {
@ -164,11 +164,11 @@ class PluginSettingsManager {
} }
``` ```
- 详细解释 - Details
`filterAuth` 默认值为 `true`,即进行权限过滤。 The default value of `filterAuth` is `true`, which means it performs permission filtering.
- 示例 - Example
```tsx | pure ```tsx | pure
const Demo = () => { const Demo = () => {
@ -180,9 +180,9 @@ const Demo = () => {
### pluginSettingsManager.has() ### pluginSettingsManager.has()
判断是否存在,内部已进行权限过滤。 Check if it exists, with internal permission filtering.
- 类型 - Type
```tsx | pure ```tsx | pure
class PluginSettingsManager { class PluginSettingsManager {
@ -190,7 +190,7 @@ class PluginSettingsManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -202,7 +202,7 @@ class MyPlugin extends Plugin {
### pluginSettingsManager.remove() ### pluginSettingsManager.remove()
移除配置。 Remove configuration.
```tsx | pure ```tsx | pure
class PluginSettingsManager { class PluginSettingsManager {
@ -212,9 +212,9 @@ class PluginSettingsManager {
### pluginSettingsManager.getRouteName() ### pluginSettingsManager.getRouteName()
获取对应路由的名称。 Get the name of the corresponding route.
- 类型 - Type
```tsx | pure ```tsx | pure
class PluginSettingsManager { class PluginSettingsManager {
@ -222,7 +222,7 @@ class PluginSettingsManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -234,9 +234,9 @@ class MyPlugin extends Plugin {
### pluginSettingsManager.getRoutePath() ### pluginSettingsManager.getRoutePath()
获取插件配置对应的页面路径。 Get the page path corresponding to the plugin configuration.
- 类型 - Type
```tsx | pure ```tsx | pure
class PluginSettingsManager { class PluginSettingsManager {
@ -244,7 +244,7 @@ class PluginSettingsManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const Demo = () => { const Demo = () => {
@ -260,7 +260,7 @@ const Demo = () => {
### pluginSettingsManager.hasAuth() ### pluginSettingsManager.hasAuth()
单独判断是否权限。 Check the permission separately.
```tsx | pure ```tsx | pure
class PluginSettingsManager { class PluginSettingsManager {

View File

@ -1,8 +1,8 @@
# Plugin # Plugin
Plugin 基类。 Plugin Base Class.
- 类型 - Type
```tsx | pure ```tsx | pure
class Plugin<T = any> { class Plugin<T = any> {
@ -46,24 +46,23 @@ class Plugin<T = any> {
} }
``` ```
- 详细信息 - Details
- Constructor
- 构造函数 - `options`: There are two ways to add a plugin. One way is to load it remotely from the plugin list, and the other way is to add it through the [PluginManager](/core/application/plugin-manager).
- `options` 插件的添加有两种方式,一种方式从插件列表中远程加载出来,另一种方式是通过 [PluginManager](/core/application/plugin-manager) 添加 - Remote loading: `options` will be automatically injected with `{ name: 'npm package.name' }`.
- 远程加载:`options` 会被自动注入 `{ name: 'npm package.name' }` - PluginManager `options` are passed by the user.
- PluginManager `options` 由用户自己传递 - `app`: This parameter is automatically injected and represents the application instance.
- `app`:此参数是自动注入的,是应用实例 - Shortcut Access: The base class provides shortcut access to some methods and properties of `app`.
- 快捷访问:基类提供了对 `app` 部分方法和属性的快捷访问
- `pluginManager` - `pluginManager`
- `router` - `router`
- `pluginSettingsManager` - `pluginSettingsManager`
- `schemaSettingsManager` - `schemaSettingsManager`
- `schemaInitializerManager` - `schemaInitializerManager`
- 声明周期 - Lifecycle
- `afterAdd`:插件被添加后立即执行 - `afterAdd`: Executed immediately after the plugin is added.
- `beforeLoad`:执行渲染时执行,在 `afterAdd` 之后,`load` 之前 - `beforeLoad`: Executed during rendering, after `afterAdd` and before `load`.
- `load`:最后执行 - `load`: Executed last.
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -79,10 +78,10 @@ class MyPlugin extends Plugin {
async load() { async load() {
console.log('load') console.log('load')
// 可以访问应用实例 // You can access the application instance
console.log(this.app) console.log(this.app)
// 访问应用实例内容 // Access the application instance content
console.log(this.app.router, this.router); console.log(this.app.router, this.router);
} }
} }

View File

@ -1,6 +1,6 @@
# RouterManager # RouterManager
用于管理路由。 Used for managing routes.
```tsx | pure ```tsx | pure
import { ComponentType } from 'react'; import { ComponentType } from 'react';
@ -22,13 +22,13 @@ class RouterManager {
} }
``` ```
## 实例方法 ## Instance Methods
### router.add() ### router.add()
添加一条路由。 Add a route.
- 类型 - Type
```tsx | pure ```tsx | pure
class RouterManager { class RouterManager {
@ -36,15 +36,15 @@ class RouterManager {
} }
``` ```
- 详情 - Details
第一个参数 `name`,是路由唯一标识,用于后续的删改查,并且 `name` 支持 `.` 用于分割层级,不过需要注意当使用 `.` 分层的时候,父级要使用 [Outlet](https://reactrouter.com/en/main/components/outlet),让子元素能正常渲染。 The first parameter `name` is the unique identifier for the route, used for subsequent operations such as modification and retrieval. The `name` also supports using `.` to separate hierarchical levels. However, when using `.` for hierarchy, the parent level should use [Outlet](https://reactrouter.com/en/main/components/outlet) to ensure proper rendering of child elements.
第二个参数 `RouteType``Component` 支持组件形式和字符串形式,如果是字符串组件,要先通过 [app.addComponents](/core/application/application#appaddcomponents) 进行注册。 The second parameter `RouteType` has a `Component` property that supports both component and string forms. If using a string component, it needs to be registered first using [app.addComponents](/core/application/application#appaddcomponents).
- 示例 - Example
单层级路由。 Single-level routing.
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -106,7 +106,7 @@ const app = new Application({
export default app.getRootComponent(); export default app.getRootComponent();
``` ```
多层级路由。 Multi-level routing.
```tsx | pure ```tsx | pure
import { Plugin } from '@nocobase/client'; import { Plugin } from '@nocobase/client';
@ -178,7 +178,7 @@ const app = new Application({
export default app.getRootComponent(); export default app.getRootComponent();
``` ```
`Component` 参数为字符串。 The `Component` parameter is a string.
```tsx | pure ```tsx | pure
const LoginPage = () => { const LoginPage = () => {
@ -200,9 +200,9 @@ class MyPlugin extends Plugin {
### router.getRoutes() ### router.getRoutes()
获取路由列表。 Get the list of routes.
- 类型 - Type
```tsx | pure ```tsx | pure
class RouterManager { class RouterManager {
@ -210,7 +210,7 @@ class RouterManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -224,9 +224,9 @@ class MyPlugin extends Plugin {
### router.getRoutesTree() ### router.getRoutesTree()
获取用于 [useRoutes()](https://reactrouter.com/hooks/use-routes) 的数据。 Get the data for [useRoutes()](https://reactrouter.com/hooks/use-routes).
- 类型 - Type
```tsx | pure ```tsx | pure
class RouterManager { class RouterManager {
@ -234,7 +234,7 @@ class RouterManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -246,9 +246,9 @@ class MyPlugin extends Plugin {
### router.get() ### router.get()
获取单个路由配置。 Get a single route configuration.
- 类型 - Type
```tsx | pure ```tsx | pure
class RouterManager { class RouterManager {
@ -256,7 +256,7 @@ class RouterManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -269,9 +269,9 @@ class MyPlugin extends Plugin {
### router.has() ### router.has()
判断是否添加过路由。 Check if a route has been added.
- 类型 - Type
```tsx | pure ```tsx | pure
class RouterManager { class RouterManager {
@ -279,7 +279,7 @@ class RouterManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -292,9 +292,9 @@ class MyPlugin extends Plugin {
### router.remove() ### router.remove()
移除路由配置。 Remove route configuration.
- 类型 - Type
```tsx | pure ```tsx | pure
class RouterManager { class RouterManager {
@ -302,7 +302,7 @@ class RouterManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -315,10 +315,10 @@ class MyPlugin extends Plugin {
### router.setType() ### router.setType()
设置路由类型,默认为 `browser` Set the router type, default is `browser`.
- 类型 - Type
```tsx | pure ```tsx | pure
class RouterManager { class RouterManager {
@ -326,12 +326,12 @@ class RouterManager {
} }
``` ```
- 详细解释 - Details
- browser: [BrowserRouter](https://reactrouter.com/en/main/router-components/browser-router) - browser: [BrowserRouter](https://reactrouter.com/en/main/router-components/browser-router)
- memory: [MemoryRouter](https://reactrouter.com/en/main/router-components/hash-router) - memory: [MemoryRouter](https://reactrouter.com/en/main/router-components/hash-router)
- hash: [HashRouter](https://reactrouter.com/en/main/router-components/memory-router) - hash: [HashRouter](https://reactrouter.com/en/main/router-components/memory-router)
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -343,9 +343,9 @@ class MyPlugin extends Plugin {
### router.setBasename() ### router.setBasename()
设置 [basename](https://reactrouter.com/en/main/router-components/browser-router#basename) Set [basename](https://reactrouter.com/en/main/router-components/browser-router#basename).
- 类型 - Type
```tsx | pure ```tsx | pure
class RouterManager { class RouterManager {
@ -353,7 +353,7 @@ class RouterManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -367,15 +367,15 @@ class MyPlugin extends Plugin {
### useRouter() ### useRouter()
获取当前路由的实例,等同于 `app.router` Get the instance of the current route, equivalent to `app.router`.
- 类型 - Type
```tsx | pure ```tsx | pure
const useRouter: () => RouterManager const useRouter: () => RouterManager
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
import { useRouter } from '@nocobase/client'; import { useRouter } from '@nocobase/client';

View File

@ -1,10 +1,10 @@
# CollectionRecordProvider # CollectionRecordProvider
用于提供 [CollectionRecord](./collection-record) 实例。 Used to provide instances of [CollectionRecord](./collection-record).
## 组件 ## Component
- 类型 - Type
```tsx | pure ```tsx | pure
interface CollectionRecordProviderProps<DataType = {}, ParentDataType = {}> { interface CollectionRecordProviderProps<DataType = {}, ParentDataType = {}> {
@ -12,21 +12,21 @@ interface CollectionRecordProviderProps<DataType = {}, ParentDataType = {}> {
record?: CollectionRecord<DataType, ParentDataType> | DataType; record?: CollectionRecord<DataType, ParentDataType> | DataType;
parentRecord?: CollectionRecord<ParentDataType> | DataType; parentRecord?: CollectionRecord<ParentDataType> | DataType;
/** /**
* 当前记录所属的 collection name * The collection name to which the current record belongs
*/ */
collectionName?: string; collectionName?: string;
} }
``` ```
- 详解 - Details
参数的具体说明参见 [CollectionRecord](./collection-record)。 The specific description of the parameters can be found in [CollectionRecord](./collection-record).
需要说明的是 `record``parentRecord` 即可以是普通的对象,也可以是 [CollectionRecord](./collection-record) 实例,但最终会转为 `CollectionRecord` 实例,并通过 context 传递给子组件。 It should be noted that both `record` and `parentRecord` can be either plain objects or instances of [CollectionRecord](./collection-record). However, they will ultimately be converted to `CollectionRecord` instances and passed to child components through context.
## 示例 ## Example
- record 参数为 CollectionRecord 实例 - The `record` parameter is an instance of `CollectionRecord`.
```tsx | pure ```tsx | pure
import { CollectionRecord, CollectionRecordProvider } from '@nocobase/client'; import { CollectionRecord, CollectionRecordProvider } from '@nocobase/client';
@ -34,7 +34,7 @@ import { CollectionRecord, CollectionRecordProvider } from '@nocobase/client';
const record = new CollectionRecord({ data: { id: 1, name: 'foo' } }); const record = new CollectionRecord({ data: { id: 1, name: 'foo' } });
<CollectionRecordProvider record={record} /> <CollectionRecordProvider record={record} />
// 最终向子组件传递的数据为: props.record // The data passed to child components is: props.record
``` ```
```tsx ```tsx
@ -50,11 +50,11 @@ const Demo = () => {
export default () => <CollectionRecordProvider record={record}><Demo /></CollectionRecordProvider> export default () => <CollectionRecordProvider record={record}><Demo /></CollectionRecordProvider>
``` ```
- record 参数为普通对象 - The `record` parameter is a plain object.
```tsx | pure ```tsx | pure
<CollectionRecordProvider record={{ id: 1, name: 'foo' }} /> <CollectionRecordProvider record={{ id: 1, name: 'foo' }} />
// 最终向子组件传递的数据为: const record = new CollectionRecord({ data: { id: 1, name: 'foo' } }); // The data passed to child components is: const record = new CollectionRecord({ data: { id: 1, name: 'foo' } });
``` ```
```tsx ```tsx
@ -68,14 +68,14 @@ const Demo = () => {
export default () => <CollectionRecordProvider record={{ id: 1, name: 'foo' }}><Demo /></CollectionRecordProvider> export default () => <CollectionRecordProvider record={{ id: 1, name: 'foo' }}><Demo /></CollectionRecordProvider>
``` ```
- record 参数为 CollectionRecord 实例且带有父记录 - The `record` parameter is an instance of `CollectionRecord` with a parent record.
```tsx | pure ```tsx | pure
const parentRecord = new CollectionRecord({ data: { id: 1, role: 'admin' } }); const parentRecord = new CollectionRecord({ data: { id: 1, role: 'admin' } });
const record = new CollectionRecord({ data: { id: 1, name: 'foo' }, parentRecord }); const record = new CollectionRecord({ data: { id: 1, name: 'foo' }, parentRecord });
<CollectionRecordProvider record={record} /> <CollectionRecordProvider record={record} />
// 最终向子组件传递的数据为: props.record // The data passed to child components is: props.record
``` ```
```tsx ```tsx
@ -92,7 +92,7 @@ const Demo = () => {
export default () => <CollectionRecordProvider record={record}><Demo /></CollectionRecordProvider> export default () => <CollectionRecordProvider record={record}><Demo /></CollectionRecordProvider>
``` ```
- record 参数为 CollectionRecord 实例,父记录通过 `parentRecord` 参数传递 - The `record` parameter is an instance of `CollectionRecord`, and the parent record is passed through the `parentRecord` parameter.
```tsx | pure ```tsx | pure
const parentRecord = new CollectionRecord({ data: { id: 1, role: 'admin' } }); const parentRecord = new CollectionRecord({ data: { id: 1, role: 'admin' } });
@ -100,8 +100,8 @@ const record = new CollectionRecord({ data: { id: 1, name: 'foo' } });
<CollectionRecordProvider record={record} parentRecord={parentRecord} /> <CollectionRecordProvider record={record} parentRecord={parentRecord} />
// 首先设置父记录:record.setParentRecord(parentRecord); // First, set the parent record: record.setParentRecord(parentRecord);
// 最终向子组件传递的数据为record带有父记录 // The data passed to child components is: record (with parent record)
``` ```
```tsx ```tsx
@ -118,15 +118,15 @@ const Demo = () => {
export default () => <CollectionRecordProvider record={record} parentRecord={parentRecord}><Demo /></CollectionRecordProvider> export default () => <CollectionRecordProvider record={record} parentRecord={parentRecord}><Demo /></CollectionRecordProvider>
``` ```
- record 参数为普通对象,父记录也是普通对象 - The `record` parameter is a plain object, and the parent record is also a plain object.
```tsx | pure ```tsx | pure
<CollectionRecordProvider record={{ id: 1, name: 'foo' }} parentRecord={{ id: 1, role: 'admin' }} /> <CollectionRecordProvider record={{ id: 1, name: 'foo' }} parentRecord={{ id: 1, role: 'admin' }} />
// 首先实例化父记录:const parentRecord = new CollectionRecord({ data: { id: 1, role: 'admin' } }); // First, instantiate the parent record: const parentRecord = new CollectionRecord({ data: { id: 1, role: 'admin' } });
// 然后实例化记录:const record = new CollectionRecord({ data: { id: 1, name: 'foo' } }); // Then, instantiate the record: const record = new CollectionRecord({ data: { id: 1, name: 'foo' } });
// 最后设置父记录:record.setParentRecord(parentRecord); // Finally, set the parent record: record.setParentRecord(parentRecord);
// 最终向子组件传递的数据为record带有父记录 // The data passed to child components is: record (with parent record)
``` ```
@ -145,9 +145,9 @@ export default () => <CollectionRecordProvider record={{ id: 1, name: 'foo' }} p
### useCollectionRecord() ### useCollectionRecord()
用于获取 `CollectionRecordProvider` 组件传递的数据记录。 Used to retrieve the data record passed by the `CollectionRecordProvider` component.
- 示例 - Example
```tsx | pure ```tsx | pure
const record = useCollectionRecord(); const record = useCollectionRecord();
@ -173,9 +173,9 @@ export default () => <CollectionRecordProvider record={{ id: 1, name: 'foo' }} p
### useCollectionRecordData() ### useCollectionRecordData()
直接获取 CollectionRecord 的 `data` 属性,等同于 `useCollectionRecord().data` Directly accessing the `data` property of CollectionRecord is equivalent to `useCollectionRecord().data`.
- 示例 - Example
```tsx | pure ```tsx | pure
const data = useCollectionRecordData(); const data = useCollectionRecordData();
@ -201,9 +201,9 @@ export default () => <CollectionRecordProvider record={{ id: 1, name: 'foo' }} >
### useCollectionParentRecord() ### useCollectionParentRecord()
直接获取 CollectionRecord 的数据 `parentRecord`,等同于 `useCollectionRecord().parentRecord` Directly accessing the `parentRecord` data of CollectionRecord is equivalent to `useCollectionRecord().parentRecord`.
- 示例 - Example
```tsx | pure ```tsx | pure
const parentRecord = useCollectionParentRecord(); const parentRecord = useCollectionParentRecord();
@ -230,9 +230,9 @@ export default () => <CollectionRecordProvider record={{ id: 1, name: 'foo' }} p
### useCollectionParentRecordData() ### useCollectionParentRecordData()
直接获取 CollectionRecord 的数据 `parentRecord.data`,等同于 `useCollectionRecord().parentRecord.data` Directly accessing the `parentRecord.data` of CollectionRecord is equivalent to `useCollectionRecord().parentRecord.data`.
- 示例 - Example
```tsx | pure ```tsx | pure
const record = useCollectionRecord(); const record = useCollectionRecord();

View File

@ -1,6 +1,6 @@
# CollectionRecord # CollectionRecord
数据表中的一条记录。 A record in a data table.
## 类型 ## 类型
@ -10,7 +10,7 @@ interface CollectionRecordOptions<DataType = {}, ParentDataType = {}> {
data?: DataType; data?: DataType;
parentRecord?: CollectionRecord<ParentDataType>; parentRecord?: CollectionRecord<ParentDataType>;
/** /**
* 当前记录所属的 collection name * The collection name to which the current record belongs
*/ */
collectionName?: string; collectionName?: string;
} }
@ -32,11 +32,11 @@ class CollectionRecord<DataType = {}, ParentDataType = {}> {
} }
``` ```
## 详解 ## Details
### CollectionRecord 基本概念 ### Basic Concepts of CollectionRecord
CollectionRecord 类用于提供数据记录,通常情况下对应着后端数据表中的一条记录。以用户表为例,其一条数据对应的 CollectionRecord 类如下: The CollectionRecord class is used to provide data records, which typically correspond to a single record in a backend database table. Taking the user table as an example, the CollectionRecord class for a single data record is as follows:
```tsx | pure ```tsx | pure
const useCollectionRecord = new CollectionRecord({ const useCollectionRecord = new CollectionRecord({
@ -57,9 +57,9 @@ const useCollectionRecord = new CollectionRecord({
}); });
``` ```
### CollectionRecord 和 Collection 的关系 ### Relationship between CollectionRecord and Collection
CollectionRecord 是指的数据,而 Collection 则是表结构。对于上面的用户表,其对应的 Collection 如下: CollectionRecord refers to the data, while Collection represents the table structure. For the user table mentioned above, its corresponding Collection is as follows:
```tsx | pure ```tsx | pure
const usersCollection = new Collection({ const usersCollection = new Collection({
@ -86,15 +86,15 @@ const usersCollection = new Collection({
}); });
``` ```
### 父子关系和关系字段 ### Parent-Child Relationship and Relationship Fields
对于[关系字段](https://docs.nocobase.com/development/server/collections/association-fields),例如用户和角色的关系,在用户表中会有一个 `roleId` 字段,其值为角色表中的 `id`,当我们通过 `users.roleId` 字段查询用户的角色时: For [relationship fields](https://docs.nocobase.com/development/server/collections/association-fields), such as the relationship between users and roles, there will be a `roleId` field in the users table, with its value being the `id` in the roles table. When we query the role of a user using the `users.roleId` field:
```bash | pure ```bash | pure
GET /api/users/1/roles:get/10 GET /api/users/1/roles:get/10
``` ```
其中 `1` 为用户的 `id``10` 为角色的 `id`,我们可以得到用户的角色数据: Where `1` is the user's `id` and `10` is the role's `id`, we can obtain the user's role data:
```tsx | pure ```tsx | pure
const roleRecord = new CollectionRecord({ const roleRecord = new CollectionRecord({
@ -116,15 +116,15 @@ const roleRecord = new CollectionRecord({
}) })
``` ```
其中 `users` id 为 1 的记录我们称之为父记录: The record with `users` id 1 is referred to as the parent record:
```tsx | pure ```tsx | pure
roleRecord.setParentRecord(userRecord); roleRecord.setParentRecord(userRecord);
``` ```
### 新记录 ### New Record
对于新表单,我们可以通过 `isNew` 属性来标识: For new forms, we can identify them using the `isNew` property:
```tsx | pure ```tsx | pure
const record = new CollectionRecord({ const record = new CollectionRecord({
@ -132,9 +132,9 @@ const record = new CollectionRecord({
}); });
``` ```
## 示例 ## Example
### 基本使用 ### Basic Usage
```tsx | pure ```tsx | pure
import { CollectionRecord } from '@nocobase/client'; import { CollectionRecord } from '@nocobase/client';
@ -146,7 +146,7 @@ const record = new CollectionRecord({
}); });
``` ```
### 创建空记录 ### Creating an Empty Record
```tsx | pure ```tsx | pure
import { CollectionRecord } from '@nocobase/client'; import { CollectionRecord } from '@nocobase/client';
@ -156,9 +156,9 @@ const record = new CollectionRecord({
}); });
``` ```
### 设置 parentRecord ### Set parentRecord
方式1: 通过构造函数设置 Method 1: Setting through the constructor
```tsx | pure ```tsx | pure
const parentRecord = new CollectionRecord({ const parentRecord = new CollectionRecord({
@ -175,7 +175,7 @@ const record = new CollectionRecord({
}); });
``` ```
方式2: 通过 `setParentRecord` 方法设置 Method 2: Setting via the `setParentRecord` method
```tsx | pure ```tsx | pure
const parentRecord = new CollectionRecord({ const parentRecord = new CollectionRecord({

View File

@ -1,16 +1,16 @@
# DataBlockProvider # DataBlockProvider
## 区块类型 ## Block Types
区块分为简单区块和包含各种数据的区块。 Blocks are divided into simple blocks and blocks that contain various data.
### 简单区块 ### Simple Blocks
简单区块例如 Markdown 区块。 Simple blocks, such as Markdown blocks.
![](./images/markdown-block.png) ![](./images/markdown-block.png)
它只有文本内容,没有其他更多复杂数据,且文本内容是存储在 `schema` 中的,没有存储在数据库中。 It only has text content and no other complex data. The text content is stored in the `schema` and not in the database.
```json {5}| pure ```json {5}| pure
{ {
@ -22,24 +22,24 @@
} }
``` ```
### 数据区块 ### Data Blocks
数据区块是指区块的数据存储在服务端的数据表中,例如 Table 组件。 Data blocks refer to blocks whose data is stored in server-side database tables, such as the Table component.
![](./images/data-block.png) ![](./images/data-block.png)
Table 中的字段信息及列表数据,都是存储在数据库中的。 The field information and list data in the Table component are stored in the database.
## DataBlockProvider 介绍 ## Introduction to DataBlockProvider
为了方便对数据区块的数据进行管理,我们提供了 `DataBlockProvider` 组件,其内部封装了: To facilitate the management of data in data blocks, we provide the `DataBlockProvider` component, which encapsulates the following components:
- `DataBlockProvider`:封装了下面的所有组件,并提供了区块属性 - `DataBlockProvider`: Encapsulates all the components below and provides block properties
- [CollectionProvider](/core/data-source/collection-provider) / [AssociationProvider](/core/data-source/association-provider): 根据 `DataBlockProvider` 提供的上下文信息,查询对应数据表数据及关系字段信息并传递 - [CollectionProvider](/core/data-source/collection-provider) / [AssociationProvider](/core/data-source/association-provider): Queries the corresponding data table data and relationship field information based on the context information provided by `DataBlockProvider` and passes them on
- [BlockResourceProvider](/core/data-block/data-block-resource-provider): 根据 `DataBlockProvider` 提供的上下文信息,构建区块 [Resource](/core/request) API用于区块数据的增删改查 - [BlockResourceProvider](/core/data-block/data-block-resource-provider): Constructs the block [Resource](/core/request) API based on the context information provided by `DataBlockProvider`, used for CRUD operations on block data
- [BlockRequestProvider](/core/data-block/data-block-request-provider): 根据 `DataBlockProvider` 提供的上下文信息,自动调用 `BlockResourceProvider` 提供的 `resource.get()``resource.list()` 发起请求,得到区块数据,并传递 - [BlockRequestProvider](/core/data-block/data-block-request-provider): Automatically calls `resource.get()` or `resource.list()` provided by `BlockResourceProvider` based on the context information provided by `DataBlockProvider`, retrieves block data, and passes it on
- [CollectionRecordProvider](/core/data-source/record-provider): 对于 `resource.get()` 场景,会自动嵌套 `CollectionRecordProvider` 并将 `resource.get()` 请求结果传递下去,`resource.list()` 场景则需要自行使用 `CollectionRecordProvider` 提供数据记录 - [CollectionRecordProvider](/core/data-source/record-provider): For the `resource.get()` scenario, it automatically nests `CollectionRecordProvider` and passes the `resource.get()` request result down. For the `resource.list()` scenario, you need to use `CollectionRecordProvider` to provide data records manually.
```tsx | pure ```tsx | pure
const DataBlockProvider = (props) => { const DataBlockProvider = (props) => {
@ -59,17 +59,17 @@ const DataBlockProvider = (props) => {
} }
``` ```
上述组件封装到 `DataBlockProvider` 的内部,只需要使用 `DataBlockProvider` 即可自行得到上述数据。 The above components are encapsulated inside the `DataBlockProvider`, and you only need to use `DataBlockProvider` to obtain the above data.
### 使用方式 ### Usage
其主要使用在区块的 schema [x-decorator](https://docs.nocobase.com/development/client/ui-schema/what-is-ui-schema#x-decorator) 中,例如: It is mainly used in the schema `x-decorator` of the block, for example:
```js {5}| pure ```js {5}| pure
{ {
type: 'void', type: 'void',
name: 'hello-block', name: 'hello-block',
'x-component': 'CardItem', 'x-component': 'CardItem',
'x-decorator': 'DataBlockProvider', 'x-decorator': 'DataBlockProvider',
'x-decorator-props': { 'x-decorator-props': {
collection: 'users', collection: 'users',
@ -83,20 +83,20 @@ const DataBlockProvider = (props) => {
} }
``` ```
### 完整示例 ### Complete Example
<code src="./demos/data-block-provider/complete-demo.tsx"></code> <code src="./demos/data-block-provider/complete-demo.tsx"></code>
## 属性 ## Properties
### 静态属性和动态属性 ### Static Properties and Dynamic Properties
- schema 中的 `x-decorator-props` 称为静态属性,它是一个普通对象,记录区块的配置信息 - The `x-decorator-props` in the schema is called static properties, which is a plain object that records the configuration information of the block.
- schema 中的 `x-use-decorator-props` 中的属性称为动态属性,它是一个 React hook可用于获取例如 URL 上的 ID或者父级的 context 数据 - The properties in `x-use-decorator-props` in the schema are called dynamic properties, which is a React hook that can be used to obtain data such as the ID on the URL or the context data of the parent.
当两者都存在时,会进行深度合并,作为 `DataBlockProvider` 的属性。 When both exist, they will be deeply merged and used as properties of `DataBlockProvider`.
### 属性详解 ### Property Details
```ts | pure ```ts | pure
interface AllDataBlockProps { interface AllDataBlockProps {
@ -112,15 +112,15 @@ interface AllDataBlockProps {
} }
``` ```
- collection`x-decorator-props`):区块的 collection 表名,用于获取区块的字段信息和区块数据 - collection (`x-decorator-props`): The table name of the block's collection, used to retrieve the field information and block data of the block.
- association`x-decorator-props`):区块的关系字段名,用于获取区块的关系字段信息和关系字段数据 - association (`x-decorator-props`): The name of the relationship field of the block, used to retrieve the relationship field information and data of the block.
- dataSource(`x-decorator-props`): 数据源,具体可参考 [Data Modeling](https://docs.nocobase.com/manual/data-modeling) - dataSource (`x-decorator-props`): The data source, refer to [Data Modeling](https://docs.nocobase.com/manual/data-modeling) for details.
- action`x-decorator-props`):区块的请求类型,`list``get` - action (`x-decorator-props`): The request type of the block, either `list` or `get`.
- params`x-decorator-props``x-use-decorator-props`):区块的请求参数,同时存在于 - params (`x-decorator-props` and `x-use-decorator-props`): The request parameters of the block, exist in both `x-decorator-props` and `x-use-decorator-props`.
- filterByTk`x-use-decorator-props`):相当于 `params.filterByTk`,可理解为 `id`,用于获取单条数据 - filterByTk (`x-use-decorator-props`): Equivalent to `params.filterByTk`, can be understood as `id`, used to retrieve a single data.
- sourceId`x-use-decorator-props`):区块的 sourceId配合 `association` 使用,用于获取区块的关系字段数据 - sourceId (`x-use-decorator-props`): The sourceId of the block, used in conjunction with `association` to retrieve the relationship field data of the block.
- record`x-use-decorator-props`):当提供 `record` 时,会使用 `record` 作为区块的数据,不发起请求 - record (`x-use-decorator-props`): When provided, the `record` will be used as the data of the block instead of making a request.
- parentRecord`x-use-decorator-props`):当提供 `parentRecord` 时,会使用 `parentRecord` 作为关系字段的表数据,不发起请求 - parentRecord (`x-use-decorator-props`): When provided, the `parentRecord` will be used as the table data of the relationship field instead of making a request.
```tsx | pure ```tsx | pure
const DataBlockProvider = (props) => { const DataBlockProvider = (props) => {
@ -140,57 +140,41 @@ const DataBlockProvider = (props) => {
} }
``` ```
### 属性组合和场景 ### Property Combinations and Scenarios
这些属性根据不同的场景,共有 8 中情况: These properties have 8 different combinations based on different scenarios:
- collection - collection
- 创建:`collection` - Create: `collection`
- 获取单条数据:`collection` + `action: get` + `params` - Get a single data: `collection` + `action: get` + `params`
- 获取列表数据:`collection` + `action: list` + `params` - Get a list of data: `collection` + `action: list` + `params`
- 使用 `record` 作为数据:`collection` + `record` - Use `record` as data: `collection` + `record`
对于 *获取单条数据**获取列表数据* `params` 非必须。 For *Get a single data* and *Get a list of data*, `params` is optional.
- association - association
- 创建:`association` + `sourceId` - Create: `association` + `sourceId`
- 获取单条数据:`association` + `sourceId` + `action: get` + `params` + `parentRecord` - Get a single data: `association` + `sourceId` + `action: get` + `params` + `parentRecord`
- 获取列表数据:`association` + `sourceId` + `action: list` + `params` + `parentRecord` - Get a list of data: `association` + `sourceId` + `action: list` + `params` + `parentRecord`
- 使用 `record` 作为数据:`association` + `sourceId` + `record` + `parentRecord` - Use `record` as data: `association` + `sourceId` + `record` + `parentRecord`
For *Get a single data* and *Get a list of data*, `params` and `parentRecord` are optional. If `parentRecord` is not provided, it will query the corresponding `collection` based on the `association`, and then query the corresponding `parentRecord` based on the `collection`.
对于 *获取单条数据**获取列表数据* `params``parentRecord` 非必须,当没有 `parentRecord` 会根据 `association` 查询到对应的 `collection`,然后再根据 `collection` 查询到对应的 `parentRecord` ### Property Access and Modification
### 属性获取和修改
#### useDataBlock() #### useDataBlock()
可用于获取和修改 `DataBlockProvider` 的属性。 Used to access and modify the properties of `DataBlockProvider`.
- 类型 - Type
```tsx | pure
interface Result<T extends {} = {}> {
props: AllDataBlockProps & T;
dn: Designable;
}
const useDataBlock: <T extends {}>() => Result<T>
```
- 详解
`props` 就对应着上面的 `AllDataBlockProps`
`dn``Designable` 对象,可用于修改 `DataBlockProvider` 的 UI schema详细见 [Designable](/core/ui-schema/designable)。
- 示例
```tsx | pure ```tsx | pure
const { props, dn } = useDataBlock<{ tableProps: { bordered?: boolean } }>(); const { props, dn } = useDataBlock<{ tableProps: { bordered?: boolean } }>();
// 获取 // get
const checked = props.tableProps.bordered; const checked = props.tableProps.bordered;
// 修改 // change
dn.deepMerge({ dn.deepMerge({
'x-decorator-props': { 'x-decorator-props': {
tableProps: { tableProps: {
@ -202,7 +186,7 @@ dn.deepMerge({
#### useDataBlockProps() #### useDataBlockProps()
相当于 `useDataBlock().props` Equivalent to `useDataBlock().props`.
```tsx | pure ```tsx | pure
const props = useDataBlockProps<{ tableProps: { bordered?: boolean } }>(); const props = useDataBlockProps<{ tableProps: { bordered?: boolean } }>();
@ -210,7 +194,7 @@ const props = useDataBlockProps<{ tableProps: { bordered?: boolean } }>();
const checked = props.tableProps.bordered; const checked = props.tableProps.bordered;
``` ```
## 示例 ## Example
### collection ### collection
@ -232,7 +216,7 @@ const checked = props.tableProps.bordered;
### association ### association
association 与 collection 类似,只是需要提供 `sourceId`,我们以 `Table list` 为例。 association is similar to collection, but it requires providing `sourceId`. Let's take `Table list` as an example.
#### Table list & sourceId #### Table list & sourceId
@ -240,7 +224,7 @@ association 与 collection 类似,只是需要提供 `sourceId`,我们以 `T
#### Table list & parentRecord #### Table list & parentRecord
如果不提供 `sourceId`,则需要提供 `parentRecord`,我们以 `Table list` 为例。 If `sourceId` is not provided, `parentRecord` needs to be provided. Let's take `Table list` as an example.
<code src="./demos/data-block-provider/association-table-list-and-parent-record.tsx"></code> <code src="./demos/data-block-provider/association-table-list-and-parent-record.tsx"></code>

View File

@ -1,10 +1,10 @@
# DataBlockRequestProvider # DataBlockRequestProvider
其内部获取到 [BlockResourceProvider](/core/data-block/data-block-resource-provider) 提供的 `resource`,根据 [BlockProvider](/core/data-block/data-block-provider) 提供的参数,自动调用 `resource.get()` 或者 `resource.list()` 获取的区块的数据,并通过 context 传递下去。 It internally retrieves the `resource` provided by [BlockResourceProvider](/core/data-block/data-block-resource-provider), and based on the parameters provided by [BlockProvider](/core/data-block/data-block-provider), automatically calls `resource.get()` or `resource.list()` to obtain the block data, which is then passed down through the context.
## 请求参数 ## Request Parameters
请求参数是获取 `DataBlockProvider` 提供中的 `params``filterByTk` The request parameters are obtained from the `params` and `filterByTk` within the `DataBlockProvider`.
```ts | pure ```ts | pure
const schema = { const schema = {
@ -12,12 +12,12 @@ const schema = {
'x-decorator-props': { 'x-decorator-props': {
'collection': 'users', 'collection': 'users',
'action': 'list', 'action': 'list',
// 静态参数 // Static props
params: { params: {
pageSize: 10, pageSize: 10,
} }
}, },
// 动态参数 // Dynamic props
'x-use-decorator-props': 'useDynamicDataBlockProps', 'x-use-decorator-props': 'useDynamicDataBlockProps',
} }
@ -30,13 +30,13 @@ const useDynamicDataBlockProps: UseDataBlockProps<'CollectionList'> = () => {
} }
``` ```
会自动调用 `resource.list()` 获取数据,发起 `GET /api/users:list?pageSize=10&size=15` 的请求。 It will automatically call `resource.list()` to fetch the data, making a `GET` request to `/api/users:list?pageSize=10&size=15`.
## Hooks ## Hooks
### useDataBlockRequest() ### useDataBlockRequest()
用于获取请求对象,一般用区块组件中。 Used to obtain the request object, typically within block components.
```tsx | pure ```tsx | pure
const MyTable = () => { const MyTable = () => {
@ -58,18 +58,18 @@ const MyTable = () => {
## Record ## Record
### Get 请求 ### Get Request
对于 `get` 请求,当获取到 `data` 数据后,会通过 `CollectionRecordProvider` 提供 `record` 对象,用于获取当前区块的数据。 For `GET` requests, once the `data` is retrieved, a `record` object is provided through `CollectionRecordProvider`, which is used to obtain the data for the current block.
```ts | pure ```ts | pure
const schema = { const schema = {
'x-decorator': 'DataBlockProvider', 'x-decorator': 'DataBlockProvider',
'x-decorator-props': { 'x-decorator-props': {
'collection': 'users', 'collection': 'users',
'action': 'get', // get 请求 'action': 'get', // get request
}, },
// 动态参数 // Dynamic props
'x-use-decorator-props': 'useDynamicFormProps', 'x-use-decorator-props': 'useDynamicFormProps',
} }
@ -82,19 +82,18 @@ const useDynamicDataBlockProps: UseDataBlockProps<'CollectionGet'> = () => {
} }
``` ```
会自动调用 `resource.get()` 获取数据,发起 `GET /api/users:get/1` 的请求,并通过 `CollectionRecordProvider` 提供上下文。 It will automatically invoke `resource.get()` to retrieve data, making a `GET` request to `/api/users:get/1`, and provide the context through `CollectionRecordProvider`.
```tsx | pure ```tsx | pure
const { data } = useDataBlockRequest(); const { data } = useDataBlockRequest();
const record = useCollectionRecord(); // record 上下文数据 const record = useCollectionRecord(); // record context data
// 相等
record.data === data; record.data === data;
``` ```
### List 请求 ### List Request
对于 `list` 请求则不会提供 `record` 对象,需要自己通过 `<CollectionRecordProvider />` 设置上下文。 For `list` requests, a `record` object will not be provided, and you will need to set the context yourself using `<CollectionRecordProvider />`.
```tsx | pure ```tsx | pure
const MyTable = () => { const MyTable = () => {

View File

@ -1,25 +1,24 @@
# DataBlockResourceProvider # DataBlockResourceProvider
根据 `DataBlockProvider` 中的 `collection``association``sourceId` 等属性,构建好 [resource](/core/request) 对象,方便子组件对区块数据的增删改查操作,其内置在 [DataBlockProvider](/core/data-block/data-block-provider) 中 Builds the `resource` object based on the `collection`, `association`, `sourceId`, and other attributes in the `DataBlockProvider`, facilitating the CRUD operations on block data for child components. It is built-in within the [DataBlockProvider](/core/data-block/data-block-provider).
## useDataBlockResource ## useDataBlockResource
用于获取当前数据块的 resource 对象。 Used to retrieve the `resource` object for the current data block.
- 类型 - Type
```ts | pure ```ts | pure
function useDataBlockResource(): IResource function useDataBlockResource(): IResource
``` ```
- 示例 - Example
```ts | pure ```ts | pure
const resource = useDataBlockResource(); const resource = useDataBlockResource();
const onSubmit = async (values) => { const onSubmit = async (values) => {
// 创建 // create
await resource.create({ values }); await resource.create({ values });
} }
``` ```
@ -28,9 +27,7 @@ const onSubmit = async (values) => {
const resource = useDataBlockResource(); const resource = useDataBlockResource();
const onDelete = async () => { const onDelete = async () => {
// 删除 // delete
await resource.destroy(); await resource.destroy();
} }
``` ```
可运行示例

View File

@ -1,6 +1,6 @@
# AssociationProvider # AssociationProvider
用于传递关联数据字段以及对应的数据表信息,等同于 `CollectionFieldProvider` + `CollectionProvider` Used for passing associated data fields and their corresponding table information, equivalent to `CollectionFieldProvider` + `CollectionProvider`.
```tsx | pure ```tsx | pure
const AssociationProvider = <CollectionFieldProvider name={fieldName}> const AssociationProvider = <CollectionFieldProvider name={fieldName}>
@ -10,4 +10,4 @@ const AssociationProvider = <CollectionFieldProvider name={fieldName}>
</CollectionFieldProvider> </CollectionFieldProvider>
``` ```
关于关系字段的更多信息,请参考 [关系字段](https://docs.nocobase.com/development/server/collections/association-fields) 以及 [CollectionField](/core/data-source/collection-field)。 For more information on relational fields, please refer to [Association Fields](https://docs.nocobase.com/development/server/collections/association-fields) and [CollectionField](/core/data-source/collection-field).

View File

@ -1,23 +1,23 @@
# CollectionFieldInterfaceManager # CollectionFieldInterfaceManager
主要是用来管理 [CollectionFieldInterface](./collection-field-interface.md) 和 [CollectionFieldInterfaceGroups](#collectionfieldinterfacegroups),其被 [DataSourceManager](./data-source-manager) 管理。 It is mainly used to manage [CollectionFieldInterface](./collection-field-interface.md) and [CollectionFieldInterfaceGroups](#collectionfieldinterfacegroups), which are managed by [DataSourceManager](./data-source-manager).
## CollectionFieldInterfaceGroups ## CollectionFieldInterfaceGroups
CollectionFieldInterfaceGroups 是用来对数据表字段进行分组的。 CollectionFieldInterfaceGroups are used to group data table fields.
![Field Groups](./images/field-groups.png) ![Field Groups](./images/field-groups.png)
## 实例方法 ## Instance Methods
### field interface ### field interface
#### addFieldInterfaces() #### addFieldInterfaces()
添加 field interface。 Add field interface。
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionFieldInterfaceManager { class CollectionFieldInterfaceManager {
@ -25,7 +25,7 @@ class CollectionFieldInterfaceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class CheckboxFieldInterface extends CollectionFieldInterface { class CheckboxFieldInterface extends CollectionFieldInterface {
@ -47,9 +47,9 @@ class MyPlugin extends Plugin {
#### getFieldInterface() #### getFieldInterface()
获取 field interface。 Get field interface。
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionFieldInterfaceManager { class CollectionFieldInterfaceManager {
@ -57,7 +57,7 @@ class CollectionFieldInterfaceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -69,9 +69,9 @@ class MyPlugin extends Plugin {
#### getFieldInterfaces() #### getFieldInterfaces()
获取所有的 field interface。 Get all field interface。
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionFieldInterfaceManager { class CollectionFieldInterfaceManager {
@ -79,7 +79,7 @@ class CollectionFieldInterfaceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -93,9 +93,9 @@ class MyPlugin extends Plugin {
#### addFieldInterfaceGroups() #### addFieldInterfaceGroups()
添加 field interface group。 Add field interface group。
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionFieldInterfaceManager { class CollectionFieldInterfaceManager {
@ -103,7 +103,7 @@ class CollectionFieldInterfaceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -128,9 +128,9 @@ class MyPlugin extends Plugin {
#### getFieldInterfaceGroups() #### getFieldInterfaceGroups()
获取所有的 field interface group。 Get all field interface group。
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionFieldInterfaceManager { class CollectionFieldInterfaceManager {
@ -138,7 +138,7 @@ class CollectionFieldInterfaceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -150,9 +150,9 @@ class MyPlugin extends Plugin {
#### getFieldInterfaceGroup() #### getFieldInterfaceGroup()
获取 field interface group。 Get field interface group。
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionFieldInterfaceManager { class CollectionFieldInterfaceManager {
@ -160,7 +160,7 @@ class CollectionFieldInterfaceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {

View File

@ -1,6 +1,6 @@
# CollectionFieldInterface # CollectionFieldInterface
用于创建数据字段。 Used to create data fields.
![](./images/collection-field-interface.png) ![](./images/collection-field-interface.png)
@ -41,7 +41,7 @@ class CollectionFieldInterface {
} }
``` ```
其需要结合 [CollectionManager](./collection-field-interface-manager.md) 使用。 It needs to be used in conjunction with [CollectionManager](./collection-field-interface-manager.md).
```ts ```ts
class EmailFieldInterface extends CollectionFieldInterface { class EmailFieldInterface extends CollectionFieldInterface {
@ -61,28 +61,28 @@ class MyPlugin extends Plugin {
} }
``` ```
## 实例属性 ## Instance Properties
### name ### name
唯一标识符。 Unique identifier.
### group ### group
分组。 Group.
### title ### title
标题。 Title.
### default ### default
配置表单默认值字段 schema。 Configure the default value field schema for the form.
![](./images/collection-field-interface-form.png) ![](./images/collection-field-interface-form.png)
## 实例方法 ## Instance Methods
### collectionFieldInterface.validateSchema(fieldSchema) ### collectionFieldInterface.validateSchema(fieldSchema)

View File

@ -1,6 +1,6 @@
# CollectionField # CollectionField
NocoBase 将字段的 schema 分为 2 部分,一部分在 schema 中,一部分在 collection 中。例如: NocoBase divides the schema of a field into two parts: one in the schema and the other in the collection. For example:
```tsx | pure ```tsx | pure
const schema = { const schema = {
@ -30,15 +30,15 @@ const collection = {
} }
``` ```
两者通过 `name: username` 联系起来,`CollectionField` 会自动读取 schema `name` 属性,并根据 `name` 属性查找 collection 中对应的 `uiSchema` 属性,然后拼接到 schema 中,进行渲染。 The two are connected through `name: username`. The `CollectionField` automatically reads the `name` property from the schema and looks for the corresponding `uiSchema` property in the collection. It then concatenates it to the schema for rendering.
这样做的好处是,对于同一个字段创建的内容,可以在不同的地方共享同一个 schema当 schema 变化时,只需要修改一处即可。比如通过上面的 `title: "UserName"` 假设变化 `title: "Name"` 则所有使用到此字段的地方都会变化。 The benefit of doing this is that for content created with the same field, the same schema can be shared in different places. When the schema changes, only one modification is needed. For example, if we change `title: "UserName"` to `title: "Name"`, it will be reflected in all places where this field is used.
<code src="./demos/collection-field/demo1.tsx"></code> <code src="./demos/collection-field/demo1.tsx"></code>
## CollectionFieldOptions ## CollectionFieldOptions
字段的配置项。 Configuration options for the field.
```ts ```ts
interface CollectionFieldOptions { interface CollectionFieldOptions {
@ -52,13 +52,13 @@ interface CollectionFieldOptions {
} }
``` ```
### 普通字段和关系字段 ### Regular Fields and Relationship Fields
字段有 2 种情况,一种是普通字段,一种是 [关系字段](https://docs-cn.nocobase.com/development/server/collections/association-fields)。 There are two types of fields: regular fields and [relationship fields](https://docs-cn.nocobase.com/development/server/collections/association-fields).
关系字段是指,字段的值是另一个 collection 的数据,例如 `users``roles` 两个 collection`users` 中有一个字段 `roles`,其值是 `roles` collection 的数据,那么 `roles` 就是一个关系字段。 A relationship field refers to a field whose value is data from another collection. For example, if there are two collections, `users` and `roles`, and the `users` collection has a field called `roles` whose value is data from the `roles` collection, then `roles` is a relationship field.
普通字段的示例如下: Here is an example of a regular field:
```json ```json
{ {
@ -81,7 +81,7 @@ interface CollectionFieldOptions {
} }
``` ```
关系字段的示例如下: Here is an example of a relationship field:
```json ```json
{ {
@ -115,24 +115,24 @@ interface CollectionFieldOptions {
} }
``` ```
相对于普通字段,关系字段多了以下属性: Compared to regular fields, relationship fields have the following additional properties:
- xx - xx
- xx - xx
### 全部字段说明 ### Field Descriptions
- `name`:字段名称 - `name`: Field name
- `collectionName`:数据表名称 - `collectionName`: Table name
- `sourceKey`:当字段为关系字段时,对应的关系字段名称。 - `sourceKey`: When the field is a relationship field, it corresponds to the relationship field name.
TODO:补全 TODO
## Hooks ## Hooks
### useCollectionField() ### useCollectionField()
用于获取字段信息。 Used to retrieve field information.
```tsx | pure ```tsx | pure
const collection = { const collection = {
@ -156,7 +156,7 @@ const { uiSchema } = useCollectionField()
const required = uiSchema?.required const required = uiSchema?.required
``` ```
其通常在 [SchemaSettings](/core/ui-schema/schema-settings) 中使用,用来获取和修改字段的属性。 It is usually used in [SchemaSettings](/core/ui-schema/schema-settings) to retrieve and modify field properties.
<code src="./demos/collection-field/demo2.tsx"></code> <code src="./demos/collection-field/demo2.tsx"></code>

View File

@ -2,9 +2,9 @@
用于提供 [CollectionManager](/core/data-source/collection-manager) 实例。 用于提供 [CollectionManager](/core/data-source/collection-manager) 实例。
## 组件 ## Component
- 类型 - Type
```tsx | pure ```tsx | pure
interface CollectionManagerProviderProps { interface CollectionManagerProviderProps {
@ -14,11 +14,11 @@ interface CollectionManagerProviderProps {
} }
``` ```
- 参数详解 - Parameter Details
- `dataSource` - 数据源名称,如果为空,则会取默认数据源。 - `dataSource` - The name of the data source. If empty, the default data source will be used.
- `instance` - CollectionManager 实例,如果没有,则会取 `dataSource` 对应的 collectionManager。 - `instance` - The CollectionManager instance. If not provided, the collectionManager corresponding to the `dataSource` will be used.
- 示例 - Example
```tsx | pure ```tsx | pure
const collectionManager = new CollectionManager(); const collectionManager = new CollectionManager();
@ -36,9 +36,9 @@ const Demo = () => {
### useCollectionManager() ### useCollectionManager()
用于获取 `CollectionManagerProvider` 传递的实例。 Used to retrieve the instance passed by `CollectionManagerProvider`.
- 示例 - Example
```tsx | pure ```tsx | pure
const Demo = () => { const Demo = () => {

View File

@ -1,14 +1,14 @@
# CollectionManager # CollectionManager
用于管理 [Collection](./collection.md),其被 [DataSource](./data-source.md) 管理。 Used to manage [Collection](./collection.md), which is managed by [DataSource](./data-source.md).
## 实例方法 ## Instance Methods
### addCollections(collections) ### addCollections(collections)
添加数据表。 Add collections.
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionManager { class CollectionManager {
@ -16,7 +16,7 @@ class CollectionManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const userCollectionOptions = { const userCollectionOptions = {
@ -32,9 +32,9 @@ collectionManager.addCollections([userCollectionOptions]);
### setCollections(collections) ### setCollections(collections)
重置数据表,会先移除所有数据表,然后再调用 `addCollections()` 添加数据表。 Reset collections, which will remove all collections first, and then call `addCollections()` to add collections.
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionManager { class CollectionManager {
@ -46,7 +46,7 @@ class CollectionManager {
由于 [CollectionTemplate](./collection-template.md) 或者 [CollectionMixins](./collection-mixins.md) 的添加会影响 Collection 的实例化,所以提供了重新添加数据表的方法。 由于 [CollectionTemplate](./collection-template.md) 或者 [CollectionMixins](./collection-mixins.md) 的添加会影响 Collection 的实例化,所以提供了重新添加数据表的方法。
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionManager { class CollectionManager {
@ -54,7 +54,7 @@ class CollectionManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const userCollectionInstance = collectionManager.getCollection('users'); const userCollectionInstance = collectionManager.getCollection('users');
@ -63,9 +63,9 @@ collectionManager.reAddCollections([userCollectionInstance]);
### getCollections(predicate?) ### getCollections(predicate?)
获取数据表。 Get a collection.
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionManager { class CollectionManager {
@ -73,7 +73,7 @@ class CollectionManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
collectionManager.getCollections(); // [ userCollection ] collectionManager.getCollections(); // [ userCollection ]
@ -84,9 +84,9 @@ collectionManager.getCollections(collection => collection.name === 'posts'); //
### getCollection(path) ### getCollection(path)
获取数据表。 Get a collection.
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionManager { class CollectionManager {
@ -94,12 +94,12 @@ class CollectionManager {
} }
``` ```
- 详细解释 - Details
- `path` 参数可以是数据表名称,也可以是[关系字段](https://docs.nocobase.com/development/server/collections/association-fields)路径。 - The `path` parameter can be either the name of a collection or a path to a [relationship field](https://docs.nocobase.com/development/server/collections/association-fields).
- `path: 'users'`: 获取 `users` 数据表 - `path: 'users'`: Get the `users` collection.
- `path: 'users.posts'`: 获取 `users` 数据表的 `posts` 关联字段对应的数据表,即 `postCollection` - `path: 'users.posts'`: Get the collection corresponding to the `posts` associated field of the `users` collection, i.e., `postCollection`.
- 示例 - Example
```tsx | pure ```tsx | pure
collectionManager.getCollection('users'); // userCollection collectionManager.getCollection('users'); // userCollection
@ -108,7 +108,7 @@ collectionManager.getCollection('users.posts'); // postCollection
collectionManager.getCollection('users.profileId'); // profileCollection collectionManager.getCollection('users.profileId'); // profileCollection
``` ```
结合 Mixin 使用: Using Mixins:
```tsx | pure ```tsx | pure
const collection = collectionManager.getCollection<TestMixin>('users'); const collection = collectionManager.getCollection<TestMixin>('users');
@ -117,9 +117,9 @@ const collection = collectionManager.getCollection<TestMixin & TestMixin2>('user
### getCollectionFields(collectionName) ### getCollectionFields(collectionName)
获取数据表字段列表。 Get the list of fields for a collection.
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionManager { class CollectionManager {
@ -127,7 +127,7 @@ class CollectionManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
collectionManager.getCollectionFields('users'); // [ { name: 'username', type: 'string', title: 'Username', .. }, { name: 'password', type: 'password', title: 'Password', .. } ] collectionManager.getCollectionFields('users'); // [ { name: 'username', type: 'string', title: 'Username', .. }, { name: 'password', type: 'password', title: 'Password', .. } ]
@ -135,9 +135,9 @@ collectionManager.getCollectionFields('users'); // [ { name: 'username', type: '
### getCollectionName(path) ### getCollectionName(path)
获取数据表名称。 Get the collection name.
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionManager { class CollectionManager {
@ -145,7 +145,7 @@ class CollectionManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
collectionManager.getCollectionName('users'); // 'users' collectionManager.getCollectionName('users'); // 'users'
@ -156,9 +156,9 @@ collectionManager.getCollectionName('users.profiles'); // 'profiles'
### getCollectionField(path) ### getCollectionField(path)
获取数据表字段。 Get collection fields.
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionManager { class CollectionManager {
@ -166,10 +166,10 @@ class CollectionManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
collectionManager.getCollectionField('users.username'); // { name: 'username', type: 'string', title: 'Username', .. } collectionManager.getCollectionField('users.username'); // { name: 'username', type: 'string', title: 'Username', .. }
collectionManager.getCollectionField('users.roles.name'); // 获取 roles 关联字段对应的 roles 表中的 name 字段 collectionManager.getCollectionField('users.roles.name'); // Get the 'name' field in the 'roles' table corresponding to the 'roles' associated field
``` ```

View File

@ -1,7 +1,7 @@
## Collection Mixins ## Collection Mixins
Collection Mixins 是为扩展 Collection 类提供的一种机制,可以通过 `dataSourceManager.addCollectionMixins()` 添加 Collection Mixins。 Collection Mixins are a mechanism for extending the Collection class, and can be added using `dataSourceManager.addCollectionMixins()`.
### 定义和注册 ### 定义和注册
@ -22,9 +22,9 @@ class MyPlugin extends Plugin {
} }
``` ```
### 使用 ### Usage
- 使用方式1`CollectionManager` 实例上调用 `getCollection()` 获取指定 `Collection` 实例。 - Method 1: Call `getCollection()` on the `CollectionManager` instance to retrieve a specific `Collection` instance.
```tsx | pure ```tsx | pure
const Demo = () => { const Demo = () => {
@ -35,7 +35,7 @@ const Demo = () => {
} }
``` ```
- 使用方式2调用 `useCollection()` 获取当前上下文的数据表信息。 - Usage 2: Call `useCollection()` to get the table information of the current context.
```tsx | pure ```tsx | pure
const Demo = () => { const Demo = () => {
@ -44,9 +44,9 @@ const Demo = () => {
} }
``` ```
### 多个 Mixins 的使用 ### Usage of Multiple Mixins
如果添加了 Mixins可通过如下方式获得类型提示 If you have added mixins, you can get type hints using the following method:
```tsx | pure ```tsx | pure
const Demo = () => { const Demo = () => {

View File

@ -1,12 +1,12 @@
# CollectionProvider # CollectionProvider
用于提供 [Collection](/core/data-source/collction) 实例。 Used to provide an instance of [Collection](/core/data-source/collection).
## 组件 ## Component
### CollectionProvider ### CollectionProvider
- 类型 - Type
```tsx | pure ```tsx | pure
interface CollectionProviderProps { interface CollectionProviderProps {
@ -16,13 +16,13 @@ interface CollectionProviderProps {
} }
``` ```
- 详解 - Details
组件会根据 `name` 去 [CollectionManager](/core/data-source/collection-manager) 中查询数据表信息,如果查询不到,则会不进行渲染。 The component will query the table information from the [CollectionManager](/core/data-source/collection-manager) based on the `name`. If the query fails, it will not be rendered.
`dataSource` 用于指定数据表所在的[命名空间](/core/data-source/collection-manager#datasource),如果不指定,则默认命名空间。 The `dataSource` is used to specify the namespace of the table in the [CollectionManager](/core/data-source/collection-manager#datasource). If not specified, the default namespace will be used.
- 示例 - Example
```tsx | pure ```tsx | pure
import { CollectionProvider } from '@nocobase/client'; import { CollectionProvider } from '@nocobase/client';
@ -36,12 +36,11 @@ const MyComponent = () => {
} }
``` ```
## Hooks ## Hooks
### useCollection() ### useCollection()
用于获取 `CollectionProvider` 传递的 `Collection` 实例。 Used to retrieve the `Collection` instance passed by `CollectionProvider`.
```tsx | pure ```tsx | pure
const collection = useCollection() const collection = useCollection()
@ -50,14 +49,14 @@ console.log(collection instanceof Collection) // true
console.log(collection); console.log(collection);
``` ```
结合 Mixin 使用: Using Mixins:
```tsx | pure ```tsx | pure
const collection = useCollection<TestMixin>() const collection = useCollection<TestMixin>()
const collection = useCollection<TestMixin & TestMixin2>() const collection = useCollection<TestMixin & TestMixin2>()
``` ```
## 示例 ## Example
<code src="./demos/collection/demo1.tsx"></code> <code src="./demos/collection/demo1.tsx"></code>

View File

@ -1,14 +1,14 @@
# CollectionTemplateManager # CollectionTemplateManager
用于管理 [CollectionTemplate](./collection-template),其被 [DataSourceManager](./data-source-manager) 管理。 Used to manage [CollectionTemplate](./collection-template), which is managed by [DataSourceManager](./data-source-manager).
## 实例方法 ## Instance Methods
### addCollectionTemplates() ### addCollectionTemplates()
用于添加 collection template。 Used to add collection templates.
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionTemplateManager { class CollectionTemplateManager {
@ -16,7 +16,7 @@ class CollectionTemplateManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class SqlCollectionTemplate extends CollectionTemplate { class SqlCollectionTemplate extends CollectionTemplate {
@ -49,9 +49,9 @@ class MyPlugin extends Plugin {
### getCollectionTemplate() ### getCollectionTemplate()
用于获取 collection template。 Used to retrieve collection templates.
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionTemplateManager { class CollectionTemplateManager {
@ -59,7 +59,7 @@ class CollectionTemplateManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
collectionManager.getCollectionTemplate(); // generalCollectionTemplate collectionManager.getCollectionTemplate(); // generalCollectionTemplate
@ -69,9 +69,9 @@ collectionManager.getCollectionTemplate('tree'); // treeCollectionTemplate
### getCollectionTemplates() ### getCollectionTemplates()
用于获取所有 collection templates。 Used to retrieve all collection templates.
- 类型 - Type
```tsx | pure ```tsx | pure
class CollectionTemplateManager { class CollectionTemplateManager {
@ -79,7 +79,7 @@ class CollectionTemplateManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
collectionManager.getCollectionTemplates(); // [ generalCollectionTemplate, treeCollectionTemplate, sqlCollectionTemplate ] collectionManager.getCollectionTemplates(); // [ generalCollectionTemplate, treeCollectionTemplate, sqlCollectionTemplate ]

View File

@ -1,6 +1,6 @@
# CollectionTemplate # CollectionTemplate
用于创建数据表的模板。 Template used for creating data tables.
![](./images/collection-template.png) ![](./images/collection-template.png)
@ -15,27 +15,27 @@ interface AvailableFieldInterfacesExclude {
interface CollectionTemplateDefaultOptions { interface CollectionTemplateDefaultOptions {
/** /**
* 自动生成 id * Auto-generate id
* @default true * @default true
* */ * */
autoGenId?: boolean; autoGenId?: boolean;
/** 创建人 */ /** Created by */
createdBy?: boolean; createdBy?: boolean;
/** 最后更新人 */ /** Updated by */
updatedBy?: boolean; updatedBy?: boolean;
/** 创建日期 */ /** Created at */
createdAt?: boolean; createdAt?: boolean;
/** 更新日期 */ /** Updated at */
updatedAt?: boolean; updatedAt?: boolean;
/** 可排序 */ /** Sortable */
sortable?: boolean; sortable?: boolean;
/* 树结构 */ /* Tree structure */
tree?: string; tree?: string;
/* 日志 */ /* Logging */
logging?: boolean; logging?: boolean;
/** 继承 */ /** Inherits */
inherits?: string | string[]; inherits?: string | string[];
/* 字段列表 */ /* Field list */
fields?: CollectionOptions['fields']; fields?: CollectionOptions['fields'];
} }
@ -48,27 +48,27 @@ class CollectionTemplate {
transform?: (collection: CollectionOptions, app: Application) => CollectionOptions; transform?: (collection: CollectionOptions, app: Application) => CollectionOptions;
title?: string; title?: string;
color?: string; color?: string;
/** 排序 */ /** Order */
order?: number; order?: number;
/** 默认配置 */ /** Default configuration */
default?: CollectionTemplateDefaultOptions; default?: CollectionTemplateDefaultOptions;
events?: any; events?: any;
/** UI 可配置的 CollectionOptions 参数(添加或编辑的 Collection 表单的字段) */ /** UI configurable CollectionOptions parameters (fields in the form for adding or editing Collection) */
configurableProperties?: Record<string, ISchema>; configurableProperties?: Record<string, ISchema>;
/** 当前模板可用的字段类型 */ /** Available field interfaces for the current template */
availableFieldInterfaces?: AvailableFieldInterfacesInclude | AvailableFieldInterfacesExclude; availableFieldInterfaces?: AvailableFieldInterfacesInclude | AvailableFieldInterfacesExclude;
/** 是否分割线 */ /** Divider */
divider?: boolean; divider?: boolean;
/** 模板描述 */ /** Template description */
description?: string; description?: string;
/**配置字段中的操作按钮 */ /** Configure actions in the configuration fields */
configureActions?: Record<string, ISchema>; configureActions?: Record<string, ISchema>;
//是否禁止删除字段 // Whether to forbid field deletion
forbidDeletion?: boolean; forbidDeletion?: boolean;
} }
``` ```
其需要结合 [CollectionManager](./collection-template-manager.md) 使用。 It needs to be used in conjunction with [CollectionManager](./collection-template-manager.md).
```ts ```ts
import { Plugin, Collection, CollectionTemplate } from '@nocobase/client'; import { Plugin, Collection, CollectionTemplate } from '@nocobase/client';
@ -103,24 +103,24 @@ class MyPlugin extends Plugin {
} }
``` ```
## 实例属性 ## Instance Properties
### name ### name
模板的唯一标识符。 The unique identifier of the template.
### Collection ### Collection
模板对应的数据表类。 The data table class corresponding to the template.
在创建数据表后Collection 会有 [template 字段](/core/data-source/collection#collectionoptions),用于标识该数据表是由哪个模板创建的。 After creating a data table, the Collection will have a [template field](/core/data-source/collection#collectionoptions) to identify which template the data table was created from.
当通过 `collectionManager.addCollections()` 添加数据表对象时,会先读取 `collection.template` 字段,然后通过 `collectionManager.getCollectionTemplate(collection.template)` 获取到 `collectionTemplate` When adding data table objects through `collectionManager.addCollections()`, it first reads the `collection.template` field, and then retrieves the `collectionTemplate` through `collectionManager.getCollectionTemplate(collection.template)`.
读取 `collectionTemplate.Collection` 字段,并通过 `new collectionTemplate.Collection(collection)` 创建对应的实例。 It reads the `collectionTemplate.Collection` field and creates the corresponding instance through `new collectionTemplate.Collection(collection)`.
如果不传递 `Collection`,则会通过 `new Collection(collection)` 创建对应的实例。 If `Collection` is not passed, it creates the corresponding instance through `new Collection(collection)`.
```ts ```ts
class SqlCollection extends Collection { class SqlCollection extends Collection {
@ -146,24 +146,23 @@ const userCollection = {
### title ### title
模板的标题。 The title of the template.
### color ### color
模板的颜色。 The color of the template.
### order ### order
模板的排序。 The order of the template.
### events ### events
- `beforeSubmit`:提交前触发 - `beforeSubmit`: Triggered before submission.
### configurableProperties ### configurableProperties
表单配置项。 Form configuration items.
![](./images//collection-template-form.png) ![](./images//collection-template-form.png)
@ -197,23 +196,21 @@ class SqlCollectionTemplate extends CollectionTemplate {
### default ### default
表单默认值。 Default form values.
## Instance Methods
## 实例方法
### collectionTemplate.transform(collection) ### collectionTemplate.transform(collection)
collection 创建后,会调用该方法,用于对 collection 进行转换。 After creating a collection, this method is called to transform the collection.
## Utils ## Utils
### getConfigurableProperties() ### getConfigurableProperties()
用于获取内置的配置项字段。 Used to retrieve built-in configurable property fields.
- 类型 - Type
```tsx | pure ```tsx | pure
export type DefaultConfigurableKeys = export type DefaultConfigurableKeys =
@ -233,7 +230,7 @@ export type DefaultConfigurableKeys =
const getConfigurableProperties: (...keys: DefaultConfigurableKeys[]) => Record<DefaultConfigurableKeys, any> const getConfigurableProperties: (...keys: DefaultConfigurableKeys[]) => Record<DefaultConfigurableKeys, any>
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
import { getConfigurableProperties } from '@nocobase/client'; import { getConfigurableProperties } from '@nocobase/client';

View File

@ -1,6 +1,6 @@
# Collection # Collection
Collection 数据表类,其被 [CollectionManager](/core/data-source/collection-manager) 管理。 The Collection class represents a data table and is managed by the [CollectionManager](/core/data-source/collection-manager).
## 类型 ## 类型
@ -107,15 +107,15 @@ export interface CollectionOptions {
} }
``` ```
- name: Collection 的标识,必须唯一。 - name: The identifier of the Collection, must be unique.
- title: Collection 的标题,用于显示。 - title: The title of the Collection, used for display.
- fields: 字段列表,详细说明请查看 [CollectionField](/core/data-source/collection-field) - fields: The list of fields, for more details please refer to [CollectionField](/core/data-source/collection-field)
- template: 模板标识,用于标识该 Collection 是由哪个模板创建的,详细说明请查看 [CollectionTemplate](/core/data-source/collection-template) - template: The template identifier, used to identify which template the Collection is created from, for more details please refer to [CollectionTemplate](/core/data-source/collection-template)
- dataSource: 数据源标识,用于标识该 Collection 是由哪个数据源创建的,详细说明请查看 [CollectionDataSource](/core/data-source/collection-manager#datasource) - dataSource: The data source identifier, used to identify which data source the Collection is created from, for more details please refer to [CollectionDataSource](/core/data-source/collection-manager#datasource)
- duplicator - duplicator
@ -134,7 +134,7 @@ export interface CollectionOptions {
- repository - repository
## 实例属性 ## Instance Properties
### collection.collectionManager ### collection.collectionManager
@ -142,19 +142,19 @@ export interface CollectionOptions {
### collection.titleFieldName ### collection.titleFieldName
标题字段的 name 属性。 The `name` property of the title field.
### 其他属性 ### Other Properties
其他属性同 [CollectionOptions](/core/data-source/collection#collectionoptions)。 Other properties are the same as [CollectionOptions](/core/data-source/collection#collectionoptions).
## 实例方法 ## Instance Methods
### collection.getOptions() ### collection.getOptions()
获取 collection 的所有配置项。 Get all configuration options of the collection.
- 类型 - Type
```tsx | pure ```tsx | pure
class Collection { class Collection {
@ -162,7 +162,7 @@ class Collection {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const usersCollection = new Collection({ const usersCollection = new Collection({
@ -178,9 +178,9 @@ console.log(usersCollection.getOptions()); // { name: 'users', title: 'Users', f
### collection.setOptions(options) ### collection.setOptions(options)
设置 collection 的配置项,最终会和默认配置项进行合并。 Set the configuration options for the collection, which will be merged with the default configuration options.
- 类型 - Type
```tsx | pure ```tsx | pure
class Collection { class Collection {
@ -188,7 +188,7 @@ class Collection {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
collection.setOptions({ collection.setOptions({
@ -202,9 +202,9 @@ collection.setOptions({
### collection.getOption(key) ### collection.getOption(key)
获取 collection 的单个配置项。 Get a single configuration option of the collection.
- 类型 - Type
```tsx | pure ```tsx | pure
class Collection { class Collection {
@ -212,7 +212,7 @@ class Collection {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
collection.getOption('name'); // 'users' collection.getOption('name'); // 'users'
@ -221,9 +221,9 @@ collection.getOption('title'); // 'Users'
### collection.getFields(predicate?) ### collection.getFields(predicate?)
获取 collection 的字段列表。 Get the list of fields for the collection.
- 类型 - Type
```tsx | pure ```tsx | pure
class Collection { class Collection {
@ -231,19 +231,19 @@ class Collection {
} }
``` ```
- 详解 - Details
- predicate - predicate
- 类型 - Type
- `CollectionFieldOptions` - `CollectionFieldOptions`
- `(collection: CollectionFieldOptions) => boolean` - `(collection: CollectionFieldOptions) => boolean`
- `keyof CollectionFieldOptions` - `keyof CollectionFieldOptions`
- 说明 - Description
- 如果传递了 `predicate`,则返回符合条件的字段列表 - If `predicate` is provided, it returns a list of fields that meet the condition.
- 如果没有传递 `predicate`,则返回所有字段列表 - If `predicate` is not provided, it returns a list of all fields.
`predicate` 的使用可看参考 [lodash.filter](https://www.lodashjs.com/docs/lodash.filter)。 The usage of `predicate` can be referred to [lodash.filter](https://www.lodashjs.com/docs/lodash.filter).
- 示例 - Example
```tsx | pure ```tsx | pure
collection.getFields(); // [{ name: 'username', type: 'string', primaryKey: true }, { name: 'age', type: 'integer' }] collection.getFields(); // [{ name: 'username', type: 'string', primaryKey: true }, { name: 'age', type: 'integer' }]
@ -257,9 +257,9 @@ collection.getFields(field => field.type === 'string'); // [{ name: 'name', type
### collection.getField(name) ### collection.getField(name)
获取 collection 的单个字段。 Get a single field of the collection.
- 类型 - Type
```tsx | pure ```tsx | pure
class Collection { class Collection {
@ -267,7 +267,7 @@ class Collection {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
collection.getField('username'); // { name: 'username', type: 'string', primaryKey: true } collection.getField('username'); // { name: 'username', type: 'string', primaryKey: true }
@ -275,9 +275,9 @@ collection.getField('username'); // { name: 'username', type: 'string', primaryK
### collection.hasField(name) ### collection.hasField(name)
判断 collection 是否存在某个字段。 Check if a collection has a specific field.
- 类型 - Type
```tsx | pure ```tsx | pure
class Collection { class Collection {
@ -285,7 +285,7 @@ class Collection {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
collection.hasField('username'); // true collection.hasField('username'); // true

View File

@ -1,21 +1,20 @@
# DataSourceManagerProvider # DataSourceManagerProvider
用于提供 `DataSourceManager` 实例。 Used to provide an instance of `DataSourceManager`.
## Hooks ## Hooks
### useDataSourceManager() ### useDataSourceManager()
获取 `DataSourceManager` 实例。 Get an instance of `DataSourceManager`.
- 类型 - Type
```tsx | pure ```tsx | pure
function useDataSourceManager(): DataSourceManager; function useDataSourceManager(): DataSourceManager;
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const MyComponent = () => { const MyComponent = () => {

View File

@ -1,6 +1,6 @@
# DataSourceManager # DataSourceManager
Nocobase 数据源前端体系包含如下内容: The Nocobase front-end data source system includes the following:
- [DataSourceManager](./data-source-manager.md) - [DataSourceManager](./data-source-manager.md)
- [DataSource](./data-source) - [DataSource](./data-source)
@ -14,11 +14,11 @@ Nocobase 数据源前端体系包含如下内容:
- [CollectionMixins](./collection-mixins) - [CollectionMixins](./collection-mixins)
## 实例属性 ## Instance Properties
- collectionTemplateManager - collectionTemplateManager
用于管理 `CollectionTemplate` 实例。 Used to manage instances of `CollectionTemplate`.
```tsx | pure ```tsx | pure
import { Plugin, CollectionTemplate } from '@nocobase/client'; import { Plugin, CollectionTemplate } from '@nocobase/client';
@ -34,11 +34,11 @@ class MyPlugin extends Plugin {
} }
``` ```
详细请参考:[CollectionTemplateManager](./collection-template-manager) Please refer to: [CollectionTemplateManager](./collection-template-manager)
- collectionFieldInterfaceManager - collectionFieldInterfaceManager
用于管理 `CollectionFieldInterface` 实例。 Used to manage instances of `CollectionFieldInterface`.
```tsx | pure ```tsx | pure
import { Plugin, CollectionFieldInterface } from '@nocobase/client'; import { Plugin, CollectionFieldInterface } from '@nocobase/client';
@ -54,15 +54,15 @@ class MyPlugin extends Plugin {
} }
``` ```
详细请参考:[CollectionTemplateManager](./collection-template-manager) Please refer to: [CollectionTemplateManager](./collection-template-manager)
## 实例方法 ## Instance Methods
### addCollectionTemplates() ### addCollectionTemplates()
`CollectionTemplateManager` 的快捷方法,用于添加 `CollectionTemplate` It is a shortcut method of `CollectionTemplateManager` used to add `CollectionTemplate`.
- 类型 - Type
```tsx | pure ```tsx | pure
class DataSourceManager { class DataSourceManager {
@ -70,7 +70,7 @@ class DataSourceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
import { Plugin, CollectionTemplate } from '@nocobase/client'; import { Plugin, CollectionTemplate } from '@nocobase/client';
@ -86,13 +86,12 @@ class MyPlugin extends Plugin {
} }
``` ```
更多详细请参考:[CollectionTemplateManager](./collection-template-manager) Please refer to: [CollectionTemplateManager](./collection-template-manager)
### addFieldInterfaces() ### addFieldInterfaces()
`CollectionFieldInterfaceManager` 的快捷方法,用于添加 `CollectionFieldInterface` It is a shortcut method of `CollectionFieldInterfaceManager` used to add `CollectionFieldInterface`.
- Type
- 类型
```tsx | pure ```tsx | pure
class DataSourceManager { class DataSourceManager {
@ -100,7 +99,7 @@ class DataSourceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
import { Plugin, CollectionFieldInterface } from '@nocobase/client'; import { Plugin, CollectionFieldInterface } from '@nocobase/client';
@ -116,13 +115,13 @@ class MyPlugin extends Plugin {
} }
``` ```
更多详细请参考:[CollectionFieldInterfaceManager](./collection-field-interface-manager) Please refer to: [CollectionFieldInterfaceManager](./collection-field-interface-manager)
### addCollectionMixins() ### addCollectionMixins()
用于添加 `Collection` 的 Mixins。 Used to add mixins to `Collection`.
- 类型 - Type
```tsx | pure ```tsx | pure
class DataSourceManager { class DataSourceManager {
@ -130,7 +129,7 @@ class DataSourceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
import { Plugin, Collection } from '@nocobase/client'; import { Plugin, Collection } from '@nocobase/client';
@ -153,13 +152,13 @@ const MyComponent = () => {
} }
``` ```
更多详细请参考:[CollectionMixins](./collection-mixins) Please refer to: [CollectionMixins](./collection-mixins)
### addDataSource() ### addDataSource()
用于添加 `DataSource` Used to add `DataSource`.
- 类型 - Type
```tsx | pure ```tsx | pure
class DataSourceManager { class DataSourceManager {
@ -167,7 +166,7 @@ class DataSourceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
import { Plugin, DataSource, DataSourceOptions } from '@nocobase/client'; import { Plugin, DataSource, DataSourceOptions } from '@nocobase/client';
@ -191,13 +190,13 @@ class MyPlugin extends Plugin {
} }
``` ```
更多详细请参考:[DataSource](./data-source) Please refer to: [DataSource](./data-source)
### removeDataSources() ### removeDataSources()
移除 `DataSource` Remove `DataSource`
- 类型 - Type
```tsx | pure ```tsx | pure
class DataSourceManager { class DataSourceManager {
@ -205,7 +204,7 @@ class DataSourceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
@ -217,9 +216,9 @@ const MyComponent = () => {
### getDataSources() ### getDataSources()
获取全部 `DataSource` 实例列表。 Get a list of all `DataSource` instances.
- 类型 - Type
```tsx | pure ```tsx | pure
class DataSourceManager { class DataSourceManager {
@ -227,7 +226,7 @@ class DataSourceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const MyComponent = () => { const MyComponent = () => {
@ -246,9 +245,9 @@ const MyComponent = () => {
### getDataSource() ### getDataSource()
获取 `DataSource` 实例。 Get the `DataSource` instance.
- 类型 - Type
```tsx | pure ```tsx | pure
class DataSourceManager { class DataSourceManager {
@ -256,7 +255,7 @@ class DataSourceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const MyComponent = () => { const MyComponent = () => {
@ -273,9 +272,9 @@ const MyComponent = () => {
### getAllCollections() ### getAllCollections()
获取所有 DataSource 的所有 Collection 实例。 Get all Collection instances of all DataSources.
- 类型 - Type
```tsx | pure ```tsx | pure
@ -287,7 +286,7 @@ class DataSourceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const MyComponent = () => { const MyComponent = () => {
@ -313,9 +312,9 @@ const MyComponent = () => {
### reload() ### reload()
重载所有 `DataSource` Reload all `DataSource` instances.
- 类型 - Type
```tsx | pure ```tsx | pure
class DataSourceManager { class DataSourceManager {
@ -323,7 +322,7 @@ class DataSourceManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const MyComponent = () => { const MyComponent = () => {

View File

@ -2,9 +2,9 @@
用于提供 `DataSource` 的实例。 用于提供 `DataSource` 的实例。
## 组件 ## Component
- 类型 - Type
```tsx | pure ```tsx | pure
interface DataSourceProviderProps { interface DataSourceProviderProps {
@ -13,7 +13,7 @@ interface DataSourceProviderProps {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const MyComponent = () => { const MyComponent = () => {
@ -29,15 +29,15 @@ const MyComponent = () => {
### useDataSource() ### useDataSource()
获取 `DataSource` 实例。 Get the `DataSource` instance.
- 类型 - Type
```tsx | pure ```tsx | pure
function useDataSource(): DataSource; function useDataSource(): DataSource;
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const MyComponent = () => { const MyComponent = () => {
@ -48,15 +48,15 @@ const MyComponent = () => {
### useDataSourceKey() ### useDataSourceKey()
获取 `DataSource` 的 key。 Get the key of the `DataSource`.
- 类型 - Type
```tsx | pure ```tsx | pure
function useDataSourceKey(): string; function useDataSourceKey(): string;
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const MyComponent = () => { const MyComponent = () => {

View File

@ -1,12 +1,12 @@
# DataSource # DataSource
主要是用于获取数据源和数据源的数据表结构列表,并在获取后交给 [CollectionManager](./collection-manager.md) 进行管理,其被 [DataSourceManager](./data-source-manager.md) 管理。 It is mainly used to obtain the data source and the list of data table structures, and then hand them over to the [CollectionManager](./collection-manager.md) for management, which is managed by the [DataSourceManager](./data-source-manager.md).
## 数据源定义 ## Data Source Definition
数据源的定义需要继承 `DataSource` 类,并实现 `getDataSource` 方法,当调用 `reload` 方法时,会调用 `getDataSource` 方法获取数据表结构。 The definition of the data source needs to inherit the `DataSource` class and implement the `getDataSource` method. When the `reload` method is called, the `getDataSource` method will be called to obtain the data table structure.
```tsx | pure ```ts
import { DataSource } from '@nocobase/client'; import { DataSource } from '@nocobase/client';
class MyDataSource extends DataSource { class MyDataSource extends DataSource {
@ -19,11 +19,11 @@ class MyDataSource extends DataSource {
} }
``` ```
### 数据源注册 ### Data Source Registration
数据源需要在插件中注册,通过 `DataSourceManager``addDataSource` 方法进行注册。 Data sources need to be registered in plugins using the `addDataSource` method of `DataSourceManager`.
初始化添加的时候 `collections` 可以为空,当调用 `reload` 方法时,会调用 `getDataSource` 方法获取数据表结构。 When initially adding a data source, the `collections` parameter can be empty. When the `reload` method is called, the `getDataSource` method will be invoked to obtain the data table structure.
```tsx | pure ```tsx | pure
import { Plugin, DataSource, DataSourceOptions } from '@nocobase/client'; import { Plugin, DataSource, DataSourceOptions } from '@nocobase/client';
@ -50,23 +50,23 @@ class MyPlugin extends Plugin {
} }
``` ```
- `key`:数据源的唯一标识 - `key`: The unique identifier of the data source
- `displayName`:数据源的显示名称 - `displayName`: The display name of the data source
- `status`:数据源的状态,`loaded` 表示已加载,`loading` 表示正在加载,`loading-failed` 表示加载失败 - `status`: The status of the data source, `loaded` indicates loaded, `loading` indicates loading, `loading-failed` indicates loading failed
- `collections`:数据表结构 - `collections`: The table structure of the data source
- `errorMessage`:错误信息 - `errorMessage`: The error message
## 实例方法 ## Instance Methods
### getDataSource() ### getDataSource()
用于获取数据源信息,其会被 `reload` 方法内部调用,外部不需要调用。 Used to retrieve information about the data source, it is called internally by the `reload` method and does not need to be called externally.
### addReloadCallback() ### addReloadCallback()
用于添加数据源加载完成后的回调函数。 Used to add a callback function that is called after the data source is loaded.
- 类型 - Type
```tsx | pure ```tsx | pure
type LoadCallback = (collections: CollectionOptions[]) => void; type LoadCallback = (collections: CollectionOptions[]) => void;
@ -78,9 +78,9 @@ class DataSource {
### removeReloadCallback() ### removeReloadCallback()
用于移除数据源加载完成后的回调函数。 Used to remove the callback function after the data source is loaded.
- 类型 - Type
```tsx | pure ```tsx | pure
type LoadCallback = (collections: CollectionOptions[]) => void; type LoadCallback = (collections: CollectionOptions[]) => void;
@ -89,7 +89,7 @@ class DataSource {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const MyComponent = () => { const MyComponent = () => {
@ -109,9 +109,9 @@ const MyComponent = () => {
### reload() ### reload()
用于重新加载数据源,会调用 `getDataSource` 方法获取数据表结构,并内部调用 `addReloadCallback` 添加的回调函数。 Used to reload the data source, it calls the `getDataSource` method to retrieve the table structure and internally calls the callback functions added by `addReloadCallback`.
- 类型 - Type
```tsx | pure ```tsx | pure
class DataSource { class DataSource {
@ -119,7 +119,7 @@ class DataSource {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const MyComponent = () => { const MyComponent = () => {
@ -133,9 +133,9 @@ const MyComponent = () => {
### getOptions() ### getOptions()
获取数据源的配置信息。 Get the configuration information of the data source.
- 类型 - Type
```tsx | pure ```tsx | pure
interface DataSourceOptions { interface DataSourceOptions {
@ -153,9 +153,9 @@ class DataSource {
### getOption() ### getOption()
获取数据源的配置信息。 Get the configuration information of the data source.
- 类型 - Type
```tsx | pure ```tsx | pure
class DataSource { class DataSource {
@ -163,7 +163,7 @@ class DataSource {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const MyComponent = () => { const MyComponent = () => {

View File

@ -1,10 +1,10 @@
# ExtendCollectionsProvider # ExtendCollectionsProvider
用于扩展 [Collection](./collection.md) 。 Used to extend [Collection](./collection.md).
## 组件 ## Component
- 类型 - Type
```tsx | pure ```tsx | pure
interface ExtendCollectionsProviderProps { interface ExtendCollectionsProviderProps {
@ -13,7 +13,7 @@ interface ExtendCollectionsProviderProps {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
import { ExtendCollectionsProvider, CollectionOptions } from '@nocobase/client'; import { ExtendCollectionsProvider, CollectionOptions } from '@nocobase/client';
@ -60,7 +60,7 @@ const ChildComponent = () => {
### useExtendCollections() ### useExtendCollections()
获取扩展的数据表。 Get the extended collections.
```tsx | pure ```tsx | pure
import { useExtendCollections } from '@nocobase/client'; import { useExtendCollections } from '@nocobase/client';

View File

@ -4,65 +4,55 @@
```ts ```ts
class APIClient { class APIClient {
// axios 实例 // Axios instance
axios: AxiosInstance; axios: AxiosInstance;
// 缓存带 uid 的 useRequest({}, {uid}) 的结果,可供其他组件调用 // Cache the results of useRequest({}, {uid}) with uid, which can be accessed by other components
services: Record<string, Result<any, any>>; services: Record<string, Result<any, any>>;
// 构造器 // Constructor
constructor(instance?: AxiosInstance | AxiosRequestConfig); constructor(instance?: AxiosInstance | AxiosRequestConfig);
// 客户端请求,支持 AxiosRequestConfig 和 ResourceActionOptions // Client request, supports AxiosRequestConfig and ResourceActionOptions
request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D> | ResourceActionOptions): Promise<R>; request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D> | ResourceActionOptions): Promise<R>;
// 获取资源 // Get resource
resource<R = IResource>(name: string, of?: any): R; resource<R = IResource>(name: string, of?: any): R;
} }
``` ```
示例 Example:
```ts ```ts
import axios from 'axios'; import axios from 'axios';
// 不传参时,内部直接创建 axios 实例 // When no parameters are passed, it creates an axios instance internally
const apiClient = new APIClient(); const apiClient = new APIClient();
// 提供 AxiosRequestConfig 配置参数 // Provide AxiosRequestConfig configuration parameters
const apiClient = new APIClient({ const apiClient = new APIClient({
baseURL: '', baseURL: '',
}); });
// 提供 AxiosInstance // Provide AxiosInstance
const instance = axios.create({ const instance = axios.create({
baseURL: '', baseURL: '',
}); });
const apiClient = new APIClient(instance); const apiClient = new APIClient(instance);
// 常规请求 // Regular request
const response = await apiClient.request({ url }); const response = await apiClient.request({ url });
// NocoBase 特有的资源操作 // NocoBase-specific resource operations
const response = await apiClient.resource('posts').list(); const response = await apiClient.resource('posts').list();
// 请求共享 // Request sharing
const { data, loading, run } = apiClient.service('uid'); const { data, loading, run } = apiClient.service('uid');
``` ```
`api.service(uid)` 的例子ComponentB 里刷新 ComponentA 的请求数据 Example of `api.service(uid)`, refreshing the request data in ComponentA from ComponentB
<code src="./demos/demo3.tsx"></code> <code src="./demos/demo3.tsx"></code>
## APIClientProvider ## APIClientProvider
提供 APIClient 实例的上下文。 Provides the context for the APIClient instance.
```tsx | pure
const apiClient = new APIClient();
<APIClientProvider apiClient={apiClient}></APIClientProvider>
```
## useAPIClient
获取当前上下文的 APIClient 实例。
```ts ```ts
const apiClient = useAPIClient(); const apiClient = useAPIClient();
@ -77,12 +67,12 @@ function useRequest<P>(
); );
``` ```
支持 `axios.request(config)`config 详情查看 [axios](https://github.com/axios/axios#request-config) Supports `axios.request(config)`, for more details on the config, please refer to the [axios documentation](https://github.com/axios/axios#request-config).
```ts ```ts
const { data, loading, refresh, run, params } = useRequest({ url: '/users' }); const { data, loading, refresh, run, params } = useRequest({ url: '/users' });
// useRequest 里传的是 AxiosRequestConfig所以 run 里传的也是 AxiosRequestConfig // Since AxiosRequestConfig is passed in useRequest, AxiosRequestConfig should also be passed in run
run({ run({
params: { params: {
pageSize: 20, pageSize: 20,
@ -90,11 +80,11 @@ run({
}); });
``` ```
例子如下 例子如下:
<code src="./demos/demo2.tsx"></code> <code src="./demos/demo2.tsx"></code>
或者是 NocoBase 的 resource & action 请求: Or it can be a NocoBase resource & action request:
```ts ```ts
const { data, run } = useRequest({ const { data, run } = useRequest({
@ -105,17 +95,17 @@ const { data, run } = useRequest({
}, },
}); });
// useRequest 传的是 ResourceActionOptions所以 run 直接传 action params 就可以了。 // Since useRequest is passed ResourceActionOptions, you can directly pass action params to run.
run({ run({
pageSize: 50, pageSize: 50,
}); });
``` ```
例子如下: Example as follows:
<code src="./demos/demo1.tsx"></code> <code src="./demos/demo1.tsx"></code>
也可以是自定义的异步函数: It can also be a custom asynchronous function:
```ts ```ts
const { data, loading, run, refresh, params } = useRequest((...params) => Promise.resolve({})); const { data, loading, run, refresh, params } = useRequest((...params) => Promise.resolve({}));
@ -123,7 +113,7 @@ const { data, loading, run, refresh, params } = useRequest((...params) => Promis
run(...params); run(...params);
``` ```
更多用法查看 ahooks 的 [useRequest()](https://ahooks.js.org/hooks/use-request/index) For more usage, please refer to [useRequest()](https://ahooks.js.org/hooks/use-request/index) in ahooks.
## useResource ## useResource
@ -131,21 +121,19 @@ run(...params);
function useResource(name: string, of?: string | number): IResource; function useResource(name: string, of?: string | number): IResource;
``` ```
资源是 NocoBase 的核心概念,包括: Resources are the core concept of NocoBase, including:
- 独立资源,如 `posts` - Independent resources, such as `posts`
- 关系资源,如 `posts.tags` `posts.user` `posts.comments` - Related resources, such as `posts.tags`, `posts.user`, `posts.comments`
资源 URI Resource URI
```bash ```bash
# 独立资源,文章
/api/posts /api/posts
# 关系资源,文章 ID=1 的评论
/api/posts/1/comments /api/posts/1/comments
``` ```
通过 APIClient 获取资源 Retrieve resources via `APIClient`.
```ts ```ts
const api = new APIClient(); const api = new APIClient();
@ -154,14 +142,14 @@ api.resource('posts');
api.resource('posts.comments', 1); api.resource('posts.comments', 1);
``` ```
useResource 用法: `useResource` Usage:
```ts ```ts
const resource = useResource('posts'); const resource = useResource('posts');
const resource = useResource('posts.comments', 1); const resource = useResource('posts.comments', 1);
``` ```
resource 的实际场景用例参见: For actual use cases of `resource`, please refer to:
- [useCollection()](collection-manager#usecollection) - [useCollection()](collection-manager#usecollection)
- [useCollectionField()](collection-manager#usecollectionfield) - [useCollectionField()](collection-manager#usecollectionfield)

View File

@ -2,7 +2,7 @@
## Designable ## Designable
对 Schema 节点进行增、删、改操作,并且提供了事件触发机制,用于将数据同步到服务端。 Perform add, delete, and update operations on Schema nodes, and provide an event triggering mechanism to synchronize data to the server.
```tsx | pure ```tsx | pure
interface Options { interface Options {
@ -38,16 +38,16 @@ class Designable {
} }
``` ```
### 构造函数 ### Constructor
- 参数讲解 - Params
- `current`: The Schema node to operate on
- `api`: An instance of [APIClient](https://docs.nocobase.com/api/sdk) used to make backend requests
- `onSuccess`: Callback function to be executed after a successful backend API request
- `refresh`: Function to refresh the page after updating the node
- `t`: The return value of `useTranslation()`
- `current`:需要操作的 Schema 节点 - Example
- `api`:用于发起后端请求的 [APIClient](https://docs.nocobase.com/api/sdk) 实例
- `onSuccess`:后端接口请求成功后的回调
- `refresh`:用于更新节点后,刷新页面
- `t``useTranslation()` 的返回值
- 示例
```tsx | pure ```tsx | pure
const schema = new Schema({ const schema = new Schema({
@ -59,7 +59,7 @@ const schema = new Schema({
const dn = new Designable({ current: schema }); const dn = new Designable({ current: schema });
``` ```
### Schema 操作方法 ### Schema Operation Methods
```tsx | pure ```tsx | pure
const schema = new Schema({ const schema = new Schema({
@ -117,7 +117,7 @@ export default () => <pre>{JSON.stringify(schema.toJSON(), null, 2)}</pre>;
#### remove #### remove
移除当前节点 Remove the current node.
```tsx | pure ```tsx | pure
dn.remove(); dn.remove();
@ -174,7 +174,7 @@ export default () => <pre>{JSON.stringify(schema.toJSON(), null, 2)}</pre>;
#### insertBeforeBegin #### insertBeforeBegin
在当前节点的前面插入,并会触发 `insertAdjacent` 事件。 Insert before the current node and trigger the `insertAdjacent` event.
```tsx | pure ```tsx | pure
dn.insertBeforeBegin({ dn.insertBeforeBegin({
@ -240,7 +240,7 @@ export default () => <pre>{JSON.stringify(schema.toJSON(), null, 2)}</pre>;
#### insertAfterBegin #### insertAfterBegin
在当前节点的前面插入,并会触发 `insertAdjacent` 事件。 Insert after the current node and trigger the `insertAdjacent` event.
```tsx | pure ```tsx | pure
dn.insertAfterBegin({ dn.insertAfterBegin({
@ -307,7 +307,7 @@ export default () => <pre>{JSON.stringify(schema.toJSON(), null, 2)}</pre>;
#### insertBeforeEnd #### insertBeforeEnd
在当前节点的前面插入,并会触发 `insertAdjacent` 事件。 Insert after the current node and trigger the `insertAdjacent` event.
```tsx | pure ```tsx | pure
dn.insertBeforeEnd({ dn.insertBeforeEnd({
@ -374,7 +374,7 @@ export default () => <pre>{JSON.stringify(schema.toJSON(), null, 2)}</pre>;
#### insertAfterEnd #### insertAfterEnd
在当前节点的前面插入,并会触发 `insertAdjacent` 事件。 Insert after the current node and trigger the `insertAdjacent` event.
```tsx | pure ```tsx | pure
dn.insertAfterEnd({ dn.insertAfterEnd({
@ -441,7 +441,7 @@ export default () => <pre>{JSON.stringify(schema.toJSON(), null, 2)}</pre>;
#### insertAdjacent #### insertAdjacent
根据第一个参数决定插入的位置,是前面四个方法的封装。 Determines the insertion position based on the first parameter, which is a wrapper for the previous four methods.
```tsx | pure ```tsx | pure
class Designable { class Designable {
@ -449,19 +449,19 @@ class Designable {
} }
``` ```
### 事件监听和 API 请求 ### Event Listeners and API Requests
- `on` :添加事件监听的基础方法 - `on`: The basic method for adding event listeners.
- `loadAPIClientEvents`:调用 `on` 方法添加对 `insertAdjacent``patch``batchPatch``remove` 的事件的监听,主要功能是将变更的 Schema 更新到服务端 - `loadAPIClientEvents`: Calls the `on` method to add event listeners for `insertAdjacent`, `patch`, `batchPatch`, and `remove` events. Its main function is to update the changed schema on the server.
- `emit`:是根据事件名称,调用之前注册过的方法,具体是由前面讲过的 *插入操作和删除操作* 触发 - `emit`: Calls the previously registered methods based on the event name, triggered by *insertion and deletion operations*.
`loadAPIClientEvents()` 并非在初始化时调用,需要手动调用,换而言之,如果不调用 `dn.loadAPIClientEvents()`,则不会将更新发送到服务端,主要是简化在单测或者 DEMO 环境对服务端的 Mock。 `loadAPIClientEvents()` is not called during initialization and needs to be manually called. In other words, if `dn.loadAPIClientEvents()` is not called, the updates will not be sent to the server. This is mainly used to simplify mocking the server in unit tests or demo environments.
## 工具函数 ## Utility Functions
### createDesignable() ### createDesignable()
`new Designable()` 的简单封装。 A simple wrapper for `new Designable()`.
```tsx | pure ```tsx | pure
function createDesignable(options: CreateDesignableProps) { function createDesignable(options: CreateDesignableProps) {
@ -477,16 +477,16 @@ const dn = createDesignable({ current: schema });
### useFieldSchema() ### useFieldSchema()
用户获取当前节点 Schema JSON 对象,更多信息请参考 [formily useFieldSchema()](https://react.formilyjs.org/api/hooks/use-field-schema)。 Used to get the current node's Schema JSON object. For more information, please refer to [formily useFieldSchema()](https://react.formilyjs.org/api/hooks/use-field-schema).
- 类型 - Type
```tsx | pure ```tsx | pure
import { Schema } from '@formily/json-schema'; import { Schema } from '@formily/json-schema';
const useFieldSchema: () => Schema; const useFieldSchema: () => Schema;
``` ```
- 示例 - Example
```tsx ```tsx
/** /**
@ -505,11 +505,11 @@ const Demo = ({ children }) => {
const schema = { const schema = {
type: 'void', type: 'void',
name: 'hello', name: 'hello',
'x-component': 'Demo', // 这里是 Demo 组件 'x-component': 'Demo',
'properties': { 'properties': {
'world': { 'world': {
'type': 'void', 'type': 'void',
'x-component': 'Demo', // 这里也是 Demo 组件 'x-component': 'Demo',
}, },
} }
} }
@ -527,16 +527,16 @@ export default app.getRootComponent();
### useField() ### useField()
获取当前节点 Schema 实例,更多信息请参考 [formily useField()](https://react.formilyjs.org/api/hooks/use-field) Get the current node's Schema instance. For more information, please refer to [formily useField()](https://react.formilyjs.org/api/hooks/use-field).
- 类型 - Type
```tsx | pure ```tsx | pure
import { GeneralField } from '@formily/core'; import { GeneralField } from '@formily/core';
const useField: <T = GeneralField>() => T; const useField: <T = GeneralField>() => T;
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const Demo = () => { const Demo = () => {
@ -564,9 +564,9 @@ const Root = () => {
### useDesignable() ### useDesignable()
对当前 Schema 节点的修改操作。 Modify the current Schema node.
- 类型 - Type
```tsx | pure ```tsx | pure
interface InsertAdjacentOptions { interface InsertAdjacentOptions {
@ -596,26 +596,26 @@ function useDesignable(): {
} }
``` ```
- 详细解释 - Details
- designable, reset, refresh, setDesignable: These values are inherited from [SchemaComponentContext](https://www.baidu.com).
- dn: An instance of `Designable`.
- findComponent: Used to find the actual component corresponding to a string in the Schema. Returns `null` if the component is not registered.
- remove: Internally calls the `dn.remove` method.
- on: Internally calls the `dn.on` method.
- insertAdjacent: Inserts a new Schema node. Internally calls the `dn.insertAdjacent` method.
- position: The position to insert.
- schema: The new Schema node.
- Options:
- wrap: A callback function for secondary processing of the Schema.
- removeParentsIfNoChildren: Removes the parent element when there are no child elements.
- breakRemoveOn: A callback for determining when to stop removing.
- onSuccess: A callback for successful insertion.
- insertBeforeBegin: Internally calls the `dn.insertBeforeBegin` method.
- insertAfterBegin: Internally calls the `dn.insertAfterBegin` method.
- insertBeforeEnd: Internally calls the `dn.insertBeforeEnd` method.
- insertAfterEnd: Internally calls the `dn.insertAfterEnd` method.
- designable、reset、refresh、setDesignable这些值继承自 [SchemaComponentContext](https://www.baidu.com) - Example
- dn`Designable` 的实例
- findComponent用于查找 Schema 中字符串对应真正的组件,如果组件未注册则返回 `null`
- remove内部调用的是 `dn.remove` 方法
- on内部调用的是 `dn.on` 方法
- insertAdjacent插入新的 Schema 节点,内部调用的是 `dn.insertAdjacent` 方法
- position插入位置
- schema新的 Schema 节点
- Options
- wrap对 Schema 的二次处理的回调函数
- removeParentsIfNoChildren当没有子元素时删除父元素
- breakRemoveOn停止删除的判断回调
- onSuccess插入成功的回调
- insertBeforeBegin内部调用的是 `dn.insertBeforeBegin` 方法
- insertAfterBegin内部调用的是 `dn.insertAfterBegin` 方法
- insertBeforeEnd内部调用的是 `dn.insertBeforeEnd` 方法
- insertAfterEnd内部调用的是 `dn.insertAfterEnd` 方法
- 示例
插入节点。 插入节点。
@ -710,7 +710,7 @@ export default () => {
}; };
``` ```
部分更新。 Partial update.
```tsx ```tsx
import React from 'react'; import React from 'react';
@ -788,4 +788,4 @@ export default () => {
</SchemaComponentProvider> </SchemaComponentProvider>
); );
}; };
``` ```

View File

@ -15,31 +15,20 @@ interface SchemaComponentContext {
} }
``` ```
Schema 渲染的上下文。 Context for rendering Schema.
- `scope`Schema 中变量的映射 - `scope`: Mapping of variables in the Schema
- `components`: Schema 中组件的映射 - `components`: Mapping of components in the Schema
- `refresh`:触发 React 重新渲染的工具函数 - `refresh`: Utility function to trigger React re-rendering
- `reset`:重置整个 Schema 节点 - `reset`: Reset the entire Schema node
- `designable`:是否显示设计器,默认 `false` - `designable`: Whether to display the designer, default is `false`
- `setDesignable`:用于切换 `designable` 的值 - `setDesignable`: Used to toggle the value of `designable`
## Hooks ## Hooks
### useSchemaOptionsContext() ### useSchemaOptionsContext()
用于获取注册的 `scope``components` Used to get registered `scope` and `components`.
```tsx | pure
const { scope, components } = useSchemaOptionsContext();
```
## 组件
### SchemaComponentProvider
其是对 `SchemaComponentContext.Provider` 和 [FormProvider ](https://react.formilyjs.org/api/components/form-provider)的封装,并内置在 `Application` 中,并且会将 `app.components``app.scopes` 传递过去,所以一般情况下 *不需要关注* 此组件。
- props - props
```tsx | pure ```tsx | pure
@ -51,36 +40,18 @@ interface SchemaComponentProviderProps {
} }
``` ```
- 详细解释 - Details
- `designable``SchemaComponentContext``designable` 的默认值 - `designable`: The default value of `designable` in `SchemaComponentContext`
- `form`NocoBase 的 Schema 能力是基于 formily 的 `FormProvider` 提供的form 是其参数,默认为 `createForm()` - `form`: NocoBase's Schema capability is based on the `FormProvider` provided by formily, and `form` is its parameter, defaulting to `createForm()`
- `scope`Schema 中所用到的变量,会通过 `SchemaComponentContext` 进行传递 - `scope`: Variables used in the Schema, passed through `SchemaComponentContext`
- `components`Schema 中所用到的组件,会通过 `SchemaComponentContext` 进行传递 - `components`: Components used in the Schema, passed through `SchemaComponentContext`
### SchemaComponent ### SchemaComponent
用于渲染 Schema此组件必须和 `SchemaComponentProvider` 一起使用,因为 `SchemaComponentProvider` 提供了 [FormProvider](https://react.formilyjs.org/api/components/form-provider) 作为渲染 Schema 的根节点。 Used to render the Schema. This component must be used together with `SchemaComponentProvider`, as `SchemaComponentProvider` provides [FormProvider](https://react.formilyjs.org/api/components/form-provider) as the root node for rendering the Schema.
- Props - Props
```tsx | pure
type SchemaComponentProps = (ISchemaFieldProps | IRecursionFieldProps) & {
memoized?: boolean;
components?: SchemaReactComponents;
scope?: any;
}
```
- 详细解释
- `memoized`:当为 `true` 时,会对每层的 Schema 使用 `useMemo()` 进行处理
- `components`:同 `SchemaComponentProvider``components`
- `scope`: 同 `SchemaComponentProvider``components`
## 综合示例
结合 `SchemaComponentProvider``useSchemaComponentContext()``SchemaComponent`
```tsx ```tsx
/** /**
* defaultShowCode: true * defaultShowCode: true
@ -113,7 +84,7 @@ const Root = () => {
export default Root; export default Root;
``` ```
使用 `new Application()` 的方式,其内置了 `SchemaComponentProvider` ,我们可以如下操作: By using the `new Application()` method, which includes the `SchemaComponentProvider` internally, we can perform the following operations:
```tsx ```tsx
/** /**
@ -161,8 +132,7 @@ export default app.getRootComponent();
### SchemaComponentOptions ### SchemaComponentOptions
在应用中,会有很多层级的嵌套,每一层都可能提供自己的组件和 scope此组件就是为了层层传递 Schema 所需的 `components``scope` 的。 In the application, there may be multiple levels of nesting, and each level may provide its own components and scope. This component is used to pass the `components` and `scope` required for each level of the Schema.
- props - props
```tsx | pure ```tsx | pure
@ -172,7 +142,7 @@ interface SchemaComponentOptionsProps {
} }
``` ```
- 示例 - Example
```tsx ```tsx
/** /**

View File

@ -1,12 +1,12 @@
# SchemaInitializerManager # SchemaInitializerManager
## 实例方法 ## Methods
### schemaInitializerManager.add() ### schemaInitializerManager.add()
添加 SchemaInitializer 实例。 Add SchemaInitializer instance.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaInitializerManager { class SchemaInitializerManager {
@ -14,7 +14,7 @@ class SchemaInitializerManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const myInitializer = new SchemaInitializer({ const myInitializer = new SchemaInitializer({
@ -38,9 +38,9 @@ class MyPlugin extends Plugin {
### schemaInitializerManager.get() ### schemaInitializerManager.get()
获取一个 SchemaInitializer 实例。 Get SchemaInitializer instance.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaInitializerManager { class SchemaInitializerManager {
@ -48,7 +48,7 @@ class SchemaInitializerManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -60,9 +60,9 @@ class MyPlugin extends Plugin {
### schemaInitializerManager.getAll() ### schemaInitializerManager.getAll()
获取所有的 SchemaInitializer 实例。 Get all SchemaInitializer instances.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaInitializerManager { class SchemaInitializerManager {
@ -70,7 +70,7 @@ class SchemaInitializerManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -82,9 +82,9 @@ class MyPlugin extends Plugin {
### app.schemaInitializerManager.has() ### app.schemaInitializerManager.has()
判断是否有存在某个 SchemaInitializer 实例。 Check if a specific SchemaInitializer instance exists.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaInitializerManager { class SchemaInitializerManager {
@ -92,7 +92,7 @@ class SchemaInitializerManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -104,9 +104,9 @@ class MyPlugin extends Plugin {
### schemaInitializerManager.remove() ### schemaInitializerManager.remove()
移除 SchemaInitializer 实例。 Remove SchemaInitializer instance.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaInitializerManager { class SchemaInitializerManager {
@ -114,7 +114,7 @@ class SchemaInitializerManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -126,9 +126,9 @@ class MyPlugin extends Plugin {
### schemaInitializerManager.addItem() ### schemaInitializerManager.addItem()
添加 SchemaInitializer 实例的 Item 项,其和直接 schemaInitializer.add() 方法的区别是,可以确保在实例存在时才会添加。 Add an Item to the SchemaInitializer instance, the difference between this method and directly calling schemaInitializer.add() is that it can ensure that the item is added only when the instance exists.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaInitializerManager { class SchemaInitializerManager {
@ -136,18 +136,18 @@ class SchemaInitializerManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
async load() { async load() {
// 方式1先获取再添加子项需要确保已注册 // Method 1: Get first, then add sub-items, make sure it is registered
const myInitializer = this.app.schemaInitializerManager.get('MyInitializer'); const myInitializer = this.app.schemaInitializerManager.get('MyInitializer');
if (myInitializer) { if (myInitializer) {
myInitializer.add('b', { type: 'item', title: 'B' }) myInitializer.add('b', { type: 'item', title: 'B' })
} }
// 方式2通过 addItem内部确保在 MyInitializer 注册时才会添加 // Method 2: Use addItem, ensure that it is added only when MyInitializer is registered
this.app.schemaInitializerManager.addItem('MyInitializer', 'b', { this.app.schemaInitializerManager.addItem('MyInitializer', 'b', {
type: 'item', type: 'item',
title: 'B' title: 'B'
@ -158,9 +158,9 @@ class MyPlugin extends Plugin {
### schemaInitializerManager.removeItem() ### schemaInitializerManager.removeItem()
移除 实例的 Item 项,其和直接 schemaInitializer.remove() 方法的区别是,可以确保在实例存在时才会移除。 Remove an Item from the SchemaInitializer instance, the difference between this method and directly calling schemaInitializer.remove() is that it can ensure that the item is removed only when the instance exists.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaInitializerManager { class SchemaInitializerManager {
@ -168,18 +168,18 @@ class SchemaInitializerManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
async load() { async load() {
// 方式1先获取再删除子项需要确保已注册 // Method 1: Get first, then remove sub-items, make sure it is registered
const myInitializer = this.app.schemaInitializerManager.get('MyInitializer'); const myInitializer = this.app.schemaInitializerManager.get('MyInitializer');
if (myInitializer) { if (myInitializer) {
myInitializer.remove('a') myInitializer.remove('a')
} }
// 方式2通过 addItem内部确保在 MyInitializer 注册时才会移除 // Method 2: Use removeItem, ensure that it is removed only when MyInitializer is registered
this.app.schemaInitializerManager.remove('MyInitializer', 'a') this.app.schemaInitializerManager.remove('MyInitializer', 'a')
} }
} }

View File

@ -34,38 +34,38 @@ class SchemaInitializer<P1 = ButtonProps, P2 = {}> {
} }
``` ```
### 详细解释 ### Details
![](../static/KTUWb69kioUg8bxYTAMc2ReDnRg.png) ![](../static/KTUWb69kioUg8bxYTAMc2ReDnRg.png)
- name:唯一标识,必填 - name: Unique identifier, required
- Component 相关 - Component related
- Component:触发组件,默认是 `Button` 组件 - Component: Trigger component, default is `Button` component
- componentProps: 组件属性,默认是 `ButtonProps` - componentProps: Component properties, default is `ButtonProps`
- title 按钮的文本 - title: Button text
- icon:按钮的 icon 属性 - icon: Button icon property
- style:组件的样式 - style: Component style
- Items 相关 - Items related
- items:列表项配置 - items: List item configuration
- ItemsComponent:默认是渲染成一个列表的形式,可通过此参数自定义 items - ItemsComponent: By default, it is rendered as a list. Customize items with this parameter
- itemsComponentProps`ItemsComponent` 的属性 - itemsComponentProps: Properties of `ItemsComponent`
- itemsComponentStyle`ItemsComponent` 的样式 - itemsComponentStyle: Style of `ItemsComponent`
- popover 组件相关 - Popover component related
- popover:是否使用 popover默认为 `true` - popover: Whether to use popover, default is `true`
- popoverPropspopover 的属性 - popoverProps: Properties of popover
- Schema 操作相关 - Schema operation related
- insertPosition:插入位置,参考:[useDesignable()](/core/ui-schema/designable#usedesignable) - insertPosition: Insertion position, refer to: [useDesignable()](/core/ui-schema/designable#usedesignable)
- designable:是否显示设计模式,参考:[useDesignable()](/core/ui-schema/designable#usedesignable) - designable: Whether to display design mode, refer to: [useDesignable()](/core/ui-schema/designable#usedesignable)
- wrap:对 Schema 的二次处理,参考:[useDesignable()](/core/ui-schema/designable#usedesignable) - wrap: Secondary processing of Schema, refer to: [useDesignable()](/core/ui-schema/designable#usedesignable)
- onSuccessSchema 更新到服务端后的回调,参考:[useDesignable()](/core/ui-schema/designable#usedesignable) - onSuccess: Callback after Schema is updated to the server, refer to: [useDesignable()](/core/ui-schema/designable#usedesignable)
- insert:自定义 Schema 插入逻辑,默认为 [useDesignable()](/core/ui-schema/designable#usedesignable) 的 `insertAdjacent` - insert: Custom Schema insertion logic, default is [useDesignable()](/core/ui-schema/designable#usedesignable)'s `insertAdjacent`
- useInsert:当自定义插入 Schema 的逻辑需要用到 Hooks 时,可以使用此参数 - useInsert: When customizing the logic for inserting Schema requires the use of Hooks, this parameter can be used
### 示例 ### Example
#### 基础用法 #### 基础用法
@ -73,7 +73,6 @@ class SchemaInitializer<P1 = ButtonProps, P2 = {}> {
const myInitializer = new SchemaInitializer({ const myInitializer = new SchemaInitializer({
name: 'MyInitializer', name: 'MyInitializer',
title: 'Add Block', title: 'Add Block',
// 插入位置
insertPosition: 'beforeEnd', insertPosition: 'beforeEnd',
items: [ items: [
{ {
@ -84,11 +83,9 @@ const myInitializer = new SchemaInitializer({
], ],
}); });
``` ```
<code src="./demos/schema-initializer-basic.tsx"></code> <code src="./demos/schema-initializer-basic.tsx"></code>
#### 定制化 `Component` #### Custom `Component`
```tsx | pure ```tsx | pure
const myInitializer = new SchemaInitializer({ const myInitializer = new SchemaInitializer({
@ -113,9 +110,9 @@ const myInitializer = new SchemaInitializer({
<code src="./demos/schema-initializer-component.tsx"></code> <code src="./demos/schema-initializer-component.tsx"></code>
#### 不使用 Popover #### Not Using Popover
关于 `useDesignable()` 的说明请参考 [useDesignable](/core/ui-schema/designable#usedesignable)。 Please refer to [useDesignable](/core/ui-schema/designable#usedesignable) for more information about `useDesignable()`.
```tsx | pure ```tsx | pure
const schema = { const schema = {
@ -139,7 +136,7 @@ const myInitializer = new SchemaInitializer({
<code src="./demos/schema-initializer-popover.tsx"></code> <code src="./demos/schema-initializer-popover.tsx"></code>
#### 定制化 Items #### Custom Items
```tsx | pure ```tsx | pure
const CustomListGridMenu: FC<SchemaInitializerItemsProps<ButtonProps, ListProps<any>>> = (props) => { const CustomListGridMenu: FC<SchemaInitializerItemsProps<ButtonProps, ListProps<any>>> = (props) => {
@ -175,9 +172,9 @@ const myInitializer = new SchemaInitializer({
<code src="./demos/schema-initializer-items.tsx"></code> <code src="./demos/schema-initializer-items.tsx"></code>
## options.items 配置详解 ## options.items
### 类型 ### Types
```tsx | pure ```tsx | pure
interface SchemaInitializerComponentCommonProps { interface SchemaInitializerComponentCommonProps {
@ -201,15 +198,13 @@ interface SchemaInitializerItemBaseType<T = {}> extends SchemaInitializerCompone
} }
``` ```
### 两种定义方式:`Component` `type` ### Two ways to define: `Component` and `type`
- `Component` param
- 通过 `Component` 定义
```tsx | pure ```tsx | pure
const Demo = () => { const Demo = () => {
// 最终渲染 `SchemaInitializerItem`
return <SchemaInitializerItem title='Demo' /> return <SchemaInitializerItem title='Demo' />
} }
@ -218,17 +213,17 @@ const myInitializer = new SchemaInitializer({
items: [ items: [
{ {
name: 'a', name: 'a',
Component: Demo, // 通过 Component 定义 Component: Demo,
} }
], ],
}); });
``` ```
- 通过 `type` 定义 - `type` param
NocoBase 内置了一些常用的 `type`,例如 `type: 'item'`,相当于 `Component: SchemaInitializerItem` NocoBase has built-in some common `type`s. For example, `type: 'item'` is equivalent to `Component: SchemaInitializerItem`.
更多内置类型,请参考:[内置组件和类型](/core/ui-schema/schema-initializer#%E5%86%85%E7%BD%AE%E7%BB%84%E4%BB%B6%E5%92%8C%E7%B1%BB%E5%9E%8B) For more built-in types, please refer to: [Built-in Components and Types](/core/ui-schema/schema-initializer#%E5%86%85%E7%BD%AE%E7%BB%84%E4%BB%B6%E5%92%8C%E7%B1%BB%E5%9E%8B)
```tsx | pure ```tsx | pure
const myInitializer = new SchemaInitializer({ const myInitializer = new SchemaInitializer({
@ -245,25 +240,25 @@ const myInitializer = new SchemaInitializer({
<code src="./demos/schema-initializer-options-item-define.tsx"></code> <code src="./demos/schema-initializer-options-item-define.tsx"></code>
### `children` 和动态方式 `useChildren` ### `children` and dynamic `useChildren`
对于某些组件而言是有子列表项的,例如 `type: 'itemGroup'`,那么我们使用 children 属性,同时考虑到某些场景下 children 是动态的,需要从 Hooks 里面获取,那么就可以通过 `useChildren` 来定义。 For some components that have child items, such as `type: 'itemGroup'`, we use the `children` property. However, in certain scenarios where the children are dynamic and need to be obtained from hooks, we can define them using `useChildren`.
<code src="./demos/schema-initializer-options-item-children.tsx"></code> <code src="./demos/schema-initializer-options-item-children.tsx"></code>
### 动态显示隐藏 `useVisible` ### Dynamic visibility with `useVisible`
<code src="./demos/schema-initializer-options-item-visible.tsx"></code> <code src="./demos/schema-initializer-options-item-visible.tsx"></code>
### 组件属性 `componentProps` 和动态属性 `useComponentProps` ### Component properties `componentProps` and dynamic properties `useComponentProps`
对于一些通用组件,我们可以通过 `componentProps` 来定义组件属性,同时考虑到某些场景下组件属性是动态的,需要从 Hooks 里面获取,那么就可以通过 `useComponentProps` 来定义。 For some common components, we can define component properties using `componentProps`. In certain scenarios where the component properties are dynamic and need to be obtained from hooks, we can define them using `useComponentProps`.
当然也可以不使用这两个属性,直接封装成一个组件,然后通过 `Component` 来定义。 Of course, you can also encapsulate them into a component and define them using the `Component` property.
<code src="./demos/schema-initializer-options-item-props.tsx"></code> <code src="./demos/schema-initializer-options-item-props.tsx"></code>
### 公共属性和组件属性 ### Common properties and component properties
```tsx | pure ```tsx | pure
{ {
@ -277,15 +272,15 @@ const myInitializer = new SchemaInitializer({
} }
``` ```
从上面的示例中我么看到,从配置项中获取组件组件所需的数据有两个方式: From the above example, we can see that there are two ways to obtain the data required by the component from the configuration:
- 组件属性:通过 `componentProps` 来定义,例如 `zzz: 'xxx'` - Component properties: defined through `componentProps`, for example `zzz: 'xxx'`
- 公共属性:将属性直接定义在配置项上,例如 `foo: 'bar'``name``title` - Common properties: directly defined on the configuration item, for example `foo: 'bar'`, `name`, `title`
在获取上 In terms of retrieval:
- `componentProps` 定义的数据会被传递给组件的 `props` - Data defined in `componentProps` will be passed to the component's `props`
- 直接定义在配置项上的数据会则需要通过 [useSchemaInitializerItem()](/core/ui-schema/schema-initializer#useschemainitializeritem) 获取 - Data directly defined on the configuration item needs to be obtained through [useSchemaInitializerItem()](/core/ui-schema/schema-initializer#useschemainitializeritem)
```tsx | pure ```tsx | pure
const Demo = (props) => { const Demo = (props) => {
@ -294,7 +289,7 @@ const Demo = (props) => {
} }
``` ```
## 实例方法 ## Methods
```tsx | pure ```tsx | pure
const myInitializer = new SchemaInitializer({ const myInitializer = new SchemaInitializer({
@ -352,9 +347,9 @@ export default app.getRootComponent();
### schemaInitializer.add() ### schemaInitializer.add()
用于新增 Item另一种添加方式参考 [schemaInitializerManager.addItem()](/core/ui-schema/schema-initializer-manager#schemainitializermanageradditem); Used to add a new item. Another way to add items is through [schemaInitializerManager.addItem()](/core/ui-schema/schema-initializer-manager#schemainitializermanageradditem);
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaInitializer { class SchemaInitializer {
@ -362,11 +357,11 @@ class SchemaInitializer {
} }
``` ```
- 参数说明 - params
第一个参数是 name作为唯一标识用于增删改查并且 `name` 支持 `.` 用于分割层级。 The first parameter is `name`, which serves as a unique identifier for adding, deleting, modifying, and querying. The `name` also supports `.` as a delimiter for hierarchical separation.
- 示例 - Example
```tsx | pure ```tsx | pure
myInitializer.add('b', { myInitializer.add('b', {
@ -428,7 +423,7 @@ export default app.getRootComponent();
### schemaInitializer.get() ### schemaInitializer.get()
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaInitializer { class SchemaInitializer {
@ -436,7 +431,7 @@ class SchemaInitializer {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const itemA = myInitializer.get('a') const itemA = myInitializer.get('a')
@ -446,9 +441,9 @@ const itemA1 = myInitializer.add('a.a1')
### schemaInitializer.remove() ### schemaInitializer.remove()
另一种移除方式参考 [schemaInitializerManager.addItem()](/core/ui-schema/schema-initializer-manager#schemainitializermanagerremoveitem); Another way to remove items can be found in [schemaInitializerManager.addItem()](/core/ui-schema/schema-initializer-manager#schemainitializermanagerremoveitem);
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaInitializer { class SchemaInitializer {
@ -456,7 +451,7 @@ class SchemaInitializer {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
myInitializer.remove('a.a1') myInitializer.remove('a.a1')
@ -468,9 +463,9 @@ myInitializer.remove('a')
### useSchemaInitializer() ### useSchemaInitializer()
用于获取 `SchemaInitializer` 上下文内容。 Used to retrieve the context content of `SchemaInitializer`.
- 类型 - Type
```tsx | pure ```tsx | pure
export type InsertType = (s: ISchema) => void; export type InsertType = (s: ISchema) => void;
@ -483,13 +478,13 @@ const useSchemaInitializer: () => {
} }
``` ```
- 参数详解 - Parameter Details
- `insert`:参数是 Schema 对象,用于插入 Schema - `insert`: The parameter is a Schema object used to insert the Schema.
- `options`:获取 `new SchemaInitializer(options)` 时 options 配置 - `options`: The options configuration when obtaining `new SchemaInitializer(options)`.
- `visible`popover 是否显示 - `visible`: Whether the popover is displayed.
- `setVisible`:设置 popover 显示状态 - `setVisible`: Sets the visibility status of the popover.
- 示例 - Example
```tsx | pure ```tsx | pure
const schema = { const schema = {
@ -507,9 +502,9 @@ const Demo = () => {
### useSchemaInitializerRender() ### useSchemaInitializerRender()
用于渲染 `SchemaInitializer` Used to render `SchemaInitializer`.
- 类型 - Type
```tsx | pure ```tsx | pure
function useSchemaInitializerRender(name: string, options?: SchemaInitializerOptions): { function useSchemaInitializerRender(name: string, options?: SchemaInitializerOptions): {
@ -518,11 +513,11 @@ function useSchemaInitializerRender(name: string, options?: SchemaInitializerOpt
} }
``` ```
- 参数详解 - Details
返回的 `render` 方法可以接收一个参数,用于覆盖 `new SchemaInitializer(options)``options` 配置。 The returned `render` method can accept a parameter to override the `options` configuration of `new SchemaInitializer(options)`.
- 示例 - Example
```tsx | pure ```tsx | pure
const Demo = () => { const Demo = () => {
@ -539,15 +534,15 @@ const Demo = () => {
### useSchemaInitializerItem() ### useSchemaInitializerItem()
用于获取配置项内容的,配置项是指的 `SchemaInitializer` 中的 `items` 中的一项。 Used to retrieve the content of a configuration item, where the configuration item refers to one item in the `items` property of `SchemaInitializer`.
- 类型 - Type
```tsx | pure ```tsx | pure
const useSchemaInitializerItem: <T = any>() => T const useSchemaInitializerItem: <T = any>() => T
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const myInitializer = new SchemaInitializer({ const myInitializer = new SchemaInitializer({
@ -564,7 +559,7 @@ const myInitializer = new SchemaInitializer({
}); });
/** /**
* 通过 useSchemaInitializerItem() 获取到的是 * The result obtained through useSchemaInitializerItem() is
* { * {
* name: 'a', * name: 'a',
* title: 'Item A', * title: 'Item A',
@ -580,22 +575,22 @@ const Demo = () => {
<code src="./demos/schema-initializer-hooks-item.tsx"></code> <code src="./demos/schema-initializer-hooks-item.tsx"></code>
## 内置组件和类型 ## Built-in Components and Types
| type | Component | 效果 | | type | Component | |
| ----------- | ------------------------------ | ----------------------------------------- | | ----------- | ------------------------------ | ----------------------------------------- |
| item | SchemaInitializerItem | 文本| | item | SchemaInitializerItem | Text |
| itemGroup | SchemaInitializerItemGroup | 分组,同 antd `Menu` 组件的 `type: 'group'` | | itemGroup | SchemaInitializerItemGroup | Group, similar to antd `Menu` component with `type: 'group'` |
| subMenu | SchemaInitializerSubMenu | 子菜单,同 antd `Menu` 组件的子菜单 | | subMenu | SchemaInitializerSubMenu | Submenu, similar to antd `Menu` component's submenu |
| divider | SchemaInitializerDivider | 分割线,同 antd `Menu` 组件的 `type: 'divider'` | | divider | SchemaInitializerDivider | Divider, similar to antd `Menu` component with `type: 'divider'` |
| switch | SchemaInitializerSwitch | 开关 | | switch | SchemaInitializerSwitch | Switch |
| actionModal | SchemaInitializerActionModal | 弹窗| | actionModal | SchemaInitializerActionModal | Modal|
以下每个示例都提供了 2 种[定义方式](/core/ui-schema/schema-initializer#两种定义方式component-和-type),一种是通过 `Component` 定义,另一种是通过 `type` 定义。 The following examples provide two [definition methods](/core/ui-schema/schema-initializer#two-ways-to-define-component-and-type), one is defined through `Component`, and the other is defined through `type`.
### `type: 'item'` & `SchemaInitializerItem` ### `type: 'item'` & `SchemaInitializerItem`
文本项 Text
```tsx | pure ```tsx | pure
interface SchemaInitializerItemProps { interface SchemaInitializerItemProps {
@ -609,7 +604,7 @@ interface SchemaInitializerItemProps {
} }
``` ```
核心参数是 `title``icon``onClick``items`,其中 `onClick` 用于插入 Schema`items` 用于渲染子列表项。 The core parameters are `title`, `icon`, `onClick`, and `items`. Among them, `onClick` is used to insert Schema, and `items` is used to render child list items.
<code src="./demos/schema-initializer-components-item.tsx"></code> <code src="./demos/schema-initializer-components-item.tsx"></code>
@ -626,13 +621,13 @@ interface SchemaInitializerItemGroupProps {
} }
``` ```
核心参数是 `title``children`,其中 `children` 用于渲染子列表项,`divider` 用于渲染分割线。 The core parameters are `title`, `children`, and `divider`. Among them, `children` is used to render child list items, and `divider` is used to render a divider.
<code src="./demos/schema-initializer-components-group.tsx"></code> <code src="./demos/schema-initializer-components-group.tsx"></code>
### `type: 'switch'` & SchemaInitializerSwitch ### `type: 'switch'` & SchemaInitializerSwitch
Switch 切换按钮。 Switch Button.
```tsx | pure ```tsx | pure
interface SchemaInitializerSwitchItemProps extends SchemaInitializerItemProps { interface SchemaInitializerSwitchItemProps extends SchemaInitializerItemProps {
@ -641,20 +636,18 @@ interface SchemaInitializerSwitchItemProps extends SchemaInitializerItemProps {
} }
``` ```
核心参数是 `checked``onClick`,其中 `onClick` 用于插入或者移除 Schema。 The core parameters are `checked` and `onClick`, where `onClick` is used to insert or remove Schema.
<code src="./demos/schema-initializer-components-switch.tsx"></code> <code src="./demos/schema-initializer-components-switch.tsx"></code>
### `type: 'subMenu'` & SchemaInitializerSubMenu ### `type: 'subMenu'` & SchemaInitializerSubMenu
子菜单。 Sub menu.
<code src="./demos/schema-initializer-components-menu.tsx"></code> <code src="./demos/schema-initializer-components-menu.tsx"></code>
### `type: 'divider'` & SchemaInitializerDivider ### `type: 'divider'` & SchemaInitializerDivider
分割线。
<code src="./demos/schema-initializer-components-divider.tsx"></code> <code src="./demos/schema-initializer-components-divider.tsx"></code>
### `type: 'actionModal'` & SchemaInitializerActionModal ### `type: 'actionModal'` & SchemaInitializerActionModal
@ -665,15 +658,15 @@ interface SchemaInitializerSwitchItemProps extends SchemaInitializerItemProps {
#### Item Mode #### Item Mode
`SchemaInitializerActionModal` 需要加上 `isItem` 属性 `SchemaInitializerActionModal` needs to add the `isItem` property.
<code src="./demos/schema-initializer-components-action-modal-2.tsx"></code> <code src="./demos/schema-initializer-components-action-modal-2.tsx"></code>
## 渲染组件 ## Render Components
### SchemaInitializerChildren ### SchemaInitializerChildren
用于自定义渲染多个列表项。 Used to customize the rendering of multiple list items.
```tsx | pure ```tsx | pure
@ -707,7 +700,7 @@ const myInitializer = new SchemaInitializer({
### SchemaInitializerChild ### SchemaInitializerChild
用于自定义渲染单个列表项。 Used to customize the rendering of individual list items.
```tsx | pure ```tsx | pure
const Demo = (props) => { const Demo = (props) => {

View File

@ -1,12 +1,12 @@
# SchemaSettingsManager # SchemaSettingsManager
## 实例方法 ## Methods
### schemaSettingsManager.add() ### schemaSettingsManager.add()
添加 SchemaSettings 实例。 Used to add a SchemaSettings instance.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaSettingsManager { class SchemaSettingsManager {
@ -14,7 +14,7 @@ class SchemaSettingsManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const mySchemaSettings = new SchemaSetting({ const mySchemaSettings = new SchemaSetting({
@ -40,9 +40,9 @@ class MyPlugin extends Plugin {
### schemaSettingsManager.get() ### schemaSettingsManager.get()
获取一个 SchemaSettings 实例。 Get a SchemaSettings instance.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaSettingsManager { class SchemaSettingsManager {
@ -50,7 +50,7 @@ class SchemaSettingsManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -62,9 +62,9 @@ class MyPlugin extends Plugin {
### schemaSettingsManager.getAll() ### schemaSettingsManager.getAll()
获取所有的 SchemaSettings 实例。 Get all SchemaSettings instances.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaSettingsManager { class SchemaSettingsManager {
@ -72,7 +72,7 @@ class SchemaSettingsManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -84,9 +84,9 @@ class MyPlugin extends Plugin {
### app.schemaSettingsManager.has() ### app.schemaSettingsManager.has()
判断是否有存在某个 SchemaSettings 实例。 Check if a specific SchemaSettings instance exists.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaSettingsManager { class SchemaSettingsManager {
@ -94,7 +94,7 @@ class SchemaSettingsManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -106,9 +106,9 @@ class MyPlugin extends Plugin {
### schemaSettingsManager.remove() ### schemaSettingsManager.remove()
移除 SchemaSettings 实例。 Remove SchemaSettings instance.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaSettingsManager { class SchemaSettingsManager {
@ -116,7 +116,7 @@ class SchemaSettingsManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
@ -128,9 +128,9 @@ class MyPlugin extends Plugin {
### schemaSettingsManager.addItem() ### schemaSettingsManager.addItem()
添加 SchemaSettings 实例的 Item 项,其和直接 schemaInitializer.add() 方法的区别是,可以确保在实例存在时才会添加。 Add an Item to the SchemaSettings instance, the difference between this method and directly calling schemaInitializer.add() is that it can ensure that the item is added only when the instance exists.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaSettingsManager { class SchemaSettingsManager {
@ -138,18 +138,18 @@ class SchemaSettingsManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
async load() { async load() {
// 方式1先获取再添加子项需要确保已注册 // Method 1: Get first, then add sub-items, make sure it is registered
const mySchemaSettings = this.app.schemaSettingsManager.get('MySchemaSettings'); const mySchemaSettings = this.app.schemaSettingsManager.get('MySchemaSettings');
if (mySchemaSettings) { if (mySchemaSettings) {
mySchemaSettings.add('b', { type: 'item', componentProps:{ title: 'B' } }) mySchemaSettings.add('b', { type: 'item', componentProps:{ title: 'B' } })
} }
// 方式2通过 addItem内部确保在 mySchemaSettings 注册时才会添加 // Method 2: Use addItem, ensure that it is added only when MySchemaSettings is registered
this.app.schemaSettingsManager.addItem('MySchemaSettings', 'b', { this.app.schemaSettingsManager.addItem('MySchemaSettings', 'b', {
type: 'item', type: 'item',
componentProps:{ title: 'B' } componentProps:{ title: 'B' }
@ -160,9 +160,9 @@ class MyPlugin extends Plugin {
### schemaSettingsManager.removeItem() ### schemaSettingsManager.removeItem()
移除 实例的 Item 项,其和直接 schemaInitializer.remove() 方法的区别是,可以确保在实例存在时才会移除。 Remove an Item from the SchemaSettings instance, the difference between this method and directly calling schemaInitializer.remove() is that it can ensure that the item is removed only when the instance exists.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaSettingsManager { class SchemaSettingsManager {
@ -170,18 +170,18 @@ class SchemaSettingsManager {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
class MyPlugin extends Plugin { class MyPlugin extends Plugin {
async load() { async load() {
// 方式1先获取再删除子项需要确保已注册 // Method 1: Get first, then remove sub-items, make sure it is registered
const mySchemaSettings = this.app.schemaSettingsManager.get('MySchemaSettings'); const mySchemaSettings = this.app.schemaSettingsManager.get('MySchemaSettings');
if (mySchemaSettings) { if (mySchemaSettings) {
mySchemaSettings.remove('a') mySchemaSettings.remove('a')
} }
// 方式2通过 addItem内部确保在 mySchemaSettings 注册时才会移除 // Method 2: Use addItem, ensure that it is removed only when MySchemaSettings is registered
this.app.schemaSettingsManager.remove('MySchemaSettings', 'a') this.app.schemaSettingsManager.remove('MySchemaSettings', 'a')
} }
} }

View File

@ -2,7 +2,7 @@
## new SchemaSettings(options) ## new SchemaSettings(options)
创建一个 SchemaSettings 实例。 Create a SchemaSettings instance.
```tsx | pure ```tsx | pure
interface SchemaSettingsOptions<T = {}> { interface SchemaSettingsOptions<T = {}> {
@ -22,19 +22,18 @@ class SchemaSettings<T = {}>{
} }
``` ```
### 详细解释 ### Details
![](../static/VfPGbhWo9os0qTxcITkcHNfin4g.png) ![](../static/VfPGbhWo9os0qTxcITkcHNfin4g.png)
- name唯一标识必填 - name: Unique identifier, required
- Component 相关 - Component related
- Component: Trigger component, default is `<MenuOutlined />` component
- componentProps: Component properties
- style: Component style
- items: List item configuration
- Component触发组件默认是 `<MenuOutlined />` 组件 ### Example
- componentProps: 组件属性
- style组件的样式
- items列表项配置
### 示例
#### 基础用法 #### 基础用法
@ -43,8 +42,8 @@ const mySchemaSettings = new SchemaSettings({
name: 'MySchemaSettings', name: 'MySchemaSettings',
items: [ items: [
{ {
name: 'demo1', // 唯一标识 name: 'demo1',
type: 'item', // 内置类型 type: 'item',
componentProps: { componentProps: {
title: 'DEMO1', title: 'DEMO1',
onClick() { onClick() {
@ -54,23 +53,23 @@ const mySchemaSettings = new SchemaSettings({
}, },
{ {
name: 'demo2', name: 'demo2',
Component: () => <SchemaSettings.Item title="DEMO2" onClick={() => alert('DEMO2')} />, // 直接使用 Component 组件 Component: () => <SchemaSettings.Item title="DEMO2" onClick={() => alert('DEMO2')} />,
}, },
], ],
}); });
``` ```
#### 定制化 `Component` #### Custom `Component`
```tsx | pure ```tsx | pure
const mySchemaSettings = new SchemaSettings({ const mySchemaSettings = new SchemaSettings({
name: 'MySchemaSettings', name: 'MySchemaSettings',
Component: Button, // 自定义组件 Component: Button,
componentProps: { componentProps: {
type: 'primary', type: 'primary',
children: '自定义按钮', children: '自定义按钮',
}, },
// Component: (props) => <Button type='primary' {...props}>自定义按钮</Button>, // 等同于上面效果 // Component: (props) => <Button type='primary' {...props}>自定义按钮</Button>,
items: [ items: [
{ {
name: 'demo1', name: 'demo1',
@ -83,7 +82,7 @@ const mySchemaSettings = new SchemaSettings({
}); });
``` ```
## options.items 配置详解 ## options.items
```tsx | pure ```tsx | pure
interface SchemaSettingsItemCommon<T = {}> { interface SchemaSettingsItemCommon<T = {}> {
@ -100,15 +99,14 @@ interface SchemaSettingsItemCommon<T = {}> {
} }
``` ```
### 两种定义方式:`Component``type` ### `Component``type`
- 通过 `Component` 定义 - `Component`
```tsx | pure ```tsx | pure
const Demo = () => { const Demo = () => {
// 最终渲染 `SchemaSettingsItem`
return <SchemaSettingsItem title='Demo' /> return <SchemaSettingsItem title='Demo' />
} }
@ -117,17 +115,17 @@ const mySettings = new SchemaSettings({
items: [ items: [
{ {
name: 'a', name: 'a',
Component: Demo, // 通过 Component 定义 Component: Demo,
} }
], ],
}); });
``` ```
- 通过 `type` 定义 - `type`
NocoBase 内置了一些常用的 `type`,例如 `type: 'item'`,相当于 `Component: SchemaSettingsItem` NocoBase has built-in some common `type`, such as `type: 'item'`, which is equivalent to `Component: SchemaSettingsItem`.
更多内置类型,请参考:[内置组件和类型](/core/ui-schema/schema-settings#%E5%86%85%E7%BD%AE%E7%BB%84%E4%BB%B6%E5%92%8C%E7%B1%BB%E5%9E%8B) For more built-in types, please refer to: [Built-in Components and Types](/core/ui-schema/schema-settings#built-in-components-and-types)
```tsx | pure ```tsx | pure
const mySettings = new SchemaSettings({ const mySettings = new SchemaSettings({
@ -146,25 +144,25 @@ const mySettings = new SchemaSettings({
<code src="./demos/schema-settings-options-item-define.tsx"></code> <code src="./demos/schema-settings-options-item-define.tsx"></code>
### `children` 和动态方式 `useChildren` ### `children` and dynamic `useChildren`
对于某些组件而言是有子列表项的,例如 `type: 'itemGroup'`,那么我们使用 children 属性,同时考虑到某些场景下 children 是动态的,需要从 Hooks 里面获取,那么就可以通过 `useChildren` 来定义。 For some components that have child items, such as `type: 'itemGroup'`, we use the `children` property. In certain scenarios where the children are dynamic and need to be obtained from hooks, we can define them using `useChildren`.
<code src="./demos/schema-settings-options-item-children.tsx"></code> <code src="./demos/schema-settings-options-item-children.tsx"></code>
### 动态显示隐藏 `useVisible` ### Dynamic visibility with `useVisible`
<code src="./demos/schema-settings-options-item-visible.tsx"></code> <code src="./demos/schema-settings-options-item-visible.tsx"></code>
### 组件属性 `componentProps` 和动态属性 `useComponentProps` ### Component properties `componentProps` and dynamic properties `useComponentProps`
对于一些通用组件,我们可以通过 `componentProps` 来定义组件属性,同时考虑到某些场景下组件属性是动态的,需要从 Hooks 里面获取,那么就可以通过 `useComponentProps` 来定义。 For some common components, we can define component properties using `componentProps`. In certain scenarios where the component properties are dynamic and need to be obtained from hooks, we can define them using `useComponentProps`.
当然也可以不使用这两个属性,直接封装成一个组件,然后通过 `Component` 来定义。 Alternatively, we can encapsulate the properties into a component and define them using `Component`.
<code src="./demos/schema-settings-options-item-props.tsx"></code> <code src="./demos/schema-settings-options-item-props.tsx"></code>
## 实例方法 ## Methods
```tsx | pure ```tsx | pure
const mySchemaSettings = new SchemaSettings({ const mySchemaSettings = new SchemaSettings({
@ -189,9 +187,9 @@ const mySchemaSettings = new SchemaSettings({
### schemaSettings.add() ### schemaSettings.add()
用于新增 Item。 Use for adding an item.
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaSettings { class SchemaSettings {
@ -199,11 +197,11 @@ class SchemaSettings {
} }
``` ```
- 参数说明 - params
第一个参数是 name作为唯一标识用于增删改查并且 `name` 支持 `.` 用于分割层级。 The first parameter is `name`, which is used as a unique identifier for adding, deleting, modifying, and querying, and `name` supports `.` to separate levels.
- 示例 - Example
```tsx | pure ```tsx | pure
mySchemaSetting.add('b', { mySchemaSetting.add('b', {
@ -219,7 +217,7 @@ mySchemaSetting.add('a.a2', {
### schemaSettings.get() ### schemaSettings.get()
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaSettings { class SchemaSettings {
@ -227,7 +225,7 @@ class SchemaSettings {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const itemA = mySchemaSetting.get('a') const itemA = mySchemaSetting.get('a')
@ -237,7 +235,7 @@ const itemA1 = mySchemaSetting.add('a.a1')
### schemaSettings.remove() ### schemaSettings.remove()
- 类型 - Type
```tsx | pure ```tsx | pure
class SchemaSettings { class SchemaSettings {
@ -245,7 +243,7 @@ class SchemaSettings {
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
mySchemaSetting.remove('a.a1') mySchemaSetting.remove('a.a1')
@ -257,9 +255,9 @@ mySchemaSetting.remove('a')
### useSchemaSettingsRender() ### useSchemaSettingsRender()
用于渲染 SchemaSettings。 Use to render SchemaSettings.
- 类型 - Type
```tsx | pure ```tsx | pure
function useSchemaSettingsRender(name: string, options?: SchemaSettingsOptions): { function useSchemaSettingsRender(name: string, options?: SchemaSettingsOptions): {
@ -268,7 +266,7 @@ function useSchemaSettingsRender(name: string, options?: SchemaSettingsOptions):
} }
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const Demo = () => { const Demo = () => {
@ -285,11 +283,11 @@ const Demo = () => {
### useSchemaSettings() ### useSchemaSettings()
获取 schemaSetting 上下文数据。 Get the schemaSetting context data.
上下文数据包含了 `schemaSetting` 实例化时的 `options` 以及调用 `useSchemaSettingsRender()` 时传入的 `options` The context data includes the `options` passed when instantiating the `schemaSetting` and the `options` passed when calling `useSchemaSettingsRender()`.
- 类型 - Type
```tsx | pure ```tsx | pure
interface UseSchemaSettingsResult<T> extends SchemaSettingsOptions<T> { interface UseSchemaSettingsResult<T> extends SchemaSettingsOptions<T> {
@ -301,7 +299,7 @@ interface UseSchemaSettingsResult<T> extends SchemaSettingsOptions<T> {
function useSchemaSettings(): UseSchemaSettingsResult; function useSchemaSettings(): UseSchemaSettingsResult;
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const { dn } = useSchemaSettings(); const { dn } = useSchemaSettings();
@ -309,9 +307,9 @@ const { dn } = useSchemaSettings();
### useSchemaSettingsItem() ### useSchemaSettingsItem()
用于获取一个 item 的数据。 Used to retrieve data for an item.
- 类型 - Type
```tsx | pure ```tsx | pure
export type SchemaSettingsItemType<T = {}> = { export type SchemaSettingsItemType<T = {}> = {
@ -329,68 +327,58 @@ export type SchemaSettingsItemType<T = {}> = {
function useSchemaSettingsItem(): SchemaSettingsItemType; function useSchemaSettingsItem(): SchemaSettingsItemType;
``` ```
- 示例 - Example
```tsx | pure ```tsx | pure
const { name } = useSchemaSettingsItem(); const { name } = useSchemaSettingsItem();
``` ```
## 内置组件和类型 ## Built-in Components and Types
| type | Component | 效果 | | type | Component | |
| ----------- | ------------------------------ | ----------------------------------------- | | ----------- | ------------------------------ | ----------------------------------------- |
| item | SchemaSettingsItem | 文本 | | item | SchemaSettingsItem | Text |
| itemGroup | SchemaSettingsItemGroup | 分组,同 Menu 组件的 `type: 'itemGroup'` | | itemGroup | SchemaSettingsItemGroup | Group, same as `type: 'itemGroup'` in Menu |
| subMenu | SchemaSettingsSubMenu | 子菜单,同 Menu 组件的子菜单 | | subMenu | SchemaSettingsSubMenu | Submenu, same as submenu in Menu |
| divider | SchemaSettingsDivider | 分割线,同 Menu 组件的 `type: 'divider'` | | divider | SchemaSettingsDivider | Divider, same as `type: 'divider'` in Menu |
| remove | SchemaSettingsRemove | 删除,用于删除一个区块 | | remove | SchemaSettingsRemove | Remove, used to delete a block |
| select | SchemaSettingsSelectItem | 下拉选择 | | select | SchemaSettingsSelectItem | Dropdown select |
| cascader | SchemaSettingsCascaderItem | 级联选择 | | cascader | SchemaSettingsCascaderItem | Cascading select |
| switch | SchemaSettingsSwitchItem | 开关 | | switch | SchemaSettingsSwitchItem | Switch |
| popup | SchemaSettingsPopupItem | 弹出层 | | popup | SchemaSettingsPopupItem | Popup |
| actionModal | SchemaSettingsActionModalItem | 操作弹窗 | | actionModal | SchemaSettingsActionModalItem | Action modal |
| modal | SchemaSettingsModalItem | 弹窗 | | modal | SchemaSettingsModalItem | Modal |
### SchemaSettingsItem ### SchemaSettingsItem
文本,对应的 `type``item`
```tsx | pure ```tsx | pure
interface SchemaSettingsItemProps extends Omit<MenuItemProps, 'title'> { interface SchemaSettingsItemProps extends Omit<MenuItemProps, 'title'> {
title: string; title: string;
} }
``` ```
核心参数为 `title``onClick`,可以在 `onClick` 中修改 schema。 The core parameters are `title` and `onClick`, and you can modify the schema in `onClick`.
<code src="./demos/schema-settings-components-item.tsx"></code> <code src="./demos/schema-settings-components-item.tsx"></code>
### SchemaSettingsItemGroup ### SchemaSettingsItemGroup
分组,对应的 `type``itemGroup` The core parameter is `title`.
核心参数是 `title`
<code src="./demos/schema-settings-components-group.tsx"></code> <code src="./demos/schema-settings-components-group.tsx"></code>
### SchemaSettingsSubMenu ### SchemaSettingsSubMenu
子菜单,对应的 `type``subMenu` The core parameter is `title`.
核心参数是 `title`
<code src="./demos/schema-settings-components-sub-menu.tsx"></code> <code src="./demos/schema-settings-components-sub-menu.tsx"></code>
### SchemaSettingsDivider ### SchemaSettingsDivider
分割线,对应的 `type``divider`
<code src="./demos/schema-settings-components-divider.tsx"></code> <code src="./demos/schema-settings-components-divider.tsx"></code>
### SchemaSettingsRemove ### SchemaSettingsRemove
删除,对应的 `type``remove`
```tsx | pure ```tsx | pure
interface SchemaSettingsRemoveProps { interface SchemaSettingsRemoveProps {
confirm?: ModalFuncProps; confirm?: ModalFuncProps;
@ -399,32 +387,24 @@ interface SchemaSettingsRemoveProps {
} }
``` ```
- `confirm`:删除前的确认弹窗 - `confirm`: Confirmation modal before deletion
- `removeParentsIfNoChildren`:如果删除后没有子节点了,是否删除父节点 - `removeParentsIfNoChildren`: Whether to delete the parent node if there are no children after deletion
- `breakRemoveOn`:如果删除的节点满足条件,是否中断删除 - `breakRemoveOn`: Whether to interrupt deletion if the deleted node meets certain conditions
<code src="./demos/schema-settings-components-remove.tsx"></code> <code src="./demos/schema-settings-components-remove.tsx"></code>
### SchemaSettingsSelectItem ### SchemaSettingsSelectItem
选择器,对应的 `type``select`
<code src="./demos/schema-settings-components-select.tsx"></code> <code src="./demos/schema-settings-components-select.tsx"></code>
### SchemaSettingsCascaderItem ### SchemaSettingsCascaderItem
级联选择,对应的 `type``cascader`
### SchemaSettingsSwitchItem ### SchemaSettingsSwitchItem
开关,对应的 `type``switch`
<code src="./demos/schema-settings-components-switch.tsx"></code> <code src="./demos/schema-settings-components-switch.tsx"></code>
### SchemaSettingsModalItem ### SchemaSettingsModalItem
弹窗,对应的 `type``modal`
```tsx | pure ```tsx | pure
export interface SchemaSettingsModalItemProps { export interface SchemaSettingsModalItemProps {
title: string; title: string;
@ -444,15 +424,13 @@ export interface SchemaSettingsModalItemProps {
} }
``` ```
我们可以通过 `schema` 参数来定义弹窗的表单,然后在 `onSubmit` 中获取表单的值,然后修改当前 schema 节点。 We can define the form of the modal using the `schema` parameter, and then retrieve the form values in the `onSubmit` function to modify the current schema node.
<code src="./demos/schema-settings-components-modal.tsx"></code> <code src="./demos/schema-settings-components-modal.tsx"></code>
### SchemaSettingsActionModalItem ### SchemaSettingsActionModalItem
操作弹窗,对应的 `type``actionModal` The difference between `SchemaSettingsActionModalItem` and `SchemaSettingsModalItem` is that the `SchemaSettingsModalItem` modal will lose context, while the `SchemaSettingsActionModalItem` will retain context. In simple scenarios, you can use `SchemaSettingsModalItem`, and in complex scenarios, you can use `SchemaSettingsActionModalItem`.
其和 `modal` 的区别是,`SchemaSettingsModalItem` 弹窗会丢失上下文,而 `SchemaSettingsActionModalItem` 会保留上下文,简单场景下可以使用 `SchemaSettingsModalItem`,复杂场景下可以使用 `SchemaSettingsActionModalItem`
```tsx | pure ```tsx | pure
export interface SchemaSettingsActionModalItemProps extends SchemaSettingsModalItemProps, Omit<SchemaSettingsItemProps, 'onSubmit' | 'onClick'> { export interface SchemaSettingsActionModalItemProps extends SchemaSettingsModalItemProps, Omit<SchemaSettingsItemProps, 'onSubmit' | 'onClick'> {

View File

@ -2,15 +2,15 @@
![SchemaToolbar](../static/designer.png) ![SchemaToolbar](../static/designer.png)
## 组件 ## Component
### SchemaToolbar 组件 ### SchemaToolbar Component
此为默认的 Toolbar 组件,其内部会自动根据 Schema 的 `x-settings``x-initializer` 渲染 `SchemaSettings``SchemaInitializer``Drag` 组件。 This is the default Toolbar component, which automatically renders the `SchemaSettings`, `SchemaInitializer`, and `Drag` components based on the Schema's `x-settings` and `x-initializer`.
Toolbar 具体的渲染规则为:当有 `x-toolbar` 会渲染对应的组件;当无 `x-toolbar` 但是有 `x-settings``x-initializer` 会渲染默认的 `SchemaToolbar` 组件。 The specific rendering rules for the Toolbar are as follows: when `x-toolbar` is present, it renders the corresponding component; when there is no `x-toolbar` but `x-settings` and `x-initializer` are present, it renders the default `SchemaToolbar` component.
- 类型 - Type
```tsx | pure ```tsx | pure
interface SchemaToolbarProps { interface SchemaToolbarProps {
@ -26,17 +26,17 @@ interface SchemaToolbarProps {
} }
``` ```
- 详细解释 - Details
- `title`:左上角的标题 - `title`: The title in the top left corner.
- `draggable`:是否可以拖拽,默认为 `true` - `draggable`: Whether it can be dragged, default is `true`.
- `initializer``SchemaInitializer` 的默认值,当 schema 里没有 `x-initializer` 时,会使用此值;当为 `false` 时,不会渲染 `SchemaInitializer` - `initializer`: The default value of `SchemaInitializer`. When there is no `x-initializer` in the schema, this value will be used. When set to `false`, `SchemaInitializer` will not be rendered.
- `settings``SchemaSettings` 的默认值,当 schema 里没有 `x-settings` 时,会使用此值;当为 `false` 时,不会渲染 `SchemaSettings` - `settings`: The default value of `SchemaSettings`. When there is no `x-settings` in the schema, this value will be used. When set to `false`, `SchemaSettings` will not be rendered.
- `showBorder`:边框是否变为橘色 - `showBorder`: Whether the border becomes orange.
- `showBackground`:背景是否变为橘色 - `showBackground`: Whether the background becomes orange.
- 示例 - Example
未指定 `x-toolbar` 时会渲染默认的 `SchemaToolbar` 这个组件。 When `x-toolbar` is not specified, the default `SchemaToolbar` component will be rendered.
```tsx ```tsx
import { useFieldSchema } from '@formily/react'; import { useFieldSchema } from '@formily/react';
@ -99,7 +99,7 @@ const Hello = () => {
const hello1 = Grid.wrap({ const hello1 = Grid.wrap({
type: 'void', type: 'void',
// 仅指定了 `x-settings` 但是没有 `x-toolbar`,会使用默认的 `SchemaToolbar` 组件 // Only `x-settings` is specified but `x-toolbar` is not, the default `SchemaToolbar` component will be used.
'x-settings': 'mySettings', 'x-settings': 'mySettings',
'x-decorator': 'CardItem', 'x-decorator': 'CardItem',
'x-component': 'Hello', 'x-component': 'Hello',
@ -146,8 +146,7 @@ const app = new Application({
export default app.getRootComponent(); export default app.getRootComponent();
``` ```
自定义 Toolbar 组件。 Custom Toolbar component.
```tsx ```tsx
import { useFieldSchema } from '@formily/react'; import { useFieldSchema } from '@formily/react';
@ -193,12 +192,10 @@ const myInitializer = new SchemaInitializer({
title: 'Demo1', title: 'Demo1',
Component: () => { Component: () => {
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
// 调用插入功能
const { insert } = useSchemaInitializer(); const { insert } = useSchemaInitializer();
const handleClick = () => { const handleClick = () => {
insert({ insert({
type: 'void', type: 'void',
// 使用自定义的 Toolbar 组件
'x-toolbar': 'MyToolbar', 'x-toolbar': 'MyToolbar',
'x-settings': 'mySettings', 'x-settings': 'mySettings',
'x-decorator': 'CardItem', 'x-decorator': 'CardItem',
@ -218,7 +215,6 @@ const Hello = () => {
const hello1 = Grid.wrap({ const hello1 = Grid.wrap({
type: 'void', type: 'void',
// 使用自定义的 Toolbar 组件
'x-toolbar': 'MyToolbar', 'x-toolbar': 'MyToolbar',
'x-settings': 'mySettings', 'x-settings': 'mySettings',
'x-decorator': 'CardItem', 'x-decorator': 'CardItem',
@ -270,9 +266,9 @@ export default app.getRootComponent();
### useSchemaToolbarRender() ### useSchemaToolbarRender()
用于渲染 `SchemaToolbar` Used to render the `SchemaToolbar`.
- 类型 - Type
```tsx | pure ```tsx | pure
const useSchemaToolbarRender: (fieldSchema: ISchema) => { const useSchemaToolbarRender: (fieldSchema: ISchema) => {
@ -281,18 +277,18 @@ const useSchemaToolbarRender: (fieldSchema: ISchema) => {
} }
``` ```
- 详细解释 - Details
前面示例中 `'x-decorator': 'CardItem'` 中组件 `CardItem` 里面就调用了 `useSchemaToolbarRender()` 进行渲染。内置的组件还有:`BlockItem``CardItem``Action``FormItem` In the previous example, the component `CardItem` is used in the `'x-decorator': 'CardItem'` property, which calls `useSchemaToolbarRender()` for rendering. Other built-in components include: `BlockItem`, `CardItem`, `Action`, `FormItem`.
`render()` 支持二次覆盖组件属性。 The `render()` function supports overriding component properties.
- 示例 - Example
```tsx | pure ```tsx | pure
const MyDecorator = () => { const MyDecorator = () => {
const filedSchema = useFieldSchema(); const filedSchema = useFieldSchema();
const { render } = useSchemaToolbarRender(filedSchema); // 从 Schema 中读取 Toolbar 组件 const { render } = useSchemaToolbarRender(filedSchema);
return <Card>{ render() }</Card> return <Card>{ render() }</Card>
} }
@ -335,10 +331,8 @@ const MyToolbar = (props) => {
return <SchemaToolbar showBackground title='Test' {...props} /> return <SchemaToolbar showBackground title='Test' {...props} />
} }
// 自定义包装器
const MyDecorator = ({children}) => { const MyDecorator = ({children}) => {
const filedSchema = useFieldSchema(); const filedSchema = useFieldSchema();
// 使用 `useSchemaToolbarRender()` 获取并渲染内容
const { render } = useSchemaToolbarRender(filedSchema); const { render } = useSchemaToolbarRender(filedSchema);
return <Card style={{ marginBottom: 10 }}>{ render({ draggable: false }) }{children}</Card> return <Card style={{ marginBottom: 10 }}>{ render({ draggable: false }) }{children}</Card>
} }
@ -353,12 +347,10 @@ const myInitializer = new SchemaInitializer({
title: 'Demo1', title: 'Demo1',
Component: () => { Component: () => {
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
// 调用插入功能
const { insert } = useSchemaInitializer(); const { insert } = useSchemaInitializer();
const handleClick = () => { const handleClick = () => {
insert({ insert({
type: 'void', type: 'void',
// 使用自定义的 Toolbar 组件
'x-toolbar': 'MyToolbar', 'x-toolbar': 'MyToolbar',
'x-settings': 'mySettings', 'x-settings': 'mySettings',
'x-decorator': 'MyDecorator', 'x-decorator': 'MyDecorator',
@ -378,7 +370,6 @@ const Hello = () => {
const hello1 = Grid.wrap({ const hello1 = Grid.wrap({
type: 'void', type: 'void',
// 使用自定义的 Toolbar 组件
'x-toolbar': 'MyToolbar', 'x-toolbar': 'MyToolbar',
'x-settings': 'mySettings', 'x-settings': 'mySettings',
'x-decorator': 'MyDecorator', 'x-decorator': 'MyDecorator',

View File

@ -4,10 +4,10 @@
### tval ### tval
用于输出多语言的字符串。 Used to output multilingual strings.
- 类型 - Type
- 示例 - Example

View File

@ -15,56 +15,58 @@ interface AvailableFieldInterfacesExclude {
interface CollectionTemplateDefaultOptions { interface CollectionTemplateDefaultOptions {
/** /**
* 自动生成 id * Auto-generate id
* @default true * @default true
* */ * */
autoGenId?: boolean; autoGenId?: boolean;
/** 创建人 */ /** Created by */
createdBy?: boolean; createdBy?: boolean;
/** 最后更新人 */ /** Updated by */
updatedBy?: boolean; updatedBy?: boolean;
/** 创建日期 */ /** Created at */
createdAt?: boolean; createdAt?: boolean;
/** 更新日期 */ /** Updated at */
updatedAt?: boolean; updatedAt?: boolean;
/** 可排序 */ /** Sortable */
sortable?: boolean; sortable?: boolean;
/* 树结构 */ /* Tree structure */
tree?: string; tree?: string;
/* 日志 */ /* Logging */
logging?: boolean; logging?: boolean;
/** 继承 */ /** Inherits */
inherits?: string | string[]; inherits?: string | string[];
/* 字段列表 */ /* Field list */
fields?: CollectionOptions['fields']; fields?: CollectionOptions['fields'];
} }
class CollectionTemplate { class CollectionTemplate {
app: Application; constructor(public collectionTemplateManager: CollectionTemplateManager) {}
collectionManager: CollectionManager;
name: string; name: string;
Collection?: typeof Collection; Collection?: typeof Collection;
transform?: (collection: CollectionOptions, app: Application) => CollectionOptions;
title?: string; title?: string;
color?: string; color?: string;
/** 排序 */ /** Sorting */
order?: number; order?: number;
/** 默认配置 */ /** Default configuration */
default?: CollectionTemplateDefaultOptions; default?: CollectionTemplateDefaultOptions;
events?: any; events?: any;
/** UI 可配置的 CollectionOptions 参数(添加或编辑的 Collection 表单的字段) */ /** UI configurable CollectionOptions parameters (fields for adding or editing Collection forms) */
configurableProperties?: Record<string, ISchema>; configurableProperties?: Record<string, ISchema>;
/** 当前模板可用的字段类型 */ /** Available field types for the current template */
availableFieldInterfaces?: AvailableFieldInterfacesInclude | AvailableFieldInterfacesExclude; availableFieldInterfaces?: AvailableFieldInterfacesInclude | AvailableFieldInterfacesExclude;
/** 是否分割线 */ /** Whether it is a divider */
divider?: boolean; divider?: boolean;
/** 模板描述 */ /** Template description */
description?: string; description?: string;
/**配置字段中的操作按钮 */ /** Configure buttons in the configuration fields */
configureActions?: Record<string, ISchema>; configureActions?: Record<string, ISchema>;
//是否禁止删除字段 // Whether to prohibit deleting fields
forbidDeletion?: boolean; forbidDeletion?: boolean;
supportDataSourceType?: string[];
notSupportDataSourceType?: string[];
transform?(collection: CollectionOptions, app: Application): CollectionOptions;
} }
``` ```

View File

@ -280,7 +280,7 @@ const MyComponent = () => {
```tsx | pure ```tsx | pure
class DataSourceManager { class DataSourceManager {
getAllCollections(options: { getAllCollections(options?: {
filterCollection?: (collection: Collection) => boolean; filterCollection?: (collection: Collection) => boolean;
filterDataSource?: (dataSource: DataSource) => boolean; filterDataSource?: (dataSource: DataSource) => boolean;
}): (DataSourceOptions & { collections: Collection[] })[]; }): (DataSourceOptions & { collections: Collection[] })[];

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { APIClient, APIClientProvider, compose, useRequest } from '@nocobase/client'; import { APIClient, APIClientProvider, compose, useRequest } from '@nocobase/client';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { APIClient, APIClientProvider, compose, useRequest } from '@nocobase/client'; import { APIClient, APIClientProvider, compose, useRequest } from '@nocobase/client';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import { APIClient, APIClientProvider, useAPIClient, useRequest } from '@nocobase/client'; import { APIClient, APIClientProvider, useAPIClient, useRequest } from '@nocobase/client';

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Application, Plugin } from '@nocobase/client'; import { Application, Plugin } from '@nocobase/client';
import React, { FC } from 'react'; import React, { FC } from 'react';

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Application, Plugin, RouterManager, useApp } from '@nocobase/client'; import { Application, Plugin, RouterManager, useApp } from '@nocobase/client';
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Application, NocoBaseBuildInPlugin } from '@nocobase/client'; import { Application, NocoBaseBuildInPlugin } from '@nocobase/client';

View File

@ -0,0 +1,15 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { ISchema as FormilySchema } from '@formily/json-schema';
export interface ISchema extends FormilySchema {
'x-use-component-props'?: string | Function;
'x-use-decorator-props'?: string;
}

View File

@ -19,3 +19,4 @@ export * from './schema-toolbar';
export * from './PluginSettingsManager'; export * from './PluginSettingsManager';
export * from './hoc'; export * from './hoc';
export { ApplicationContext } from './context'; export { ApplicationContext } from './context';
export * from './globalType';

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { FormItem, Input } from '@formily/antd-v5'; import { FormItem, Input } from '@formily/antd-v5';
import { ISchema, observer, useForm } from '@formily/react'; import { ISchema, observer, useForm } from '@formily/react';

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { import {

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { ISchema } from '@formily/react'; import { ISchema } from '@formily/react';
import { import {

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { FormDrawer, FormLayout } from '@formily/antd-v5'; import { FormDrawer, FormLayout } from '@formily/antd-v5';
import { createForm } from '@formily/core'; import { createForm } from '@formily/core';

View File

@ -22,29 +22,28 @@ interface AvailableFieldInterfacesExclude {
interface CollectionTemplateDefaultOptions { interface CollectionTemplateDefaultOptions {
/** /**
* id * Auto-generate id
* @default true * @default true
* */ * */
autoGenId?: boolean; autoGenId?: boolean;
/** 创建人 */ /** Created by */
createdBy?: boolean; createdBy?: boolean;
/** 最后更新人 */ /** Updated by */
updatedBy?: boolean; updatedBy?: boolean;
/** 创建日期 */ /** Created at */
createdAt?: boolean; createdAt?: boolean;
/** 更新日期 */ /** Updated at */
updatedAt?: boolean; updatedAt?: boolean;
/** 可排序 */ /** Sortable */
sortable?: boolean; sortable?: boolean;
/* 树结构 */ /* Tree structure */
tree?: string; tree?: string;
/* 日志 */ /* Logging */
logging?: boolean; logging?: boolean;
/** 继承 */ /** Inherits */
inherits?: string | string[]; inherits?: string | string[];
/* 字段列表 */ /* Field list */
fields?: CollectionOptions['fields']; fields?: CollectionOptions['fields'];
[key: string]: any;
} }
export type CollectionTemplateFactory = new ( export type CollectionTemplateFactory = new (
@ -56,22 +55,22 @@ export abstract class CollectionTemplate {
Collection?: typeof Collection; Collection?: typeof Collection;
title?: string; title?: string;
color?: string; color?: string;
/** 排序 */ /** Sorting */
order?: number; order?: number;
/** 默认配置 */ /** Default configuration */
default?: CollectionTemplateDefaultOptions; default?: CollectionTemplateDefaultOptions;
events?: any; events?: any;
/** UI 可配置的 CollectionOptions 参数(添加或编辑的 Collection 表单的字段) */ /** UI configurable CollectionOptions parameters (fields for adding or editing Collection forms) */
configurableProperties?: Record<string, ISchema>; configurableProperties?: Record<string, ISchema>;
/** 当前模板可用的字段类型 */ /** Available field types for the current template */
availableFieldInterfaces?: AvailableFieldInterfacesInclude | AvailableFieldInterfacesExclude; availableFieldInterfaces?: AvailableFieldInterfacesInclude | AvailableFieldInterfacesExclude;
/** 是否分割线 */ /** Whether it is a divider */
divider?: boolean; divider?: boolean;
/** 模板描述 */ /** Template description */
description?: string; description?: string;
/**配置字段中的操作按钮 */ /** Configure buttons in the configuration fields */
configureActions?: Record<string, ISchema>; configureActions?: Record<string, ISchema>;
//是否禁止删除字段 // Whether to prohibit deleting fields
forbidDeletion?: boolean; forbidDeletion?: boolean;
supportDataSourceType?: string[]; supportDataSourceType?: string[];

View File

@ -0,0 +1,139 @@
{
"key": "data-source2",
"displayName": "Data Source 2",
"status": "loaded",
"type": "postgres",
"isDBInstance": true,
"collections": [
{
"name": "test",
"title": "test",
"tableName": "test",
"timestamps": false,
"autoGenId": false,
"filterTargetKey": "id",
"fields": [
{
"name": "id",
"type": "integer",
"allowNull": false,
"primaryKey": false,
"unique": false,
"autoIncrement": true,
"possibleTypes": ["integer", "sort"],
"rawType": "INTEGER",
"interface": "integer",
"uiSchema": {
"type": "number",
"x-component": "InputNumber",
"x-component-props": {
"stringMode": true,
"step": "1"
},
"x-validator": "integer",
"title": "id"
}
},
{
"name": "title",
"type": "string",
"allowNull": false,
"primaryKey": false,
"unique": false,
"possibleTypes": ["string", "uuid", "nanoid"],
"rawType": "CHARACTER VARYING(255)",
"interface": "input",
"uiSchema": {
"x-component": "Input",
"x-component-props": {
"style": {
"width": "100%"
}
},
"title": "title"
}
},
{
"name": "content",
"type": "text",
"allowNull": true,
"primaryKey": false,
"unique": false,
"rawType": "TEXT",
"interface": "textarea",
"uiSchema": {
"type": "string",
"x-component": "Input.TextArea",
"title": "content"
}
}
],
"introspected": true
},
{
"name": "test2",
"title": "test2",
"tableName": "test2",
"timestamps": false,
"autoGenId": false,
"filterTargetKey": "id",
"fields": [
{
"name": "id",
"type": "integer",
"allowNull": false,
"primaryKey": true,
"unique": false,
"autoIncrement": true,
"possibleTypes": ["integer", "sort"],
"rawType": "INTEGER",
"interface": "integer",
"uiSchema": {
"type": "number",
"x-component": "InputNumber",
"x-component-props": {
"stringMode": true,
"step": "1"
},
"x-validator": "integer",
"title": "id"
}
},
{
"name": "title",
"type": "string",
"allowNull": true,
"primaryKey": false,
"unique": false,
"possibleTypes": ["string", "uuid", "nanoid"],
"rawType": "CHARACTER VARYING(255)",
"interface": "input",
"uiSchema": {
"x-component": "Input",
"x-component-props": {
"style": {
"width": "100%"
}
},
"title": "title"
}
},
{
"name": "content",
"type": "text",
"allowNull": true,
"primaryKey": false,
"unique": false,
"rawType": "TEXT",
"interface": "textarea",
"uiSchema": {
"type": "string",
"x-component": "Input.TextArea",
"title": "content"
}
}
],
"introspected": true
}
]
}

View File

@ -0,0 +1,819 @@
[
{
"key": "yzowed2vee0",
"name": "users",
"title": "{{t(\"Users\")}}",
"inherit": false,
"hidden": false,
"description": null,
"fields": [
{
"key": "6m3kn2pytkc",
"name": "id",
"type": "bigInt",
"interface": "id",
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"autoIncrement": true,
"primaryKey": true,
"allowNull": false,
"uiSchema": {
"type": "number",
"title": "{{t(\"ID\")}}",
"x-component": "InputNumber",
"x-read-pretty": true
}
},
{
"key": "8douy9r69x5",
"name": "nickname",
"type": "string",
"interface": "input",
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"uiSchema": {
"type": "string",
"title": "{{t(\"Nickname\")}}",
"x-component": "Input"
}
},
{
"key": "vp191ptc0d7",
"name": "username",
"type": "string",
"interface": "input",
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"unique": true,
"uiSchema": {
"type": "string",
"title": "{{t(\"Username\")}}",
"x-component": "Input",
"x-validator": {
"username": true
},
"required": true
}
},
{
"key": "47o82qhkvdm",
"name": "email",
"type": "string",
"interface": "email",
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"unique": true,
"uiSchema": {
"type": "string",
"title": "{{t(\"Email\")}}",
"x-component": "Input",
"x-validator": "email",
"required": true
}
},
{
"key": "q5i9ynhq325",
"name": "phone",
"type": "string",
"interface": "phone",
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"unique": true,
"uiSchema": {
"type": "string",
"title": "{{t(\"Phone\")}}",
"x-component": "Input",
"x-validator": "phone",
"required": true
}
},
{
"key": "cc4aslvh9dv",
"name": "password",
"type": "password",
"interface": "password",
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"hidden": true,
"uiSchema": {
"type": "string",
"title": "{{t(\"Password\")}}",
"x-component": "Password"
}
},
{
"key": "e87ndyttazh",
"name": "appLang",
"type": "string",
"interface": null,
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null
},
{
"key": "snfbet0pe49",
"name": "resetToken",
"type": "string",
"interface": null,
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"unique": true,
"hidden": true
},
{
"key": "j78yhz6wifd",
"name": "systemSettings",
"type": "json",
"interface": null,
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"defaultValue": {}
},
{
"key": "lkxqml8gchd",
"name": "sort",
"type": "sort",
"interface": null,
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"hidden": true
},
{
"key": "lt3pcrjngzc",
"name": "createdById",
"type": "context",
"interface": null,
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"dataType": "bigInt",
"dataIndex": "state.currentUser.id",
"createOnly": true,
"visible": true,
"index": true
},
{
"key": "lcfaf27uxyz",
"name": "createdBy",
"type": "belongsTo",
"interface": null,
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"target": "users",
"foreignKey": "createdById",
"targetKey": "id"
},
{
"key": "y6lwdb31r5t",
"name": "updatedById",
"type": "context",
"interface": null,
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"dataType": "bigInt",
"dataIndex": "state.currentUser.id",
"visible": true,
"index": true
},
{
"key": "exhbmthsin0",
"name": "updatedBy",
"type": "belongsTo",
"interface": null,
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"target": "users",
"foreignKey": "updatedById",
"targetKey": "id"
},
{
"key": "s921nnlzdwi",
"name": "roles",
"type": "belongsToMany",
"interface": "m2m",
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"target": "roles",
"foreignKey": "userId",
"otherKey": "roleName",
"onDelete": "CASCADE",
"sourceKey": "id",
"targetKey": "name",
"through": "rolesUsers",
"uiSchema": {
"type": "array",
"title": "{{t(\"Roles\")}}",
"x-component": "AssociationField",
"x-component-props": {
"multiple": true,
"fieldNames": {
"label": "title",
"value": "name"
}
}
}
},
{
"key": "qe7b1rsct5h",
"name": "jobs",
"type": "belongsToMany",
"interface": null,
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"through": "users_jobs",
"foreignKey": "userId",
"sourceKey": "id",
"otherKey": "jobId",
"targetKey": "id",
"target": "jobs"
},
{
"key": "vt0n1l1ruyz",
"name": "usersJobs",
"type": "hasMany",
"interface": null,
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"target": "users_jobs",
"foreignKey": "userId",
"sourceKey": "id",
"targetKey": "id"
},
{
"key": "ekol7p60nry",
"name": "sortName",
"type": "sort",
"interface": "sort",
"description": null,
"collectionName": "users",
"parentKey": null,
"reverseKey": null,
"uiSchema": {
"type": "number",
"x-component": "InputNumber",
"x-component-props": {
"stringMode": true,
"step": "1"
},
"x-validator": "integer",
"title": "sort"
}
}
],
"category": [],
"origin": "@nocobase/plugin-users",
"dumpRules": {
"group": "user"
},
"sortable": "sort",
"model": "UserModel",
"createdBy": true,
"updatedBy": true,
"logging": true,
"shared": true,
"from": "db2cm",
"filterTargetKey": "id"
},
{
"key": "rmx938ttbue",
"name": "roles",
"title": "{{t(\"Roles\")}}",
"inherit": false,
"hidden": false,
"description": null,
"fields": [
{
"key": "l6thu4n5u6x",
"name": "name",
"type": "uid",
"interface": "input",
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null,
"prefix": "r_",
"primaryKey": true,
"uiSchema": {
"type": "string",
"title": "{{t(\"Role UID\")}}",
"x-component": "Input"
}
},
{
"key": "yhfq9yv8z0p",
"name": "title",
"type": "string",
"interface": "input",
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null,
"unique": true,
"uiSchema": {
"type": "string",
"title": "{{t(\"Role name\")}}",
"x-component": "Input"
},
"translation": true
},
{
"key": "vnhjlmopfuz",
"name": "description",
"type": "string",
"interface": null,
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null
},
{
"key": "s4iqsehgxo6",
"name": "strategy",
"type": "json",
"interface": null,
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null
},
{
"key": "75e4wnv873m",
"name": "default",
"type": "boolean",
"interface": null,
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null,
"defaultValue": false
},
{
"key": "nofdv0gte68",
"name": "hidden",
"type": "boolean",
"interface": null,
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null,
"defaultValue": false
},
{
"key": "bogzo1uvk84",
"name": "allowConfigure",
"type": "boolean",
"interface": null,
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null
},
{
"key": "k3fvj8ddpp9",
"name": "allowNewMenu",
"type": "boolean",
"interface": null,
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null
},
{
"key": "v1ditqsv1uk",
"name": "menuUiSchemas",
"type": "belongsToMany",
"interface": null,
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null,
"target": "uiSchemas",
"targetKey": "x-uid",
"foreignKey": "roleName",
"sourceKey": "name",
"otherKey": "uiSchemaXUid",
"through": "rolesUischemas"
},
{
"key": "ccqhlcvgnz8",
"name": "resources",
"type": "hasMany",
"interface": null,
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null,
"target": "dataSourcesRolesResources",
"sourceKey": "name",
"foreignKey": "roleName",
"targetKey": "id"
},
{
"key": "s4fshtx7oxv",
"name": "snippets",
"type": "set",
"interface": null,
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null,
"defaultValue": ["!ui.*", "!pm", "!pm.*"]
},
{
"key": "oyzvbhc60mp",
"name": "users",
"type": "belongsToMany",
"interface": null,
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null,
"target": "users",
"foreignKey": "roleName",
"otherKey": "userId",
"onDelete": "CASCADE",
"sourceKey": "name",
"targetKey": "id",
"through": "rolesUsers"
},
{
"key": "89yklh7lm3p",
"name": "sort",
"type": "sort",
"interface": null,
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null,
"hidden": true
},
{
"key": "iz5s22dinui",
"name": "color",
"type": "string",
"interface": "color",
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null,
"defaultValue": "#1677FF",
"uiSchema": {
"type": "string",
"x-component": "ColorPicker",
"default": "#1677FF",
"title": "color"
}
},
{
"key": "o5nyb6isl62",
"name": "long-text",
"type": "text",
"interface": "textarea",
"description": null,
"collectionName": "roles",
"parentKey": null,
"reverseKey": null,
"uiSchema": {
"type": "string",
"x-component": "Input.TextArea",
"title": "Long text"
}
}
],
"category": [],
"origin": "@nocobase/plugin-acl",
"dumpRules": "required",
"autoGenId": false,
"model": "RoleModel",
"filterTargetKey": "name",
"sortable": true,
"from": "db2cm"
},
{
"key": "24gntrrr5a6",
"name": "tree",
"title": "TreeCollection",
"inherit": false,
"hidden": false,
"description": null,
"fields": [
{
"key": "pcea3h3ivkg",
"name": "parentId",
"type": "bigInt",
"interface": "integer",
"description": null,
"collectionName": "t_4uamm7v51dj",
"parentKey": null,
"reverseKey": null,
"isForeignKey": true,
"uiSchema": {
"type": "number",
"title": "{{t(\"Parent ID\")}}",
"x-component": "InputNumber",
"x-read-pretty": true
},
"target": "t_4uamm7v51dj"
},
{
"key": "185j2rf7o68",
"name": "parent",
"type": "belongsTo",
"interface": "m2o",
"description": null,
"collectionName": "t_4uamm7v51dj",
"parentKey": null,
"reverseKey": null,
"foreignKey": "parentId",
"treeParent": true,
"onDelete": "CASCADE",
"uiSchema": {
"title": "{{t(\"Parent\")}}",
"x-component": "AssociationField",
"x-component-props": {
"multiple": false,
"fieldNames": {
"label": "id",
"value": "id"
}
}
},
"target": "t_4uamm7v51dj",
"targetKey": "id"
},
{
"key": "gjvso3p9sjn",
"name": "children",
"type": "hasMany",
"interface": "o2m",
"description": null,
"collectionName": "t_4uamm7v51dj",
"parentKey": null,
"reverseKey": null,
"foreignKey": "parentId",
"treeChildren": true,
"onDelete": "CASCADE",
"uiSchema": {
"title": "{{t(\"Children\")}}",
"x-component": "AssociationField",
"x-component-props": {
"multiple": true,
"fieldNames": {
"label": "id",
"value": "id"
}
}
},
"target": "t_4uamm7v51dj",
"targetKey": "id",
"sourceKey": "id"
},
{
"key": "j50f3am3c88",
"name": "id",
"type": "bigInt",
"interface": "integer",
"description": null,
"collectionName": "t_4uamm7v51dj",
"parentKey": null,
"reverseKey": null,
"autoIncrement": true,
"primaryKey": true,
"allowNull": false,
"uiSchema": {
"type": "number",
"title": "{{t(\"ID\")}}",
"x-component": "InputNumber",
"x-read-pretty": true
},
"target": "t_4uamm7v51dj"
},
{
"key": "9szmn2ecqgs",
"name": "f_y99u3pyj0bt",
"type": "string",
"interface": "input",
"description": null,
"collectionName": "t_4uamm7v51dj",
"parentKey": null,
"reverseKey": null,
"uiSchema": {
"type": "string",
"x-component": "Input",
"title": "Single line text"
}
}
],
"category": [],
"logging": true,
"autoGenId": true,
"createdAt": false,
"createdBy": false,
"updatedAt": false,
"updatedBy": false,
"template": "tree",
"view": false,
"tree": "adjacencyList",
"filterTargetKey": "id"
},
{
"key": "16ocj2rsg3t",
"name": "interfaces",
"title": "Interfaces",
"inherit": false,
"hidden": false,
"description": null,
"fields": [
{
"key": "k2v39l19inp",
"name": "id",
"type": "bigInt",
"interface": "integer",
"description": null,
"collectionName": "interfaces",
"parentKey": null,
"reverseKey": null,
"autoIncrement": true,
"primaryKey": true,
"allowNull": false,
"uiSchema": {
"type": "number",
"title": "{{t(\"ID\")}}",
"x-component": "InputNumber",
"x-read-pretty": true
}
},
{
"key": "gfnqdj8sd01",
"name": "createdAt",
"type": "date",
"interface": "createdAt",
"description": null,
"collectionName": "interfaces",
"parentKey": null,
"reverseKey": null,
"field": "createdAt",
"uiSchema": {
"type": "datetime",
"title": "{{t(\"Created at\")}}",
"x-component": "DatePicker",
"x-component-props": {},
"x-read-pretty": true
}
},
{
"key": "3ddqrb1lle5",
"name": "createdBy",
"type": "belongsTo",
"interface": "createdBy",
"description": null,
"collectionName": "interfaces",
"parentKey": null,
"reverseKey": null,
"target": "users",
"foreignKey": "createdById",
"uiSchema": {
"type": "object",
"title": "{{t(\"Created by\")}}",
"x-component": "AssociationField",
"x-component-props": {
"fieldNames": {
"value": "id",
"label": "nickname"
}
},
"x-read-pretty": true
},
"targetKey": "id"
},
{
"key": "9nc7gqqw0ht",
"name": "updatedAt",
"type": "date",
"interface": "updatedAt",
"description": null,
"collectionName": "interfaces",
"parentKey": null,
"reverseKey": null,
"field": "updatedAt",
"uiSchema": {
"type": "string",
"title": "{{t(\"Last updated at\")}}",
"x-component": "DatePicker",
"x-component-props": {},
"x-read-pretty": true
}
},
{
"key": "06wr4f2qi4w",
"name": "updatedBy",
"type": "belongsTo",
"interface": "updatedBy",
"description": null,
"collectionName": "interfaces",
"parentKey": null,
"reverseKey": null,
"target": "users",
"foreignKey": "updatedById",
"uiSchema": {
"type": "object",
"title": "{{t(\"Last updated by\")}}",
"x-component": "AssociationField",
"x-component-props": {
"fieldNames": {
"value": "id",
"label": "nickname"
}
},
"x-read-pretty": true
},
"targetKey": "id"
},
{
"key": "g5beggm3aln",
"name": "nano-iD",
"type": "nanoid",
"interface": "nanoid",
"description": null,
"collectionName": "interfaces",
"parentKey": null,
"reverseKey": null,
"customAlphabet": "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
"size": 21,
"autoFill": true,
"uiSchema": {
"type": "string",
"x-component": "NanoIDInput",
"title": "Nano ID"
}
},
{
"key": "wchbz23orvg",
"name": "attachment",
"type": "belongsToMany",
"interface": "attachment",
"description": null,
"collectionName": "interfaces",
"parentKey": null,
"reverseKey": null,
"uiSchema": {
"x-component-props": {
"accept": "image/*",
"multiple": true
},
"type": "array",
"x-component": "Upload.Attachment",
"title": "Attachment"
},
"target": "attachments",
"through": "t_zj0zu7maytd",
"foreignKey": "f_iek1e32gsq0",
"otherKey": "f_dtc6w8dzyoo",
"targetKey": "id",
"sourceKey": "id"
}
],
"category": [],
"logging": true,
"autoGenId": true,
"createdAt": true,
"createdBy": true,
"updatedAt": true,
"updatedBy": true,
"template": "general",
"view": false,
"filterTargetKey": "id"
}
]

View File

@ -0,0 +1,287 @@
{
"users:list": {
"data": [
{
"createdAt": "2024-04-07T06:50:37.797Z",
"updatedAt": "2024-04-07T06:50:37.797Z",
"appLang": null,
"createdById": null,
"email": "admin@nocobase.com",
"f_1gx8uyn3wva": 1,
"id": 1,
"nickname": "Super Admin",
"phone": null,
"systemSettings": {},
"updatedById": null,
"username": "nocobase",
"roles": [
{
"createdAt": "2024-04-07T06:50:37.700Z",
"updatedAt": "2024-04-07T06:50:37.700Z",
"allowConfigure": null,
"allowNewMenu": true,
"default": true,
"description": null,
"hidden": false,
"color": "#1677FF",
"name": "member",
"snippets": ["!pm", "!pm.*", "!ui.*"],
"strategy": {
"actions": ["view", "update:own", "destroy:own", "create"]
},
"title": "{{t(\"Member\")}}",
"rolesUsers": {
"createdAt": "2024-04-07T06:50:37.854Z",
"updatedAt": "2024-04-07T06:50:37.854Z",
"default": null,
"roleName": "member",
"userId": 1
}
},
{
"createdAt": "2024-04-07T06:50:37.622Z",
"updatedAt": "2024-04-07T06:50:37.622Z",
"allowConfigure": null,
"allowNewMenu": null,
"default": false,
"description": null,
"hidden": true,
"color": "#1677FF",
"name": "root",
"snippets": ["pm", "pm.*", "ui.*"],
"strategy": null,
"title": "{{t(\"Root\")}}",
"rolesUsers": {
"createdAt": "2024-04-07T06:50:38.152Z",
"updatedAt": "2024-04-07T06:50:38.186Z",
"default": true,
"roleName": "root",
"userId": 1
}
},
{
"createdAt": "2024-04-07T06:50:37.657Z",
"updatedAt": "2024-04-07T06:50:37.657Z",
"allowConfigure": true,
"allowNewMenu": true,
"default": false,
"description": null,
"hidden": false,
"name": "admin",
"color": "#1677FF",
"snippets": ["pm", "pm.*", "ui.*"],
"strategy": {
"actions": ["create", "view", "update", "destroy"]
},
"title": "{{t(\"Admin\")}}",
"rolesUsers": {
"createdAt": "2024-04-07T06:50:38.152Z",
"updatedAt": "2024-04-07T06:50:38.152Z",
"default": null,
"roleName": "admin",
"userId": 1
}
}
]
}
],
"meta": {
"count": 1,
"page": 1,
"pageSize": 20,
"totalPage": 1,
"allowedActions": {
"view": [1],
"update": [1],
"destroy": []
}
}
},
"users:get": {
"data": {
"createdAt": "2024-04-07T06:50:37.797Z",
"updatedAt": "2024-04-07T06:50:37.797Z",
"appLang": null,
"createdById": null,
"email": "admin@nocobase.com",
"f_1gx8uyn3wva": 1,
"id": 1,
"nickname": "Super Admin",
"phone": null,
"systemSettings": {},
"updatedById": null,
"username": "nocobase",
"roles": [
{
"createdAt": "2024-04-07T06:50:37.700Z",
"updatedAt": "2024-04-07T06:50:37.700Z",
"allowConfigure": null,
"allowNewMenu": true,
"default": true,
"description": null,
"hidden": false,
"color": "#1677FF",
"name": "member",
"snippets": ["!pm", "!pm.*", "!ui.*"],
"strategy": {
"actions": ["view", "update:own", "destroy:own", "create"]
},
"title": "{{t(\"Member\")}}",
"rolesUsers": {
"createdAt": "2024-04-07T06:50:37.854Z",
"updatedAt": "2024-04-07T06:50:37.854Z",
"default": null,
"roleName": "member",
"userId": 1
}
},
{
"createdAt": "2024-04-07T06:50:37.622Z",
"updatedAt": "2024-04-07T06:50:37.622Z",
"allowConfigure": null,
"allowNewMenu": null,
"default": false,
"description": null,
"hidden": true,
"color": "#1677FF",
"name": "root",
"snippets": ["pm", "pm.*", "ui.*"],
"strategy": null,
"title": "{{t(\"Root\")}}",
"rolesUsers": {
"createdAt": "2024-04-07T06:50:38.152Z",
"updatedAt": "2024-04-07T06:50:38.186Z",
"default": true,
"roleName": "root",
"userId": 1
}
},
{
"createdAt": "2024-04-07T06:50:37.657Z",
"updatedAt": "2024-04-07T06:50:37.657Z",
"allowConfigure": true,
"allowNewMenu": true,
"default": false,
"description": null,
"hidden": false,
"name": "admin",
"color": "#1677FF",
"snippets": ["pm", "pm.*", "ui.*"],
"strategy": {
"actions": ["create", "view", "update", "destroy"]
},
"title": "{{t(\"Admin\")}}",
"rolesUsers": {
"createdAt": "2024-04-07T06:50:38.152Z",
"updatedAt": "2024-04-07T06:50:38.152Z",
"default": null,
"roleName": "admin",
"userId": 1
}
}
]
}
},
"roles:list": {
"data": [
{
"createdAt": "2024-04-07T06:50:37.622Z",
"updatedAt": "2024-04-07T06:50:37.622Z",
"allowConfigure": null,
"allowNewMenu": null,
"default": false,
"description": null,
"hidden": true,
"name": "root",
"color": "#1677FF",
"snippets": ["pm", "pm.*", "ui.*"],
"strategy": null,
"title": "{{t(\"Root\")}}"
},
{
"createdAt": "2024-04-07T06:50:37.657Z",
"updatedAt": "2024-04-07T06:50:37.657Z",
"allowConfigure": true,
"allowNewMenu": true,
"default": false,
"description": null,
"hidden": false,
"color": "#1677FF",
"name": "admin",
"snippets": ["pm", "pm.*", "ui.*"],
"strategy": {
"actions": ["create", "view", "update", "destroy"]
},
"title": "{{t(\"Admin\")}}"
},
{
"createdAt": "2024-04-07T06:50:37.700Z",
"updatedAt": "2024-04-07T06:50:37.700Z",
"allowConfigure": null,
"allowNewMenu": true,
"default": true,
"description": null,
"color": "#1677FF",
"hidden": false,
"name": "member",
"snippets": ["!pm", "!pm.*", "!ui.*"],
"strategy": {
"actions": ["view", "update:own", "destroy:own", "create"]
},
"title": "{{t(\"Member\")}}"
}
],
"meta": {
"count": 3,
"page": 1,
"pageSize": 20,
"totalPage": 1,
"allowedActions": {
"view": ["root", "admin", "member"],
"update": ["root", "admin", "member"],
"destroy": []
}
}
},
"roles:get": {
"data": {
"createdAt": "2024-04-07T06:50:37.622Z",
"updatedAt": "2024-04-07T06:50:37.622Z",
"allowConfigure": null,
"allowNewMenu": null,
"default": false,
"description": null,
"hidden": true,
"name": "root",
"color": "#1677FF",
"snippets": ["pm", "pm.*", "ui.*"],
"strategy": null,
"title": "{{t(\"Root\")}}"
}
},
"tree:list": {
"data": [
{
"id": 1,
"parentId": null,
"f_y99u3pyj0bt": "1"
},
{
"id": 2,
"parentId": 1,
"f_y99u3pyj0bt": "2"
}
],
"meta": {
"count": 2,
"page": 1,
"pageSize": 20,
"totalPage": 1,
"allowedActions": {
"view": [1, 2],
"update": [1, 2],
"destroy": [1, 2]
}
}
}
}

View File

@ -0,0 +1,124 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import MockAdapter from 'axios-mock-adapter';
import { AxiosInstance, AxiosRequestConfig } from 'axios';
import {
ActionInitializer,
AntdSchemaComponentPlugin,
Application,
ApplicationOptions,
CollectionPlugin,
LocalDataSource,
SchemaSettingsPlugin,
} from '../index';
import dataSourceMainCollections from './dataSourceMainCollections.json';
import dataSource2 from './dataSource2.json';
import dataSourceMainData from './dataSourceMainData.json';
import _ from 'lodash';
const defaultApis = {
'uiSchemas:patch': { data: { result: 'ok' } },
'uiSchemas:batchPatch': { data: { result: 'ok' } },
'uiSchemas:saveAsTemplate': { data: { result: 'ok' } },
'users:update': { data: { result: 'ok' } },
'users:create': { data: { result: 'ok' } },
'roles:update': { data: { result: 'ok' } },
'roles:create': { data: { result: 'ok' } },
...dataSourceMainData,
};
type URL = string;
type ResponseData = any;
type MockApis = Record<URL, ResponseData>;
function getProcessMockData(apis: Record<string, any>, key: string) {
return (config: AxiosRequestConfig) => {
if (!apis[key]) return [404, { data: { message: 'mock data not found' } }];
if (config?.params?.pageSize || config?.params?.page) {
const { data, meta } = apis[key];
const pageSize = config.params.pageSize || meta?.pageSize || 20;
const page = config.params.page || meta?.page || 1;
return [
200,
{
data: data.slice(pageSize * (page - 1), pageSize * page),
meta: {
...meta,
page,
pageSize,
count: data.length,
totalPage: Math.ceil(data.length / pageSize),
},
},
];
}
return [200, apis[key]];
};
}
export const mockApi = (axiosInstance: AxiosInstance, apis: MockApis = {}, delayResponse?: number) => {
const mock = new MockAdapter(axiosInstance, { delayResponse });
Object.keys(apis).forEach((key) => {
mock.onAny(key).reply(getProcessMockData(apis, key));
});
return (apis: MockApis = {}) => {
Object.keys(apis).forEach((key) => {
mock.onAny(key).reply(getProcessMockData(apis, key));
});
};
};
export const mockAppApi = (app: Application, apis: MockApis = {}, delayResponse?: number) => {
const mock = mockApi(app.apiClient.axios, apis, delayResponse);
return mock;
};
export interface MockAppOptions extends ApplicationOptions {
apis?: MockApis;
delayResponse?: number;
enableMultipleDataSource?: boolean;
}
export const mockApp = (options: MockAppOptions) => {
const {
apis: optionsApis = {},
enableMultipleDataSource,
delayResponse,
router = { type: 'memory', initialEntries: ['/'] },
...appOptions
} = options;
const app = new Application({
disableAcl: true,
...appOptions,
router,
});
app.pluginManager.add(AntdSchemaComponentPlugin);
app.pluginManager.add(SchemaSettingsPlugin);
app.pluginManager.add(CollectionPlugin, { config: { enableRemoteDataSource: false } });
app.addComponents({ ActionInitializer });
const apis = Object.assign({}, defaultApis, optionsApis);
app.getCollectionManager().addCollections(dataSourceMainCollections as any);
if (enableMultipleDataSource) {
app.dataSourceManager.addDataSource(LocalDataSource, dataSource2 as any);
}
mockAppApi(app, apis, delayResponse);
return app;
};

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Icon } from '@nocobase/client'; import { Icon } from '@nocobase/client';
import React from 'react'; import React from 'react';

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Icon } from '@nocobase/client'; import { Icon } from '@nocobase/client';
import React from 'react'; import React from 'react';

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Icon } from '@nocobase/client'; import { Icon } from '@nocobase/client';
import React from 'react'; import React from 'react';

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Icon } from '@nocobase/client'; import { Icon } from '@nocobase/client';
import React from 'react'; import React from 'react';

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { ISchema, observer, useForm } from '@formily/react'; import { ISchema, observer, useForm } from '@formily/react';
import { import {

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { ISchema, observer, useForm } from '@formily/react'; import { ISchema, observer, useForm } from '@formily/react';
import { import {

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Field } from '@formily/core'; import { Field } from '@formily/core';
import { ISchema, observer, useField, useFieldSchema } from '@formily/react'; import { ISchema, observer, useField, useFieldSchema } from '@formily/react';

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { ISchema, observer, useForm } from '@formily/react'; import { ISchema, observer, useForm } from '@formily/react';
import { import {

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { import {
ArrayTable, ArrayTable,

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { ISchema } from '@formily/react'; import { ISchema } from '@formily/react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';

View File

@ -1,58 +1,56 @@
/** import { SchemaComponent, useActionContext, Plugin, ISchema } from '@nocobase/client';
* This file is part of the NocoBase (R) project. import { mockApp } from '@nocobase/client/demo-utils';
* Copyright (c) 2020-2024 NocoBase Co., Ltd. import React from 'react';
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { useActionContext } from '@nocobase/client'; function useCloseActionProps() {
import { getAppComponent } from '@nocobase/test/web'; const { setVisible } = useActionContext();
return {
const App = getAppComponent({ type: 'default',
schema: { onClick() {
type: 'void', setVisible(false);
name: 'root', },
properties: { };
test: { }
type: 'void', const schema: ISchema = {
'x-component': 'Action', name: 'test',
title: 'Open', type: 'void',
'x-component-props': { 'x-component': 'Action',
openMode: 'drawer', title: 'Open',
}, 'x-component-props': {
properties: { openMode: 'drawer',
drawer: { },
type: 'void', properties: {
'x-component': 'Action.Container', drawer: {
title: 'Title', type: 'void',
properties: { 'x-component': 'Action.Container',
footer: { title: 'Title',
type: 'void', properties: {
'x-component': 'Action.Container.Footer', footer: {
properties: { type: 'void',
close: { 'x-component': 'Action.Container.Footer',
title: 'Close', properties: {
'x-component': 'Action', close: {
'x-use-component-props': function useActionProps() { title: 'Close',
const { setVisible } = useActionContext(); 'x-component': 'Action',
return { 'x-use-component-props': 'useCloseActionProps',
type: 'default',
onClick() {
setVisible(false);
},
};
},
},
},
},
}, },
}, },
}, },
}, },
}, },
}, },
}); }
export default App; const Demo = () => {
return <SchemaComponent schema={schema} scope={{ useCloseActionProps }} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({ plugins: [DemoPlugin] });
export default app.getRootComponent();

View File

@ -1,68 +1,60 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { ISchema, observer } from '@formily/react';
import { import {
Action,
ActionContextProvider, ActionContextProvider,
Form, ISchema,
FormItem,
Input,
SchemaComponent, SchemaComponent,
SchemaComponentProvider, Plugin,
useActionContext, useActionContext,
} from '@nocobase/client'; } from '@nocobase/client';
import { mockApp } from '@nocobase/client/demo-utils';
import React, { useState } from 'react'; import React, { useState } from 'react';
function useActionProps() {
const { setVisible } = useActionContext();
return {
onClick() {
setVisible(false);
},
};
}
const schema: ISchema = { const schema: ISchema = {
type: 'object', name: 'test',
'x-component': 'Action.Drawer',
type: 'void',
title: 'Drawer Title',
properties: { properties: {
drawer1: { hello1: {
'x-component': 'Action.Drawer', 'x-content': 'Hello',
title: 'T1',
},
footer1: {
'x-component': 'Action.Drawer.Footer',
type: 'void', type: 'void',
title: 'Drawer Title',
properties: { properties: {
hello1: { close1: {
'x-content': 'Hello', title: 'Close',
title: 'T1', 'x-component': 'Action',
}, 'x-use-component-props': 'useActionProps'
footer1: {
'x-component': 'Action.Drawer.Footer',
type: 'void',
properties: {
close1: {
title: 'Close',
'x-component': 'Action',
'x-use-component-props': function useActionProps() {
const { setVisible } = useActionContext();
return {
onClick() {
setVisible(false);
},
};
},
},
},
}, },
}, },
}, },
}, },
}
const Demo = () => {
const [visible, setVisible] = useState(false);
return <ActionContextProvider value={{ visible, setVisible }}>
<a onClick={() => setVisible(true)}>Open</a>
<SchemaComponent schema={schema} scope={{ useActionProps }} />
</ActionContextProvider>;
}; };
export default observer(() => { class DemoPlugin extends Plugin {
const [visible, setVisible] = useState(false); async load() {
return ( this.app.router.add('root', { path: '/', Component: Demo })
<SchemaComponentProvider components={{ Form, Action, Input, FormItem }}> }
<ActionContextProvider value={{ visible, setVisible }}> }
<a onClick={() => setVisible(true)}>Open</a>
<SchemaComponent schema={schema} /> const app = mockApp({ plugins: [DemoPlugin] });
</ActionContextProvider>
</SchemaComponentProvider> export default app.getRootComponent();
);
});

View File

@ -1,26 +1,29 @@
/** import React from 'react';
* This file is part of the NocoBase (R) project. import { ISchema, SchemaComponent, Plugin } from '@nocobase/client';
* Copyright (c) 2020-2024 NocoBase Co., Ltd. import { mockApp } from '@nocobase/client/demo-utils';
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; const schema: ISchema = {
name: 'test',
const App = getAppComponent({ type: 'void',
schema: { properties: {
type: 'void', test: {
name: 'root', type: 'void',
properties: { 'x-component': 'Action.Link',
test: { title: 'Edit',
type: 'void',
'x-component': 'Action.Link',
title: 'Edit',
},
}, },
}, },
}); }
export default App; const Demo = () => {
return <SchemaComponent schema={schema} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({ plugins: [DemoPlugin] });
export default app.getRootComponent();

View File

@ -1,16 +1,8 @@
/** import { App as AntdApp } from 'antd';
* This file is part of the NocoBase (R) project. import { useAPIClient, useActionContext, Plugin, SchemaComponent } from '@nocobase/client';
* Copyright (c) 2020-2024 NocoBase Co., Ltd. import { ISchema, useForm } from '@formily/react';
* Authors: NocoBase Team. import { mockApp } from '@nocobase/client/demo-utils';
* import React from 'react';
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web';
import { Space, App as AntdApp } from 'antd';
import { useAPIClient, useActionContext } from '@nocobase/client';
import { useForm } from '@formily/react';
const useCloseActionProps = () => { const useCloseActionProps = () => {
const { setVisible } = useActionContext(); const { setVisible } = useActionContext();
@ -46,67 +38,68 @@ const useSubmitActionProps = () => {
}; };
}; };
const App = getAppComponent({ const schema: ISchema = {
schema: { name: 'test',
type: 'void', type: 'void',
name: 'root', 'x-component': 'Action',
'x-component': Space, title: 'Open Modal',
properties: { 'x-component-props': {
test: { openSize: 'small',
type: 'void', },
'x-component': 'Action', properties: {
title: 'Open Modal', drawer: {
'x-component-props': { type: 'void',
openSize: 'small', 'x-component': 'Action.Modal',
title: 'Modal Title',
'x-decorator': 'FormV2',
properties: {
username: {
type: 'string',
title: `Username`,
required: true,
'x-decorator': 'FormItem',
'x-component': 'Input',
}, },
properties: { footer: {
drawer: { type: 'void',
type: 'void', 'x-component': 'Action.Modal.Footer',
'x-component': 'Action.Modal', properties: {
title: 'Modal Title', close: {
'x-decorator': 'FormV2', title: 'Close',
properties: { 'x-component': 'Action',
username: { 'x-component-props': {
type: 'string', type: 'default',
title: `Username`,
required: true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
footer: {
type: 'void',
'x-component': 'Action.Modal.Footer',
properties: {
close: {
title: 'Close',
'x-component': 'Action',
'x-component-props': {
type: 'default',
},
'x-use-component-props': 'useCloseActionProps',
},
submit: {
title: 'Submit',
'x-component': 'Action',
'x-use-component-props': 'useSubmitActionProps',
},
},
}, },
'x-use-component-props': 'useCloseActionProps',
},
submit: {
title: 'Submit',
'x-component': 'Action',
'x-use-component-props': 'useSubmitActionProps',
}, },
}, },
}, },
}, },
}, },
}, },
appOptions: { }
scopes: {
useSubmitActionProps, const Demo = () => {
useCloseActionProps, return <SchemaComponent schema={schema} scope={{ useSubmitActionProps, useCloseActionProps }} />;
}, };
},
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
plugins: [DemoPlugin],
apis: { apis: {
test: { data: 'ok' }, test: { data: 'ok' },
}, },
}); });
export default App; export default app.getRootComponent();

View File

@ -1,42 +1,41 @@
/** import React from "react";
* This file is part of the NocoBase (R) project. import { ISchema, SchemaComponent, Plugin } from "@nocobase/client";
* Copyright (c) 2020-2024 NocoBase Co., Ltd. import { mockApp } from "@nocobase/client/demo-utils";
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; const schema: ISchema = {
name: 'test',
const App = getAppComponent({ 'x-component': 'Action',
schema: { 'x-component-props': {
type: 'void', type: 'primary',
name: 'root', popover: true,
properties: { },
test: { type: 'void',
'x-component': 'Action', title: 'Open',
'x-component-props': { properties: {
type: 'primary', popover: {
popover: true, type: 'void',
}, 'x-component': 'Action.Popover',
type: 'void', properties: {
title: 'Open', hello: {
properties: { type: 'void',
popover: { 'x-content': 'Hello',
type: 'void',
'x-component': 'Action.Popover',
properties: {
hello: {
type: 'void',
'x-content': 'Hello',
},
},
},
}, },
}, },
}, },
}, },
}); }
export default App;
const Demo = () => {
return <SchemaComponent schema={schema} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({ plugins: [DemoPlugin] });
export default app.getRootComponent();

View File

@ -1,14 +1,6 @@
/** import { ISchema, SchemaComponent, SchemaInitializer, Plugin } from '@nocobase/client';
* This file is part of the NocoBase (R) project. import { mockApp } from '@nocobase/client/demo-utils';
* Copyright (c) 2020-2024 NocoBase Co., Ltd. import React from 'react';
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { ActionInitializer, SchemaInitializer } from '@nocobase/client';
import { getAppComponent } from '@nocobase/test/web';
const addActionButton = new SchemaInitializer({ const addActionButton = new SchemaInitializer({
name: 'addActionButton', name: 'addActionButton',
@ -48,39 +40,43 @@ const addActionButton = new SchemaInitializer({
], ],
}); });
const App = getAppComponent({ const schema: ISchema = {
schema: { name: 'test',
type: 'void', type: 'void',
name: 'root', 'x-component': 'ActionBar',
properties: { 'x-initializer': 'addActionButton',
test: { 'x-component-props': {
type: 'void', layout: 'one-column',
'x-component': 'ActionBar', },
'x-initializer': 'addActionButton', properties: {
'x-component-props': { a1: {
layout: 'one-column', title: 'Action 1',
}, 'x-component': 'Action',
properties: { 'x-action': 'a1',
a1: { },
title: 'Action 1', a2: {
'x-component': 'Action', title: 'Action 2',
'x-action': 'a1', 'x-component': 'Action',
}, 'x-action': 'a2',
a2: {
title: 'Action 2',
'x-component': 'Action',
'x-action': 'a2',
},
},
},
},
},
appOptions: {
schemaInitializers: [addActionButton],
components: {
ActionInitializer,
}, },
}, },
}
const Demo = () => {
return <SchemaComponent schema={schema} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.schemaInitializerManager.add(addActionButton)
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
designable: true,
plugins: [DemoPlugin]
}); });
export default App; export default app.getRootComponent();

View File

@ -1,14 +1,6 @@
/** import { ISchema, Plugin, SchemaComponent, SchemaInitializer } from '@nocobase/client';
* This file is part of the NocoBase (R) project. import { mockApp } from '@nocobase/client/demo-utils';
* Copyright (c) 2020-2024 NocoBase Co., Ltd. import React from 'react';
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { ActionInitializer, SchemaInitializer } from '@nocobase/client';
import { getAppComponent } from '@nocobase/test/web';
const addActionButton = new SchemaInitializer({ const addActionButton = new SchemaInitializer({
name: 'addActionButton', name: 'addActionButton',
@ -50,41 +42,45 @@ const addActionButton = new SchemaInitializer({
], ],
}); });
const App = getAppComponent({ const schema: ISchema = {
schema: { type: 'void',
type: 'void', name: 'test',
name: 'root', 'x-component': 'ActionBar',
properties: { 'x-initializer': 'addActionButton',
test: { 'x-component-props': {
type: 'void', layout: 'two-columns',
'x-component': 'ActionBar', },
'x-initializer': 'addActionButton', properties: {
'x-component-props': { a1: {
layout: 'two-columns', title: 'Action 1',
}, 'x-component': 'Action',
properties: { 'x-action': 'a1',
a1: { 'x-align': 'left',
title: 'Action 1', },
'x-component': 'Action', a2: {
'x-action': 'a1', title: 'Action 2',
'x-align': 'left', 'x-component': 'Action',
}, 'x-action': 'a2',
a2: { 'x-align': 'right',
title: 'Action 2',
'x-component': 'Action',
'x-action': 'a2',
'x-align': 'right',
},
},
},
},
},
appOptions: {
schemaInitializers: [addActionButton],
components: {
ActionInitializer,
}, },
}, },
}
const Demo = () => {
return <SchemaComponent schema={schema} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.schemaInitializerManager.add(addActionButton)
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
designable: true,
plugins: [DemoPlugin]
}); });
export default App; export default app.getRootComponent();

View File

@ -1,32 +1,30 @@
/** import { mockApp } from '@nocobase/client/demo-utils';
* This file is part of the NocoBase (R) project. import React from 'react';
* Copyright (c) 2020-2024 NocoBase Co., Ltd. import { SchemaComponent, Plugin, ISchema } from '@nocobase/client';
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; const schema: ISchema = {
type: 'void',
const App = getAppComponent({ name: 'test',
schema: { 'x-component': 'Action',
type: 'void', 'x-component-props': {
name: 'root', ghost: true, // ButtonProps
properties: { type: 'dashed', // ButtonProps
test: { danger: true, // ButtonProps
type: 'void', title: 'Open', // title
'x-component': 'Action',
'x-component-props': {
ghost: true, // ButtonProps
type: 'dashed', // ButtonProps
danger: true, // ButtonProps
title: 'Open', // title
},
// title: 'Open', // It's also possible here
},
},
}, },
}); // title: 'Open', // It's also possible here
}
export default App; const Demo = () => {
return <SchemaComponent schema={schema} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({ plugins: [DemoPlugin] });
export default app.getRootComponent();

View File

@ -1,44 +1,42 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; import { App as AntdApp } from 'antd';
import { Space, App as AntdApp } from 'antd'; import { ActionProps, ISchema, SchemaComponent, Plugin } from '@nocobase/client';
import { ActionProps } from '@nocobase/client'; import { mockApp } from '@nocobase/client/demo-utils';
import React from 'react';
const App = getAppComponent({ function useActionProps(): ActionProps {
schema: { const { message } = AntdApp.useApp();
type: 'void',
name: 'root',
'x-component': Space,
properties: {
test: {
type: 'void',
'x-component': 'Action',
title: 'Delete',
'x-use-component-props': function useActionProps(): ActionProps {
const { message } = AntdApp.useApp();
return { return {
confirm: { confirm: {
// confirm props // confirm props
title: 'Delete', title: 'Delete',
content: 'Are you sure you want to delete it?', content: 'Are you sure you want to delete it?',
},
onClick() {
// after confirm ok
message.success('Deleted!');
},
};
},
},
}, },
}, onClick() {
}); // after confirm ok
message.success('Deleted!');
},
};
}
const schema: ISchema = {
type: 'void',
name: 'test',
'x-component': 'Action',
title: 'Delete',
'x-use-component-props': 'useActionProps',
}
export default App; const Demo = () => {
return <SchemaComponent schema={schema} scope={{ useActionProps }} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({ plugins: [DemoPlugin] });
export default app.getRootComponent();

View File

@ -1,47 +1,45 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; import { SchemaComponent, Plugin, ISchema } from '@nocobase/client';
import { Button, Space } from 'antd'; import { mockApp } from '@nocobase/client/demo-utils';
import { Button } from 'antd';
import React from 'react'; import React from 'react';
const ComponentButton = (props) => { const ComponentButton = (props) => {
return <Button {...props}>Custom Component</Button>; return <Button {...props}>Custom Component</Button>;
}; };
const App = getAppComponent({ const schema: ISchema = {
schema: { type: 'void',
type: 'void', name: 'test',
name: 'root', 'x-component': 'Space',
'x-component': Space, properties: {
properties: { test1: {
test1: { type: 'void',
type: 'void', 'x-component': 'Action',
'x-component': 'Action', 'x-component-props': {
'x-component-props': { component: 'ComponentButton', // string type
component: 'ComponentButton', // string type
},
}, },
test2: { },
type: 'void', test2: {
'x-component': 'Action', type: 'void',
'x-component-props': { 'x-component': 'Action',
component: ComponentButton, // ComponentType type 'x-component-props': {
}, component: ComponentButton, // ComponentType type
}, },
}, },
}, },
appOptions: { }
components: {
ComponentButton, // register custom component
},
},
});
export default App; const Demo = () => {
return <SchemaComponent schema={schema} components={{ ComponentButton }} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({ plugins: [DemoPlugin] });
export default app.getRootComponent();

View File

@ -1,35 +1,32 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; import { SchemaComponent, Plugin, ISchema } from '@nocobase/client';
import { Space } from 'antd'; import { mockApp } from '@nocobase/client/demo-utils';
import React from 'react';
const App = getAppComponent({ const schema: ISchema = {
schema: { name: 'test',
type: 'void', type: 'void',
name: 'root', 'x-component': 'Action',
'x-component': Space, title: 'Open Drawer',
properties: { properties: {
test: { drawer: {
type: 'void', type: 'void',
'x-component': 'Action', 'x-component': 'Action.Drawer',
title: 'Open Drawer', title: 'Drawer Title',
properties: {
drawer: {
type: 'void',
'x-component': 'Action.Drawer',
title: 'Drawer Title',
},
},
},
}, },
}, },
}); }
export default App; const Demo = () => {
return <SchemaComponent schema={schema} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({ plugins: [DemoPlugin] });
export default app.getRootComponent();

View File

@ -1,15 +1,8 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; import { ISchema, useActionContext } from '@nocobase/client';
import { Space } from 'antd'; import { SchemaComponent, Plugin } from '@nocobase/client';
import { useActionContext } from '@nocobase/client'; import { mockApp } from '@nocobase/client/demo-utils';
import React from 'react';
const useCloseActionProps = () => { const useCloseActionProps = () => {
const { setVisible } = useActionContext(); const { setVisible } = useActionContext();
@ -32,57 +25,57 @@ const useSubmitActionProps = () => {
}; };
}; };
const App = getAppComponent({ const schema: ISchema = {
schema: { name: 'test',
type: 'void', type: 'void',
name: 'root', 'x-component': 'Action',
'x-component': Space, title: 'Open Drawer',
properties: { properties: {
test: { drawer: {
type: 'void', type: 'void',
'x-component': 'Action', 'x-component': 'Action.Drawer',
title: 'Open Drawer', title: 'Drawer Title',
properties: { properties: {
drawer: { content: {
type: 'void', type: 'void',
'x-component': 'Action.Drawer', 'x-content': 'Hello',
title: 'Drawer Title', },
properties: { footer: {
content: { type: 'void',
type: 'void', 'x-component': 'Action.Drawer.Footer', // must be `Action.Drawer.Footer`
'x-content': 'Hello', properties: {
}, close: {
footer: { title: 'Close',
type: 'void', 'x-component': 'Action',
'x-component': 'Action.Drawer.Footer', // must be `Action.Drawer.Footer` 'x-use-component-props': 'useCloseActionProps',
properties: { },
close: { submit: {
title: 'Close', title: 'Submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useCloseActionProps', 'x-use-component-props': 'useSubmitActionProps',
},
submit: {
title: 'Submit',
'x-component': 'Action',
'x-use-component-props': 'useSubmitActionProps',
},
},
},
}, },
}, },
}, },
}, },
}, },
}, },
appOptions: { };
scopes: {
useCloseActionProps, const Demo = () => {
useSubmitActionProps, return <SchemaComponent schema={schema} scope={{ useCloseActionProps, useSubmitActionProps }} />;
}, };
},
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
plugins: [DemoPlugin],
apis: { apis: {
test: { data: 'ok' }, test: { data: 'ok' },
}, }
}); });
export default App; export default app.getRootComponent();

View File

@ -1,45 +1,44 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; import { SchemaComponent, Plugin, ISchema } from '@nocobase/client';
import { Space } from 'antd'; import { mockApp } from '@nocobase/client/demo-utils';
import React from 'react';
const App = getAppComponent({ const schema: ISchema = {
schema: { name: 'test',
type: 'void', type: 'void',
name: 'root', 'x-component': 'Action',
'x-component': Space, title: 'Open Drawer',
properties: { 'x-component-props': {
test: { openSize: 'large', // open drawer size
type: 'void', },
'x-component': 'Action', properties: {
title: 'Open Drawer', drawer: {
'x-component-props': { type: 'void',
openSize: 'large', // open drawer size title: 'Drawer Title',
}, 'x-component': 'Action.Drawer',
properties: { properties: {
drawer: { // Drawer content
type: 'void', hello: {
title: 'Drawer Title', type: 'void',
'x-component': 'Action.Drawer', 'x-content': 'Hello',
properties: {
// Drawer content
hello: {
type: 'void',
'x-content': 'Hello',
},
},
},
}, },
}, },
}, },
}, },
};
const Demo = () => {
return <SchemaComponent schema={schema} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
plugins: [DemoPlugin],
}); });
export default App; export default app.getRootComponent();

View File

@ -1,16 +1,9 @@
/** import { App as AntdApp } from 'antd';
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web';
import { Space, App as AntdApp } from 'antd';
import { useAPIClient, useActionContext } from '@nocobase/client'; import { useAPIClient, useActionContext } from '@nocobase/client';
import { useForm } from '@formily/react'; import { useForm } from '@formily/react';
import { SchemaComponent, Plugin } from '@nocobase/client';
import { mockApp } from '@nocobase/client/demo-utils';
import React from 'react';
const useCloseActionProps = () => { const useCloseActionProps = () => {
const { setVisible } = useActionContext(); const { setVisible } = useActionContext();
@ -46,65 +39,65 @@ const useSubmitActionProps = () => {
}; };
}; };
const App = getAppComponent({ const schema: ISchema = {
schema: { name: 'test',
type: 'void', type: 'void',
name: 'root', 'x-component': 'Action',
'x-component': Space, title: 'Open Drawer',
properties: { properties: {
test: { drawer: {
type: 'void', type: 'void',
'x-component': 'Action', 'x-component': 'Action.Drawer',
title: 'Open Drawer', title: 'Drawer Title',
properties: { 'x-decorator': 'FormV2', // This uses the `FormV2` component.
drawer: { properties: {
type: 'void', username: {
'x-component': 'Action.Drawer', // This is a form field.
title: 'Drawer Title', type: 'string',
'x-decorator': 'FormV2', // This uses the `FormV2` component. title: `Username`,
properties: { required: true,
username: { 'x-decorator': 'FormItem',
// This is a form field. 'x-component': 'Input',
type: 'string', },
title: `Username`, footer: {
required: true, type: 'void',
'x-decorator': 'FormItem', 'x-component': 'Action.Drawer.Footer',
'x-component': 'Input', properties: {
}, close: {
footer: { title: 'Close',
type: 'void', 'x-component': 'Action',
'x-component': 'Action.Drawer.Footer', 'x-component-props': {
properties: { type: 'default',
close: {
title: 'Close',
'x-component': 'Action',
'x-component-props': {
type: 'default',
},
'x-use-component-props': 'useCloseActionProps',
},
submit: {
title: 'Submit',
'x-component': 'Action',
'x-use-component-props': 'useSubmitActionProps',
},
},
}, },
'x-use-component-props': 'useCloseActionProps',
},
submit: {
title: 'Submit',
'x-component': 'Action',
'x-use-component-props': 'useSubmitActionProps',
}, },
}, },
}, },
}, },
}, },
}, },
appOptions: { };
scopes: {
useSubmitActionProps, const Demo = () => {
useCloseActionProps, return <SchemaComponent schema={schema} scope={{ useCloseActionProps, useSubmitActionProps }} />;
}, };
},
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
plugins: [DemoPlugin],
apis: { apis: {
test: { data: 'ok' }, test: { data: 'ok' },
}, }
}); });
export default App; export default app.getRootComponent();

View File

@ -1,15 +1,9 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; import { App as AntdApp } from 'antd';
import { Space, App as AntdApp } from 'antd'; import { ISchema, useAPIClient } from '@nocobase/client';
import { useAPIClient, ActionProps } from '@nocobase/client'; import { SchemaComponent, Plugin, ActionProps } from '@nocobase/client';
import { mockApp } from '@nocobase/client/demo-utils';
import React from 'react';
const useCustomActionProps = (): ActionProps => { const useCustomActionProps = (): ActionProps => {
const api = useAPIClient(); const api = useAPIClient();
@ -25,53 +19,60 @@ const useCustomActionProps = (): ActionProps => {
}; };
}; };
const App = getAppComponent({ const schema: ISchema = {
schema: { type: 'void',
type: 'void', name: 'root',
name: 'root', 'x-component': 'Space',
'x-component': Space, properties: {
properties: { test0: {
test1: { type: 'void',
type: 'void', 'x-component': 'Action',
'x-component': 'Action', title: 'test2',
title: 'test1', 'x-use-component-props': 'useCustomActionProps', // string type
'x-use-component-props': useCustomActionProps, // function type },
}, test1: {
test2: { type: 'void',
type: 'void', 'x-component': 'Action',
'x-component': 'Action', title: 'test1',
title: 'test2', 'x-use-component-props': useCustomActionProps, // function type
'x-use-component-props': function useCustomActionProps(): ActionProps { },
// inline function type test2: {
const api = useAPIClient(); type: 'void',
const { message } = AntdApp.useApp(); 'x-component': 'Action',
title: 'test2',
'x-use-component-props': function useCustomActionProps(): ActionProps {
// inline function type
const api = useAPIClient();
const { message } = AntdApp.useApp();
return { return {
onClick: async () => { onClick: async () => {
const { data } = await api.request({ url: 'test' }); const { data } = await api.request({ url: 'test' });
if (data.data.result === 'ok') { if (data.data.result === 'ok') {
message.success('Success!'); message.success('Success!');
} }
}, },
}; };
},
},
test3: {
type: 'void',
'x-component': 'Action',
title: 'test2',
'x-use-component-props': 'useCustomActionProps', // string type
}, },
}, },
}, },
appOptions: { };
scopes: {
useCustomActionProps, const Demo = () => {
}, return <SchemaComponent schema={schema} scope={{ useCustomActionProps }} />;
}, };
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
plugins: [DemoPlugin],
apis: { apis: {
test: { data: { result: 'ok' } }, test: { data: { result: 'ok' } },
}, }
}); });
export default App; export default app.getRootComponent();

View File

@ -1,14 +1,5 @@
/** import { SchemaComponent, Plugin, SchemaSettings } from '@nocobase/client';
* This file is part of the NocoBase (R) project. import { mockApp } from '@nocobase/client/demo-utils';
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { SchemaSettings } from '@nocobase/client';
import { getAppComponent } from '@nocobase/test/web';
import React from 'react'; import React from 'react';
const myActionSettings = new SchemaSettings({ const myActionSettings = new SchemaSettings({
@ -23,65 +14,77 @@ const myActionSettings = new SchemaSettings({
const MyToolbar = (props) => <span>{props.title}</span>; const MyToolbar = (props) => <span>{props.title}</span>;
const App = getAppComponent({ const schema = {
schema: { type: 'void',
type: 'void', name: 'root',
name: 'root', properties: {
properties: { test: {
test: { type: 'void',
type: 'void', 'x-component': 'ActionBar',
'x-component': 'ActionBar', 'x-component-props': {
'x-component-props': { layout: 'two-columns',
layout: 'two-columns', },
properties: {
a1: {
title: 'Action 1',
'x-component': 'Action',
'x-action': 'a1',
'x-align': 'right',
'x-settings': 'myActionSettings',
}, },
properties: { a2: {
a1: { title: 'Action 2',
title: 'Action 1', 'x-component': 'Action',
'x-component': 'Action', 'x-action': 'a2',
'x-action': 'a1', 'x-align': 'right',
'x-align': 'right', 'x-settings': 'myActionSettings',
'x-settings': 'myActionSettings', },
}, a3: {
a2: { title: 'Action 3',
title: 'Action 2', 'x-component': 'Action',
'x-component': 'Action', 'x-action': 'a1',
'x-action': 'a2', 'x-align': 'left',
'x-align': 'right', 'x-settings': 'myActionSettings',
'x-settings': 'myActionSettings', },
}, a4: {
a3: { title: 'Action 4',
title: 'Action 3', 'x-component': 'Action',
'x-component': 'Action', 'x-action': 'a2',
'x-action': 'a1', 'x-align': 'left',
'x-align': 'left', 'x-settings': 'myActionSettings',
'x-settings': 'myActionSettings', },
}, a5: {
a4: { title: '',
title: 'Action 4', 'x-component': 'Action',
'x-component': 'Action', 'x-action': 'a5',
'x-action': 'a2', 'x-align': 'left',
'x-align': 'left', 'x-toolbar': 'MyToolbar',
'x-settings': 'myActionSettings', 'x-toolbar-props': {
}, title: 'MyTitle',
a5: {
title: '',
'x-component': 'Action',
'x-action': 'a5',
'x-align': 'left',
'x-toolbar': 'MyToolbar',
'x-toolbar-props': {
title: 'MyTitle',
},
}, },
}, },
}, },
}, },
}, },
appOptions: { };
schemaSettings: [myActionSettings],
components: { MyToolbar }, const Demo = () => {
}, return <SchemaComponent schema={schema} components={{ MyToolbar }} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo });
}
}
const app = mockApp({
plugins: [DemoPlugin],
designable: true, designable: true,
schemaSettings: [myActionSettings],
apis: {
test: { data: { result: 'ok' } },
},
}); });
export default App; export default app.getRootComponent();

View File

@ -0,0 +1,206 @@
# Action
Combines buttons and various operations together, providing a unified way to handle actions.
## Action
The trigger for the action, by default using the `Button` component from ant-design, and provides context for subsequent pop-ups or drawers.
```ts
export interface ActionProps extends ButtonProps {
/**
* button title
*/
title?: string;
/**
* custom component, replace the default Button component
*/
component?: string | ComponentType<any>;
/**
* Dynamic rendering of the opened content in conjunction with `Action.Container`.
*/
openMode?: 'drawer' | 'modal' | 'page';
/**
* The size of the pop-up window, only valid when `openMode: 'modal'`
*/
openSize?: 'small' | 'middle' | 'large';
/**
* Customize the position of the pop-up window
*/
containerRefKey?: string;
/**
* Whether to display the popover, only valid when `openMode: 'popover'`
*/
popover?: boolean;
/**
* When the button is clicked, whether a pop-up confirmation is required
*/
confirm?: false | {
title: string;
content: string;
};
}
```
### Basic Usage
- `ButtonProp`
- title
<code src="./demos/new-demos/basic.tsx"></code>
### Custom Component
- component
<code src="./demos/new-demos/custom-component.tsx"></code>
### Dynamic Props
Here, the ability of `x-use-component-props` is used. For more information, please refer to [x-use-component-props](https://docs.nocobase.com/development/client/ui-schema/what-is-ui-schema#x-component-props-and-x-use-component-props).
<code src="./demos/new-demos/dynamic-props.tsx"></code>
### Confirm
- confirm
<code src="./demos/new-demos/confirm.tsx"></code>
## Action.Link
Replace the `Button` component with an `a` tag.
<code src="./demos/new-demos/action-link.tsx"></code>
## Action.Drawer
Used to pop up a drawer on the right side.
```ts
interface ActionDrawer extends DrawerProps {}
```
### Basic Usage
- `DrawerProps`
<code src="./demos/new-demos/drawer-basic.tsx"></code>
### openSize
<code src="./demos/new-demos/drawer-openSize.tsx"></code>
### Footer
The Footer can contain buttons such as Cancel or Submit.
Its Schema `x-component` must be set to the `Action.Drawer.Footer` component.
<code src="./demos/new-demos/drawer-footer.tsx"></code>
### With Form
<code src="./demos/new-demos/drawer-with-form.tsx"></code>
## Action.Modal
```ts
interface ActionModal extends ModalProps {}
```
Its usage is similar to `Action.Drawer`, here is just one example.
<code src="./demos/new-demos/action-modal.tsx"></code>
## Action.Popover
Note that the `popover` property of Action must be set to `true`.
<code src="./demos/new-demos/action-popover.tsx"></code>
## Action.Container
When rendering content dynamically as needed, you can use `Action.Container` + Action `openMode` property to make dynamic decisions.
<code src="./demos/new-demos/action-container.tsx"></code>
## ActionBar
Generally used for the top operation buttons of a section, it automatically handles layout and rendering of [schema-initializer](/core/ui-schema/schema-initializer).
```ts
import { SpaceProps } from 'antd'
interface ActionBarProps {
layout?: 'one-column' | 'two-columns';
style?: CSSProperties;
className?: string;
spaceProps?: SpaceProps;
}
```
### one-column
One-column layout, aligned to the left.
The `x-action` in the Schema is the unique identifier for the button, which should not be duplicated with existing ones. It is used for searching and deleting in `ActionInitializer`.
<code src="./demos/new-demos/actionbar-one-column.tsx"></code>
### two-columns
Two-column layout, controlled by `x-align`.
<code src="./demos/new-demos/actionbar-two-columns.tsx"></code>
## ActionContext
Encapsulated inside the `Action` component, used for passing context.
```ts
export type OpenSize = 'small' | 'middle' | 'large';
export interface ActionContextProps {
button?: React.JSX.Element;
visible?: boolean;
setVisible?: (v: boolean) => void;
openMode?: 'drawer' | 'modal' | 'page';
snapshot?: boolean;
openSize?: OpenSize;
/**
* Customize the position of the pop-up window
*/
containerRefKey?: string;
formValueChanged?: boolean;
setFormValueChanged?: (v: boolean) => void;
fieldSchema?: Schema;
drawerProps?: DrawerProps;
modalProps?: ModalProps;
submitted?: boolean;
setSubmitted?: (v: boolean) => void;
}
```
Assuming that the Action component cannot meet the requirements, we can directly use the ActionContext component for customization.
<code src="./demos/new-demos/action-context.tsx"></code>
## ActionSchemaToolbar
Used to render a single button with [SchemaToolbar](/core/ui-schema/schema-toolbar) and [SchemaSettings](/core/ui-schema/schema-settings).
<code src="./demos/new-demos/schema-toolbar.tsx"></code>
## Hooks
### useActionContext()
Get the `ActionContext` context.
```ts
const { visible, setVisible, fieldSchema } = useActionContext();
```

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { APIClientProvider, AssociationSelect, FormProvider, SchemaComponent } from '@nocobase/client'; import { APIClientProvider, AssociationSelect, FormProvider, SchemaComponent } from '@nocobase/client';
import React from 'react'; import React from 'react';

View File

@ -1,40 +1,45 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; import { mockApp } from '@nocobase/client/demo-utils';
import React from 'react';
import { SchemaComponent, Plugin, ISchema } from '@nocobase/client';
const App = getAppComponent({ const schema: ISchema = {
schema: { type: 'void',
type: 'void', name: 'root',
name: 'root', 'x-decorator': 'FormV2',
'x-decorator': 'FormV2', 'x-component': 'ShowFormData',
'x-component': 'ShowFormData', properties: {
properties: { test: {
test: { type: 'string',
type: 'string', title: 'Test',
title: 'Test', 'x-decorator': 'FormItem',
'x-decorator': 'FormItem', 'x-component': 'AssociationSelect',
'x-component': 'AssociationSelect', 'x-component-props': {
'x-component-props': { service: {
service: { resource: 'roles', // roles 表
resource: 'roles', // roles 表 action: 'list', // 列表接口
action: 'list', // 列表接口 },
}, fieldNames: {
fieldNames: { label: 'title', // 显示的字段
label: 'title', // 显示的字段 value: 'name', // 值字段
value: 'name', // 值字段
},
}, },
}, },
}, },
}, },
delayResponse: 500, };
const Demo = () => {
return <SchemaComponent schema={schema} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
plugins: [DemoPlugin],
}); });
export default App; export default app.getRootComponent();

View File

@ -1,41 +1,46 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; import { mockApp } from '@nocobase/client/demo-utils';
import React from 'react';
import { SchemaComponent, Plugin, ISchema } from '@nocobase/client';
const App = getAppComponent({ const schema: ISchema = {
schema: { type: 'void',
type: 'void', name: 'root',
name: 'root', 'x-decorator': 'FormV2',
'x-decorator': 'FormV2', 'x-component': 'ShowFormData',
'x-component': 'ShowFormData', properties: {
properties: { test: {
test: { type: 'array', // 数组类型
type: 'array', // 数组类型 title: 'Test',
title: 'Test', 'x-decorator': 'FormItem',
'x-decorator': 'FormItem', 'x-component': 'AssociationSelect',
'x-component': 'AssociationSelect', 'x-component-props': {
'x-component-props': { multiple: true, // 多选
multiple: true, // 多选 service: {
service: { resource: 'roles',
resource: 'roles', action: 'list',
action: 'list', },
}, fieldNames: {
fieldNames: { label: 'title',
label: 'title', value: 'name',
value: 'name',
},
}, },
}, },
}, },
}, },
delayResponse: 500, };
const Demo = () => {
return <SchemaComponent schema={schema} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
plugins: [DemoPlugin],
}); });
export default App; export default app.getRootComponent();

View File

@ -1,42 +1,47 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; import { mockApp } from '@nocobase/client/demo-utils';
import React from 'react';
import { SchemaComponent, Plugin, ISchema } from '@nocobase/client';
const App = getAppComponent({ const schema: ISchema = {
schema: { type: 'void',
type: 'void', name: 'root',
name: 'root', 'x-decorator': 'FormV2',
'x-decorator': 'FormV2', 'x-component': 'ShowFormData',
'x-component': 'ShowFormData', properties: {
properties: { test: {
test: { type: 'string',
type: 'string', title: 'Test',
title: 'Test', default: 'admin',
default: 'admin', 'x-decorator': 'FormItem',
'x-decorator': 'FormItem', 'x-component': 'AssociationSelect',
'x-component': 'AssociationSelect', 'x-pattern': 'readPretty',
'x-pattern': 'readPretty', 'x-component-props': {
'x-component-props': { service: {
service: { resource: 'roles',
resource: 'roles', action: 'list',
action: 'list', },
}, fieldNames: {
fieldNames: { label: 'title',
label: 'title', value: 'name',
value: 'name',
},
}, },
}, },
}, },
}, },
delayResponse: 500, }
const Demo = () => {
return <SchemaComponent schema={schema} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
plugins: [DemoPlugin],
}); });
export default App; export default app.getRootComponent();

View File

@ -0,0 +1,24 @@
# AssociationSelect
Retrieve data from a table by specifying the table and field.
```ts
type AssociationSelectProps<P = any> = RemoteSelectProps<P> & {
action?: string;
multiple?: boolean;
};
```
## Basic Usage
<code src="./demos/new-demos/basic.tsx"></code>
## Multiple Selection
`type` needs to be changed to `array`, and the property needs to be added `multiple: true`.
<code src="./demos/new-demos/multiple.tsx"></code>
## Read Pretty
<code src="./demos/new-demos/read-pretty.tsx"></code>

View File

@ -1,14 +1,10 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { useField } from '@formily/react'; import { useField } from '@formily/react';
import { getAppComponent } from '@nocobase/test/web'; import { mockApp } from '@nocobase/client/demo-utils';
import React from 'react';
import { SchemaComponent, Plugin } from '@nocobase/client';
const mockVal = (str: string, repeat = 1) => ({ const mockVal = (str: string, repeat = 1) => ({
value: str.repeat(repeat), value: str.repeat(repeat),
@ -26,22 +22,34 @@ function useAutoCompleteProps() {
}; };
} }
const App = getAppComponent({ const schema = {
schema: { type: 'void',
type: 'void', name: 'root',
name: 'root', 'x-decorator': 'FormV2',
'x-decorator': 'FormV2', 'x-component': 'ShowFormData',
'x-component': 'ShowFormData', properties: {
properties: { test: {
test: { type: 'boolean',
type: 'boolean', title: 'Test',
title: 'Test', 'x-decorator': 'FormItem',
'x-decorator': 'FormItem', 'x-component': 'AutoComplete',
'x-component': 'AutoComplete', 'x-use-component-props': 'useAutoCompleteProps',
'x-use-component-props': useAutoCompleteProps,
},
}, },
}, },
}
const Demo = () => {
return <SchemaComponent schema={schema} scope={{ useAutoCompleteProps }} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
plugins: [DemoPlugin],
}); });
export default App; export default app.getRootComponent();

View File

@ -1,31 +1,37 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; import { mockApp } from '@nocobase/client/demo-utils';
import React from 'react';
import { SchemaComponent, Plugin } from '@nocobase/client';
const App = getAppComponent({ const schema = {
schema: { type: 'void',
type: 'void', name: 'root',
name: 'root', 'x-decorator': 'FormV2',
'x-decorator': 'FormV2', 'x-component': 'ShowFormData',
'x-component': 'ShowFormData', 'x-pattern': 'readPretty',
'x-pattern': 'readPretty', properties: {
properties: { test: {
test: { type: 'boolean',
type: 'boolean', title: 'Test',
title: 'Test', default: 'aaa',
default: 'aaa', 'x-decorator': 'FormItem',
'x-decorator': 'FormItem', 'x-component': 'AutoComplete',
'x-component': 'AutoComplete',
},
}, },
}, },
};
const Demo = () => {
return <SchemaComponent schema={schema} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
plugins: [DemoPlugin],
}); });
export default App; export default app.getRootComponent();

View File

@ -0,0 +1,20 @@
# AutoComplete
AutoComplete input box. It is a wrapper component based on the ant-design [AutoComplete](https://ant.design/components/auto-complete) component.
## Basic Usage
```ts
type AutoCompleteProps = AntdAutoCompleteProps;
```
<code src="./demos/basic.tsx"></code>
## Read Pretty
```ts
type AutoCompleteReadPrettyProps = InputReadPrettyProps;
```
<code src="./demos/read-pretty.tsx"></code>

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { observer, useFieldSchema } from '@formily/react'; import { observer, useFieldSchema } from '@formily/react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';

View File

@ -1,17 +1,7 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web';
import { DragHandler, SchemaSettings } from '@nocobase/client';
import { useFieldSchema } from '@formily/react';
import { observer } from '@formily/reactive-react';
import React from 'react'; import React from 'react';
import { useFieldSchema, observer, ISchema } from '@formily/react';
import { mockApp } from '@nocobase/client/demo-utils';
import { SchemaComponent, Plugin, DragHandler, SchemaSettings } from '@nocobase/client';
const simpleSettings = new SchemaSettings({ const simpleSettings = new SchemaSettings({
name: 'simpleSettings', name: 'simpleSettings',
@ -39,39 +29,47 @@ const MyBlock = observer(
{ displayName: 'MyBlock' }, { displayName: 'MyBlock' },
); );
const App = getAppComponent({ const schema: ISchema = {
type: 'void',
name: 'test',
'x-component': 'DndContext',
properties: {
block1: {
type: 'void',
'x-decorator': 'BlockItem',
'x-component': 'MyBlock',
'x-settings': 'simpleSettings',
},
block2: {
type: 'void',
'x-decorator': 'BlockItem',
'x-component': 'MyBlock',
'x-settings': 'simpleSettings',
},
block3: {
type: 'void',
'x-decorator': 'BlockItem',
'x-component': 'MyBlock',
'x-settings': 'simpleSettings',
},
},
}
const Demo = () => {
return <SchemaComponent schema={schema} components={{ MyBlock }} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.schemaSettingsManager.add(simpleSettings)
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
designable: true, designable: true,
schema: { plugins: [DemoPlugin],
type: 'void', delayResponse: 500,
name: 'root',
'x-component': 'DndContext',
properties: {
block1: {
type: 'void',
'x-decorator': 'BlockItem',
'x-component': 'MyBlock',
'x-settings': 'simpleSettings',
},
block2: {
type: 'void',
'x-decorator': 'BlockItem',
'x-component': 'MyBlock',
'x-settings': 'simpleSettings',
},
block3: {
type: 'void',
'x-decorator': 'BlockItem',
'x-component': 'MyBlock',
'x-settings': 'simpleSettings',
},
},
},
appOptions: {
schemaSettings: [simpleSettings],
components: {
MyBlock,
},
},
}); });
export default App; export default app.getRootComponent();

View File

@ -0,0 +1,22 @@
# BlockItem
A regular decorator component with no UI effects, usually used in `x-decorator`.
It provides the following 2 capabilities:
- Drag and drop functionality
- Rendering of [SchemaToolbar](/core/ui-schema/schema-toolbar) and [SchemaSettings](/core/ui-schema/schema-settings)
[CardItem](/components/card-item) and [FormItem](/components/form-item) components are both implemented based on BlockItem and have the same capabilities mentioned above.
```ts
interface BlockItemProps {
name?: string;
className?: string;
children?: React.ReactNode;
}
```
Note that the drag and drop functionality requires configuring the `DndContext` component.
<code src="./demos/new-demos/basic.tsx"></code>

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { CardItem, FormProvider, SchemaComponent } from '@nocobase/client'; import { CardItem, FormProvider, SchemaComponent } from '@nocobase/client';
import React from 'react'; import React from 'react';

View File

@ -1,14 +1,7 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; import React from 'react';
import { SchemaSettings } from '@nocobase/client'; import { mockApp } from '@nocobase/client/demo-utils';
import { SchemaComponent, Plugin, SchemaSettings, ISchema } from '@nocobase/client';
const simpleSettings = new SchemaSettings({ const simpleSettings = new SchemaSettings({
name: 'simpleSettings', name: 'simpleSettings',
@ -20,48 +13,59 @@ const simpleSettings = new SchemaSettings({
], ],
}); });
const App = getAppComponent({ const schema: ISchema = {
designable: true, type: 'void',
schema: { name: 'root',
type: 'void', 'x-component': 'DndContext',
name: 'root', properties: {
'x-component': 'DndContext', block1: {
properties: { type: 'void',
block1: { 'x-component': 'CardItem',
type: 'void', 'x-component-props': {
'x-component': 'CardItem', title: 'Block 1',
'x-component-props': { },
title: 'Block 1', 'x-settings': 'simpleSettings',
}, properties: {
'x-settings': 'simpleSettings', hello: {
properties: { type: 'void',
hello: { 'x-component': 'div',
type: 'void', 'x-content': 'Hello Card!',
'x-component': 'div',
'x-content': 'Hello Card!',
},
}, },
}, },
block2: { },
type: 'void', block2: {
'x-component': 'CardItem', type: 'void',
'x-settings': 'simpleSettings', 'x-component': 'CardItem',
'x-component-props': { 'x-settings': 'simpleSettings',
title: 'Block 2', 'x-component-props': {
}, title: 'Block 2',
properties: { },
hello: { properties: {
type: 'void', hello: {
'x-component': 'div', type: 'void',
'x-content': 'Hello Card!', 'x-component': 'div',
}, 'x-content': 'Hello Card!',
}, },
}, },
}, },
}, },
appOptions: { };
schemaSettings: [simpleSettings],
}, const Demo = () => {
return <SchemaComponent schema={schema} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.schemaSettingsManager.add(simpleSettings)
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
designable: true,
plugins: [DemoPlugin],
delayResponse: 500,
}); });
export default App; export default app.getRootComponent();

View File

@ -1,14 +1,7 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { getAppComponent } from '@nocobase/test/web'; import React from 'react';
import { SchemaSettings } from '@nocobase/client'; import { mockApp } from '@nocobase/client/demo-utils';
import { SchemaComponent, Plugin, SchemaSettings, ISchema } from '@nocobase/client';
const simpleSettings = new SchemaSettings({ const simpleSettings = new SchemaSettings({
name: 'simpleSettings', name: 'simpleSettings',
@ -20,74 +13,85 @@ const simpleSettings = new SchemaSettings({
], ],
}); });
const App = getAppComponent({ const schema: ISchema = {
type: 'void',
name: 'root',
'x-decorator': 'DndContext',
'x-component': 'div',
'x-component-props': {
style: {
height: 300,
overflow: 'auto',
border: '1px solid #f0f0f0',
},
},
properties: {
block1: {
type: 'void',
'x-component': 'CardItem',
'x-component-props': {
title: 'Block 1',
},
'x-settings': 'simpleSettings',
properties: {
hello: {
type: 'void',
'x-component': 'div',
'x-content': 'Hello Card!',
},
},
},
block2: {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'simpleSettings',
'x-component-props': {
title: 'Block 2',
},
properties: {
hello: {
type: 'void',
'x-component': 'div',
'x-content': 'Hello Card!',
},
},
},
block3: {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'simpleSettings',
'x-component-props': {
title: 'Block 3',
lazyRender: {
threshold: 1,
},
},
properties: {
hello: {
type: 'void',
'x-component': 'div',
'x-content': 'Hello Card!',
},
},
},
},
};
const Demo = () => {
return <SchemaComponent schema={schema} />;
};
class DemoPlugin extends Plugin {
async load() {
this.app.schemaSettingsManager.add(simpleSettings)
this.app.router.add('root', { path: '/', Component: Demo })
}
}
const app = mockApp({
designable: true, designable: true,
schema: { plugins: [DemoPlugin],
type: 'void', delayResponse: 500,
name: 'root',
'x-decorator': 'DndContext',
'x-component': 'div',
'x-component-props': {
style: {
height: 300,
overflow: 'auto',
border: '1px solid #f0f0f0',
},
},
properties: {
block1: {
type: 'void',
'x-component': 'CardItem',
'x-component-props': {
title: 'Block 1',
},
'x-settings': 'simpleSettings',
properties: {
hello: {
type: 'void',
'x-component': 'div',
'x-content': 'Hello Card!',
},
},
},
block2: {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'simpleSettings',
'x-component-props': {
title: 'Block 2',
},
properties: {
hello: {
type: 'void',
'x-component': 'div',
'x-content': 'Hello Card!',
},
},
},
block3: {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'simpleSettings',
'x-component-props': {
title: 'Block 3',
lazyRender: {
threshold: 1,
},
},
properties: {
hello: {
type: 'void',
'x-component': 'div',
'x-content': 'Hello Card!',
},
},
},
},
},
appOptions: {
schemaSettings: [simpleSettings],
},
}); });
export default App; export default app.getRootComponent();

View File

@ -0,0 +1,27 @@
# CardItem
Card decorator. Its main functions are:
- Drag and render [SchemaToolbar](/core/ui-schema/schema-toolbar) and [SchemaSettings](/core/ui-schema/schema-settings), inherited from [BlockItem](/components/block-item)
- Lazy rendering
It is based on the ant-design [Card](https://ant.design/components/card-cn/) component, and lazy loading is implemented using [react-intersection-observer](https://github.com/thebuilder/react-intersection-observer).
```ts
interface CardItemProps extends CardProps {
name?: string;
/**
* lazy render options
* @see https://github.com/thebuilder/react-intersection-observer
*/
lazyRender?: IntersectionOptions;
}
```
## Basic
<code src="./demos/new-demos/basic.tsx" ></code>
## Custom lazy render
<code src="./demos/new-demos/lazy-render.tsx" ></code>

View File

@ -1,11 +1,4 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { FormItem } from '@formily/antd-v5'; import { FormItem } from '@formily/antd-v5';
import { Cascader, SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; import { Cascader, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';

Some files were not shown because too many files have changed in this diff Show More