fix: client docs (#2965)
* fix: application bug * fix: test error * feat: client doc * fix: delete it.only * fix: demos * fix: ci * fix: create index.md --------- Co-authored-by: dream2023 <1098626505@qq.com>
This commit is contained in:
		
							parent
							
								
									bafb03a228
								
							
						
					
					
						commit
						05040a1c5f
					
				
							
								
								
									
										23
									
								
								.github/workflows/deploy-client-docs.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								.github/workflows/deploy-client-docs.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
name: deploy client docs
 | 
			
		||||
on: [push]
 | 
			
		||||
jobs:
 | 
			
		||||
  build:
 | 
			
		||||
    name: Build
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
    - uses: actions/setup-node@v3
 | 
			
		||||
      with:
 | 
			
		||||
        node-version: "18"
 | 
			
		||||
    - run: yarn install
 | 
			
		||||
    - name: Build
 | 
			
		||||
      run: yarn doc build core/client
 | 
			
		||||
    - name: copy files via ssh
 | 
			
		||||
      uses: appleboy/scp-action@v0.1.4
 | 
			
		||||
      with:
 | 
			
		||||
        host: ${{ secrets.CN_CLIENT_HOST }}
 | 
			
		||||
        username: ${{ secrets.CN_CLIENT_USERNAME }}
 | 
			
		||||
        key: ${{ secrets.CN_CLIENT_KEY }}
 | 
			
		||||
        port: ${{ secrets.CN_CLIENT_PORT }}
 | 
			
		||||
        source: "packages/core/client/dist/*"
 | 
			
		||||
        target: ${{ secrets.CN_CLIENT_TARGET }}/${{ github.ref_name }}
 | 
			
		||||
@ -1,18 +1,6 @@
 | 
			
		||||
import { defineConfig } from 'dumi';
 | 
			
		||||
import { defineThemeConfig } from 'dumi-theme-nocobase'
 | 
			
		||||
import { getUmiConfig } from '@nocobase/devtools/umiConfig';
 | 
			
		||||
import fs from 'fs';
 | 
			
		||||
import path from 'path';
 | 
			
		||||
 | 
			
		||||
const contributingPath = path.resolve(__dirname, './contributing.md');
 | 
			
		||||
const docsContributingPath = path.resolve(__dirname, './docs/contributing.md');
 | 
			
		||||
 | 
			
		||||
// check if the target path already exists, and remove it if it does
 | 
			
		||||
if (fs.existsSync(docsContributingPath)) {
 | 
			
		||||
  fs.unlinkSync(docsContributingPath);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fs.copyFileSync(contributingPath, docsContributingPath);
 | 
			
		||||
import { defineConfig } from 'dumi';
 | 
			
		||||
import { defineThemeConfig } from 'dumi-theme-nocobase';
 | 
			
		||||
 | 
			
		||||
const umiConfig = getUmiConfig();
 | 
			
		||||
 | 
			
		||||
@ -23,34 +11,106 @@ export default defineConfig({
 | 
			
		||||
  },
 | 
			
		||||
  resolve: {
 | 
			
		||||
    atomDirs: [
 | 
			
		||||
      { type: 'component', dir: 'src' },
 | 
			
		||||
      { type: 'component', dir: 'src/schema-component/antd' },
 | 
			
		||||
      { type: 'component', dir: 'src/route-switch/antd' },
 | 
			
		||||
    ]
 | 
			
		||||
      { type: 'api', dir: 'src' },
 | 
			
		||||
      { type: 'api', dir: 'src/schema-component/antd' },
 | 
			
		||||
      { type: 'api', dir: 'src/route-switch/antd' },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
  themeConfig: defineThemeConfig({
 | 
			
		||||
    title: 'NocoBase',
 | 
			
		||||
    logo: 'https://www.nocobase.com/images/logo.png',
 | 
			
		||||
    github: 'https://github.com/nocobase/nocobase',
 | 
			
		||||
    footer: 'nocobase | Copyright © 2022',
 | 
			
		||||
    sidebarGroupModePath: ['/components'],
 | 
			
		||||
    // sidebarGroupModePath: ['/components'],
 | 
			
		||||
    nav: [
 | 
			
		||||
      {
 | 
			
		||||
        title: 'Intro',
 | 
			
		||||
        link: '/intro',
 | 
			
		||||
        title: 'API',
 | 
			
		||||
        link: '/apis/application',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: 'Client',
 | 
			
		||||
        link: '/components/acl',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: 'Develop',
 | 
			
		||||
        link: '/develop',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: 'Contributing',
 | 
			
		||||
        link: '/contributing',
 | 
			
		||||
      }
 | 
			
		||||
    ]
 | 
			
		||||
  })
 | 
			
		||||
    ],
 | 
			
		||||
    sidebarEnhance: {
 | 
			
		||||
      '/apis': [
 | 
			
		||||
        {
 | 
			
		||||
          title: 'Core',
 | 
			
		||||
          type: 'group',
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              title: 'Application',
 | 
			
		||||
              children: [
 | 
			
		||||
                {
 | 
			
		||||
                  title: 'Application',
 | 
			
		||||
                  link: '/apis/application',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  title: 'APIClient',
 | 
			
		||||
                  link: '/apis/api-client',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  title: 'SettingsCenter',
 | 
			
		||||
                  link: '#',
 | 
			
		||||
                },
 | 
			
		||||
              ],
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              title: 'UI schema designer',
 | 
			
		||||
              children: [
 | 
			
		||||
                {
 | 
			
		||||
                  title: 'SchemaComponent',
 | 
			
		||||
                  link: '#',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  title: 'SchemaInitializer',
 | 
			
		||||
                  link: '#',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  title: 'SchemaSettings',
 | 
			
		||||
                  link: '#',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  title: 'DNDContext & DragHandler',
 | 
			
		||||
                  link: '#',
 | 
			
		||||
                },
 | 
			
		||||
              ],
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              title: 'Collection Manager',
 | 
			
		||||
              link: '#',
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              title: 'BlockProvider',
 | 
			
		||||
              link: '#',
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              title: 'RecordProvider',
 | 
			
		||||
              link: '#',
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          title: 'React components',
 | 
			
		||||
          type: 'group',
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              title: 'Board',
 | 
			
		||||
              link: '#',
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              title: 'Icon',
 | 
			
		||||
              link: '#',
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          title: 'Schema components',
 | 
			
		||||
          type: 'group',
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              title: 'Input',
 | 
			
		||||
              link: '#',
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  }),
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -1,61 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
toc: menu
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# 参与贡献
 | 
			
		||||
 | 
			
		||||
客户端的模块都在 `src` 目录下,各自模块独立。
 | 
			
		||||
 | 
			
		||||
## 客户端模块
 | 
			
		||||
 | 
			
		||||
最小单元模块化,一个完整的模块包含:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
|- /__tests__/ # 测试文件目录
 | 
			
		||||
|- /demos/ # demo 目录
 | 
			
		||||
|- index.ts # 最好不要直接在 index.ts 文件里写代码,index 文件只负责 export
 | 
			
		||||
|- index.md # 文档,默认为英文
 | 
			
		||||
|- index.zh-CN.md # 中文文档,可缺失,可以先都写到 index.md 里
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 测试
 | 
			
		||||
 | 
			
		||||
详细文档见 [@testing-library/react](https://testing-library.com/docs/react-testing-library/intro/)
 | 
			
		||||
 | 
			
		||||
```tsx | pure
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { render } from '@testing-library/react';
 | 
			
		||||
import { compose } from '../';
 | 
			
		||||
 | 
			
		||||
describe('compose', () => {
 | 
			
		||||
  it('case 1', () => {
 | 
			
		||||
    const A: React.FC = (props) => (
 | 
			
		||||
      <div>
 | 
			
		||||
        <h1>A</h1>
 | 
			
		||||
        {props.children}
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
    const App = compose(A)();
 | 
			
		||||
    const { container } = render(<App />);
 | 
			
		||||
    expect(container).toMatchSnapshot();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Demo
 | 
			
		||||
 | 
			
		||||
组件 Demo 见 [dumi](https://d.umijs.org/guide/basic#write-component-demo),可以直接写在文档里,如:
 | 
			
		||||
 | 
			
		||||
<pre lang="markdown">
 | 
			
		||||
```jsx
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export default () => <h1>Hello NocoBase!</h1>;
 | 
			
		||||
```
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
也可以引用 demo 文件
 | 
			
		||||
 | 
			
		||||
```markdown
 | 
			
		||||
<code src="./demos/dmeo1.tsx"></code>
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										1
									
								
								packages/core/client/docs/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								packages/core/client/docs/index.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
<Navigate replace to="/apis/application"></Navigate>
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
group:
 | 
			
		||||
  title: Client
 | 
			
		||||
  order: 1
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# ACL
 | 
			
		||||
 | 
			
		||||
访问控制列表,plugin-acl 的前端模块,详细文档待补充。
 | 
			
		||||
@ -1,25 +0,0 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { Table } from 'antd';
 | 
			
		||||
import { i18n, compose, APIClient, APIClientProvider, AntdConfigProvider } from '@nocobase/client';
 | 
			
		||||
import MockAdapter from 'axios-mock-adapter';
 | 
			
		||||
import { I18nextProvider } from 'react-i18next';
 | 
			
		||||
 | 
			
		||||
const apiClient = new APIClient({
 | 
			
		||||
  baseURL: `${location.protocol}//${location.host}/api/`,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const mock = new MockAdapter(apiClient.axios);
 | 
			
		||||
 | 
			
		||||
mock.onGet('/app:getLang').reply(200, {
 | 
			
		||||
  data: { lang: 'zh-CN' },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const providers = [
 | 
			
		||||
  [APIClientProvider, { apiClient }],
 | 
			
		||||
  [I18nextProvider, { i18n }],
 | 
			
		||||
  [AntdConfigProvider, { remoteLocale: true }],
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export default compose(...providers)(() => {
 | 
			
		||||
  return <Table />;
 | 
			
		||||
});
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
group:
 | 
			
		||||
  title: Client
 | 
			
		||||
  order: 1
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# AntdConfigProvider
 | 
			
		||||
 | 
			
		||||
为 antd 组件提供统一的全局化配置
 | 
			
		||||
 | 
			
		||||
<code src="./demos/demo1.tsx"></code>
 | 
			
		||||
							
								
								
									
										1
									
								
								packages/core/client/src/appInfo/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								packages/core/client/src/appInfo/index.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
# AppInfo
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
import { Application, Plugin } from '@nocobase/client';
 | 
			
		||||
import React, { FC } from 'react';
 | 
			
		||||
import { Link, Outlet, useLocation } from 'react-router-dom';
 | 
			
		||||
import { Application } from '../Application';
 | 
			
		||||
import { Plugin } from '../Plugin';
 | 
			
		||||
 | 
			
		||||
const Root = () => {
 | 
			
		||||
  return (
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,6 @@
 | 
			
		||||
import { Application, Plugin, RouterManager, useApp } from '@nocobase/client';
 | 
			
		||||
import React, { useMemo } from 'react';
 | 
			
		||||
import { Link, Navigate, Outlet, useParams } from 'react-router-dom';
 | 
			
		||||
import { Application } from '../Application';
 | 
			
		||||
import { useApp } from '../hooks';
 | 
			
		||||
import { Plugin } from '../Plugin';
 | 
			
		||||
import { RouterManager } from '../RouterManager';
 | 
			
		||||
 | 
			
		||||
const Root = () => {
 | 
			
		||||
  return (
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
---
 | 
			
		||||
group:
 | 
			
		||||
  title: Client
 | 
			
		||||
  title: core
 | 
			
		||||
  order: 1
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,22 +0,0 @@
 | 
			
		||||
import React, { createContext, useContext } from 'react';
 | 
			
		||||
import MockAdapter from 'axios-mock-adapter';
 | 
			
		||||
import { APIClient, APIClientProvider, compose, AsyncDataProvider, useAsyncData } from '@nocobase/client';
 | 
			
		||||
 | 
			
		||||
const apiClient = new APIClient();
 | 
			
		||||
 | 
			
		||||
const mock = new MockAdapter(apiClient.axios);
 | 
			
		||||
 | 
			
		||||
mock.onGet('/users/1').reply(200, {
 | 
			
		||||
  data: { id: 1, name: 'John Smith' },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const providers = [
 | 
			
		||||
  [APIClientProvider, { apiClient }],
 | 
			
		||||
  [AsyncDataProvider, { request: { url: '/users/1' } }],
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export default compose(...providers)(() => {
 | 
			
		||||
  const { data } = useAsyncData();
 | 
			
		||||
  console.log(data);
 | 
			
		||||
  return <div>{data?.data?.name}</div>;
 | 
			
		||||
});
 | 
			
		||||
@ -1,51 +0,0 @@
 | 
			
		||||
import { APIClient, APIClientProvider, SchemaComponent, SchemaComponentProvider, useRequest } from '@nocobase/client';
 | 
			
		||||
import { Table } from 'antd';
 | 
			
		||||
import MockAdapter from 'axios-mock-adapter';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
const apiClient = new APIClient();
 | 
			
		||||
 | 
			
		||||
const mock = new MockAdapter(apiClient.axios);
 | 
			
		||||
 | 
			
		||||
mock.onGet('/users').reply(200, {
 | 
			
		||||
  data: [
 | 
			
		||||
    { id: 1, name: 'John Smith' },
 | 
			
		||||
    { id: 2, name: 'Mike' },
 | 
			
		||||
  ],
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const TableView = (props) => {
 | 
			
		||||
  const { request, ...others } = props;
 | 
			
		||||
  const callback = () => props.dataSource || [];
 | 
			
		||||
  const { data, loading } = useRequest<{
 | 
			
		||||
    data: any;
 | 
			
		||||
  }>(props.request || callback);
 | 
			
		||||
  return <Table {...others} dataSource={data?.data} loading={loading} />;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default () => {
 | 
			
		||||
  return (
 | 
			
		||||
    <APIClientProvider apiClient={apiClient}>
 | 
			
		||||
      <SchemaComponentProvider components={{ TableView }}>
 | 
			
		||||
        <SchemaComponent
 | 
			
		||||
          schema={{
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            name: 'tableView',
 | 
			
		||||
            'x-component': 'TableView',
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              request: { url: '/users' },
 | 
			
		||||
              rowKey: 'id',
 | 
			
		||||
              columns: [
 | 
			
		||||
                {
 | 
			
		||||
                  title: 'Name',
 | 
			
		||||
                  dataIndex: 'name',
 | 
			
		||||
                  key: 'name',
 | 
			
		||||
                },
 | 
			
		||||
              ],
 | 
			
		||||
            },
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      </SchemaComponentProvider>
 | 
			
		||||
    </APIClientProvider>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -1,84 +0,0 @@
 | 
			
		||||
import {
 | 
			
		||||
  APIClient,
 | 
			
		||||
  APIClientProvider,
 | 
			
		||||
  AsyncDataProvider,
 | 
			
		||||
  SchemaComponent,
 | 
			
		||||
  SchemaComponentProvider,
 | 
			
		||||
  useAsyncData,
 | 
			
		||||
} from '@nocobase/client';
 | 
			
		||||
import { Table } from 'antd';
 | 
			
		||||
import MockAdapter from 'axios-mock-adapter';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
const apiClient = new APIClient();
 | 
			
		||||
 | 
			
		||||
const mock = new MockAdapter(apiClient.axios);
 | 
			
		||||
 | 
			
		||||
mock.onGet('/users').reply(200, {
 | 
			
		||||
  data: [
 | 
			
		||||
    { id: 1, name: 'John Smith' },
 | 
			
		||||
    { id: 2, name: 'Mike' },
 | 
			
		||||
  ],
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const TableView = (props) => {
 | 
			
		||||
  const { data, loading } = useAsyncData();
 | 
			
		||||
  return <Table {...props} dataSource={data?.data} loading={loading} />;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const AsyncDataTableView = (props) => {
 | 
			
		||||
  const { request, ...others } = props;
 | 
			
		||||
  return (
 | 
			
		||||
    <AsyncDataProvider request={request}>
 | 
			
		||||
      <TableView {...others} />
 | 
			
		||||
    </AsyncDataProvider>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default () => {
 | 
			
		||||
  return (
 | 
			
		||||
    <APIClientProvider apiClient={apiClient}>
 | 
			
		||||
      <SchemaComponentProvider components={{ TableView, AsyncDataTableView, AsyncDataProvider }}>
 | 
			
		||||
        <SchemaComponent
 | 
			
		||||
          schema={{
 | 
			
		||||
            properties: {
 | 
			
		||||
              table1: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                'x-decorator': 'AsyncDataProvider',
 | 
			
		||||
                'x-decorator-props': {
 | 
			
		||||
                  request: { url: '/users' },
 | 
			
		||||
                },
 | 
			
		||||
                'x-component': 'TableView',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  rowKey: 'id',
 | 
			
		||||
                  columns: [
 | 
			
		||||
                    {
 | 
			
		||||
                      title: 'Name',
 | 
			
		||||
                      dataIndex: 'name',
 | 
			
		||||
                      key: 'name',
 | 
			
		||||
                    },
 | 
			
		||||
                  ],
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
              table2: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                'x-component': 'AsyncDataTableView',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  request: { url: '/users' },
 | 
			
		||||
                  rowKey: 'id',
 | 
			
		||||
                  columns: [
 | 
			
		||||
                    {
 | 
			
		||||
                      title: 'Name',
 | 
			
		||||
                      dataIndex: 'name',
 | 
			
		||||
                      key: 'name',
 | 
			
		||||
                    },
 | 
			
		||||
                  ],
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      </SchemaComponentProvider>
 | 
			
		||||
    </APIClientProvider>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -1,154 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
group:
 | 
			
		||||
  title: Client
 | 
			
		||||
  order: 1
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# AsyncDataProvider
 | 
			
		||||
 | 
			
		||||
利用 Formily 提供的 [Effect Hooks](https://core.formilyjs.org/zh-CN/api/entry/form-effect-hooks) 或 [x-reactions](https://react.formilyjs.org/zh-CN/api/shared/schema#schemareactions) 协议能一定程度的解决某些场景的异步数据源问题,但是如果只用来处理异步请求,并不会很好用,而且局限于 Formily 体系内。为了更灵活的处理异步请求的各种需求,NocoBase 提供了非常好用的可配置化的 [useRequest()](api-client#userequest),用于配置各种异步请求。与此同时,又提供了 `<AsyncDataProvider/>` 组件,可以将请求结果共享给子组件,方便处理其他更复杂的需求。以平时最常见,但却可能非常复杂的表格为例。表格的使用场景有:
 | 
			
		||||
 | 
			
		||||
- TableView 只作为表格视图
 | 
			
		||||
- RowSelection 动态数据的勾选项
 | 
			
		||||
- TableField 表格字段
 | 
			
		||||
 | 
			
		||||
各自的 schema 可以这么表示:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// 表格视图,type 为 void,无 default 默认值,无 field.value,
 | 
			
		||||
// dataSource 直接写在组件的 props 里
 | 
			
		||||
{
 | 
			
		||||
  type: 'void',
 | 
			
		||||
  'x-component': 'TableView',
 | 
			
		||||
  'x-component-props': {
 | 
			
		||||
    columns: [
 | 
			
		||||
      {
 | 
			
		||||
        title: 'Name',
 | 
			
		||||
        dataIndex: 'name',
 | 
			
		||||
        key: 'name',
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    dataSource: [
 | 
			
		||||
      { id: 1, name: 'Name1' },
 | 
			
		||||
      { id: 2, name: 'Name2' },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 单选(表格视图),类似于 Radio.Group 字段,可选项由表格视图提供
 | 
			
		||||
{
 | 
			
		||||
  type: 'number',
 | 
			
		||||
  'x-component': 'RowSelection',
 | 
			
		||||
  'x-component-props': {
 | 
			
		||||
    rowSelection: {
 | 
			
		||||
      type: 'radio',
 | 
			
		||||
    },
 | 
			
		||||
    columns: [
 | 
			
		||||
      {
 | 
			
		||||
        title: 'Name',
 | 
			
		||||
        dataIndex: 'name',
 | 
			
		||||
        key: 'name',
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    dataSource: [
 | 
			
		||||
      { id: 1, name: 'Name1' },
 | 
			
		||||
      { id: 2, name: 'Name2' },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
  default: 1,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 多选(表格视图),类似于 Checkbox.Group 字段,可选项由表格视图提供
 | 
			
		||||
{
 | 
			
		||||
  type: 'array',
 | 
			
		||||
  'x-component': 'RowSelection',
 | 
			
		||||
  'x-component-props': {
 | 
			
		||||
    rowSelection: {
 | 
			
		||||
      type: 'checkbox',
 | 
			
		||||
    },
 | 
			
		||||
    columns: [
 | 
			
		||||
      {
 | 
			
		||||
        title: 'Name',
 | 
			
		||||
        dataIndex: 'name',
 | 
			
		||||
        key: 'name',
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    dataSource: [
 | 
			
		||||
      { id: 1, name: 'Name1' },
 | 
			
		||||
      { id: 2, name: 'Name2' },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
  default: [1],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 表格字段,数据由表单提供,schema 层面可以配置默认值
 | 
			
		||||
// 与表格视图的方式不同,dataSource 和 columns 不适合直接配置在 x-component-props 里,怎么处理先忽略。
 | 
			
		||||
{
 | 
			
		||||
  type: 'array',
 | 
			
		||||
  'x-component': 'TableField',
 | 
			
		||||
  'x-component-props': {},
 | 
			
		||||
  default: [
 | 
			
		||||
    { id: 1, name: 'Name1' },
 | 
			
		||||
    { id: 2, name: 'Name2' },
 | 
			
		||||
  ],
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
大多数实际应用中,表格视图的 dataSource 是异步获取的,可能也需要过滤和分页,这样一来直接在 x-component-props 里写 dataSource 并不合适。为了解决这个问题,可以给组件扩展一个 request 属性,用于请求远程数据,例子如下:
 | 
			
		||||
 | 
			
		||||
<code src="./demos/demo2.tsx"></code>
 | 
			
		||||
 | 
			
		||||
上述例子的 `<TableView/>` 组件就是一个 React Component,可以正常使用,而不局限于 SchemaComponent 场景。更进一步,为了处理过滤表单、分页等问题,建议将 request 通过 `<AsyncDataProvider/>` 共享给 `<TableView/>` 组件。
 | 
			
		||||
 | 
			
		||||
```tsx | pure
 | 
			
		||||
const result = useRequest(props.request);
 | 
			
		||||
<AsyncDataProvider value={result}>
 | 
			
		||||
  <TableView/>
 | 
			
		||||
</AsyncDataProvider>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
或者直接将 request 交给 AsyncDataProvider
 | 
			
		||||
 | 
			
		||||
```tsx | pure
 | 
			
		||||
<AsyncDataProvider request={props.request}>
 | 
			
		||||
  <TableView/>
 | 
			
		||||
</AsyncDataProvider>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
在 `<AsyncDataProvider/>` 的子组件里就可以通过 `useAsyncData()` 来获取 result,可用于处理过滤、分页等。
 | 
			
		||||
 | 
			
		||||
```ts
 | 
			
		||||
const { data, loading, params, run, refresh, parent } = useAsyncData();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
转化为 Schema 时,可以将 AsyncDataProvider 放在 `x-decorator` 里,也可以将重新组合的 AsyncDataProvider + TableView,放在 `x-component` 里。
 | 
			
		||||
 | 
			
		||||
<code src="./demos/demo3.tsx"></code>
 | 
			
		||||
 | 
			
		||||
将 AsyncDataProvider 独立出来,放到 x-decorator 里的另一个好处,例子如下:
 | 
			
		||||
 | 
			
		||||
```tsx | pure
 | 
			
		||||
<CollectionProvider>
 | 
			
		||||
  {/* 从 CollectionProvider 里获取资源请求参数,并将请求结果同时共享给 DesignableBar 和 TableView */}
 | 
			
		||||
  <AsyncDataProvider>
 | 
			
		||||
    <DesignableBar/>
 | 
			
		||||
    <TableView>
 | 
			
		||||
      <RecordProvider>
 | 
			
		||||
        <CollectionFieldProvider>
 | 
			
		||||
          {/* 从 CollectionFieldProvider 里获取关系资源请求参数,并将请求结果同时共享给子组件 */}
 | 
			
		||||
          <AsyncDataProvider>
 | 
			
		||||
            {/* 组件 */}
 | 
			
		||||
          </AsyncDataProvider>
 | 
			
		||||
        </CollectionFieldProvider>
 | 
			
		||||
      </RecordProvider>
 | 
			
		||||
    </TableView>
 | 
			
		||||
  </AsyncDataProvider>
 | 
			
		||||
</CollectionProvider>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
上面例子嵌套了两层 AsyncDataProvider,在子 AsyncDataProvider 里,也可以获取到更上一级的请求结果,如:
 | 
			
		||||
 | 
			
		||||
```ts
 | 
			
		||||
const { parent } = useAsyncData();
 | 
			
		||||
parent.refresh();
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										1
									
								
								packages/core/client/src/block-provider/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								packages/core/client/src/block-provider/index.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
# BlockProvider
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
group:
 | 
			
		||||
  title: Client
 | 
			
		||||
  order: 1
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# I18n
 | 
			
		||||
 | 
			
		||||
提供国际化解决方案。
 | 
			
		||||
@ -1,25 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
group:
 | 
			
		||||
  title: Route Components
 | 
			
		||||
  order: 2
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# AdminLayout <Badge>待定</Badge>
 | 
			
		||||
 | 
			
		||||
结构
 | 
			
		||||
 | 
			
		||||
- Layout
 | 
			
		||||
- Layout.Header
 | 
			
		||||
  - SiteTitle
 | 
			
		||||
  - Menu(SchemaComponent)
 | 
			
		||||
  - PluginManager.Toolbar
 | 
			
		||||
    - DesignableAction
 | 
			
		||||
    - CollectionManager.Action
 | 
			
		||||
    - ACL.Action
 | 
			
		||||
    - SystemSettings.Action
 | 
			
		||||
    - CurrentUser.Dropdown
 | 
			
		||||
- Layout.Sider
 | 
			
		||||
  - SideMenu(随 Menu 联动的)
 | 
			
		||||
- Layout.Content
 | 
			
		||||
  - PageTitle
 | 
			
		||||
  - SchemaComponent
 | 
			
		||||
@ -1,8 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
group:
 | 
			
		||||
  title: Route Components
 | 
			
		||||
  order: 2
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# AuthLayout
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								packages/core/client/src/schema-settings/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								packages/core/client/src/schema-settings/index.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
# SchemaSettings
 | 
			
		||||
@ -1,44 +0,0 @@
 | 
			
		||||
import {
 | 
			
		||||
  AntdSchemaComponentProvider,
 | 
			
		||||
  APIClient,
 | 
			
		||||
  APIClientProvider,
 | 
			
		||||
  SchemaComponentProvider,
 | 
			
		||||
  SystemSettingsProvider,
 | 
			
		||||
  useSystemSettings,
 | 
			
		||||
} from '@nocobase/client';
 | 
			
		||||
import MockAdapter from 'axios-mock-adapter';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
const apiClient = new APIClient();
 | 
			
		||||
 | 
			
		||||
const mock = new MockAdapter(apiClient.axios);
 | 
			
		||||
 | 
			
		||||
mock.onGet('/systemSettings:get/1').reply(200, {
 | 
			
		||||
  data: {
 | 
			
		||||
    title: 'NocoBase',
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const Demo = () => {
 | 
			
		||||
  const { data } = useSystemSettings();
 | 
			
		||||
  return (
 | 
			
		||||
    <div>
 | 
			
		||||
      <h3>以下为测试内容</h3>
 | 
			
		||||
      System title: {data?.data?.title}
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default () => {
 | 
			
		||||
  return (
 | 
			
		||||
    <APIClientProvider apiClient={apiClient}>
 | 
			
		||||
      <SystemSettingsProvider>
 | 
			
		||||
        <SchemaComponentProvider>
 | 
			
		||||
          <AntdSchemaComponentProvider>
 | 
			
		||||
            <Demo />
 | 
			
		||||
          </AntdSchemaComponentProvider>
 | 
			
		||||
        </SchemaComponentProvider>
 | 
			
		||||
      </SystemSettingsProvider>
 | 
			
		||||
    </APIClientProvider>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -1,21 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
group:
 | 
			
		||||
  title: Client
 | 
			
		||||
  order: 1
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# SystemSettings
 | 
			
		||||
 | 
			
		||||
## SystemSettingsProvider
 | 
			
		||||
 | 
			
		||||
## SystemSettingsShortcut
 | 
			
		||||
 | 
			
		||||
## useSystemSettings
 | 
			
		||||
 | 
			
		||||
```ts
 | 
			
		||||
const { data, loading, refresh } = useSystemSettings();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Examples
 | 
			
		||||
 | 
			
		||||
<code src="./demos/demo1.tsx"></code>
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user