feat: add client provider

This commit is contained in:
chenos 2021-09-28 09:33:38 +08:00
parent 897169a613
commit 1dff47e8e4
24 changed files with 90 additions and 887 deletions

View File

@ -4,11 +4,10 @@
"scripts": {
"start": "concurrently \"cd ../../ && npm run start-server\" \"umi dev\"",
"start-client": "umi dev",
"start-server": "nodemon",
"start-server": "ts-node-dev -r dotenv/config --project tsconfig.apis.json ./src/apis/index.ts",
"build": "npm run build-server && npm run build-client",
"build-client": "umi build",
"nocobase": "cross-env TS_NODE_PROJECT=\"tsconfig.api.json\" ts-node ./src/api/index.ts",
"build-server": "rimraf -rf lib && tsc --project tsconfig.api.json",
"build-server": "rimraf -rf lib && tsc --project tsconfig.apis.json",
"postinstall": "umi generate tmp",
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
"test": "umi-test",
@ -27,10 +26,20 @@
},
"dependencies": {
"@nocobase/client": "^0.4.0-alpha.7",
"@nocobase/preset-nocobase": "^0.4.0-alpha.7",
"@nocobase/plugin-action-logs": "^0.4.0-alpha.7",
"@nocobase/plugin-automations": "^0.4.0-alpha.7",
"@nocobase/plugin-china-region": "^0.4.0-alpha.7",
"@nocobase/plugin-collections": "^0.4.0-alpha.7",
"@nocobase/plugin-file-manager": "^0.4.0-alpha.7",
"@nocobase/plugin-pages": "^0.4.0-alpha.7",
"@nocobase/plugin-permissions": "^0.4.0-alpha.7",
"@nocobase/plugin-ui-router": "^0.4.0-alpha.7",
"@nocobase/plugin-ui-schema": "^0.4.0-alpha.7",
"@nocobase/plugin-users": "^0.4.0-alpha.7",
"@nocobase/plugin-saas": "^0.4.0-alpha.7",
"@nocobase/server": "^0.4.0-alpha.7",
"@umijs/preset-react": "1.x",
"koa-mount": "^4.0.0",
"ts-node-dev": "^1.1.8",
"umi": "^3.0.0"
},
"devDependencies": {
@ -40,11 +49,11 @@
"concurrently": "^5.3.0",
"cross-env": "^7.0.3",
"mockjs": "^1.1.0",
"nodemon": "^2.0.12",
"prettier": "^2.2.0",
"react": "17.x",
"react-dom": "17.x",
"ts-node": "^10.2.1",
"ts-node-dev": "^1.1.8",
"yorkie": "^2.0.0"
}
}

View File

@ -1,4 +1,10 @@
import Server from '@nocobase/server';
import dotenv from 'dotenv';
import path from 'path';
dotenv.config({
path: path.resolve(__dirname, '../../../../.env'),
});
const start = Date.now();
@ -35,6 +41,7 @@ const api = new Server({
});
const plugins = [
'@nocobase/plugin-saas',
'@nocobase/plugin-collections',
'@nocobase/plugin-ui-router',
'@nocobase/plugin-ui-schema',

View File

@ -1,9 +1,9 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./lib/api"
"outDir": "./lib/apis"
},
"include": [
"src/api",
"src/apis",
]
}

View File

@ -0,0 +1,19 @@
import { RequestMethod, RequestOptionsInit } from 'umi-request';
export class ClientSDK {
options: any;
constructor(options) {
this.options = options;
}
request(url: string, options?: RequestOptionsInit): RequestMethod {
return this.options.request(url, options);
}
resource(name) {
}
}
export default ClientSDK;

View File

@ -2,7 +2,6 @@ import React from 'react';
import { observer } from '@formily/react';
import { Table, Checkbox, Spin } from 'antd';
import { useRequest } from 'ahooks';
import { request } from '../../../schemas';
import { Resource } from '../../../resource';
import { useContext } from 'react';
import { RoleContext } from '.';
@ -23,7 +22,7 @@ export const MenuPermissionTable = observer((props) => {
const [allUiSchemaKyes, setAllUiSchemaKyes] = useState([]);
const [uiSchemaKyes, setUiSchemaKeys] = useState([]);
const { data, loading } = useRequest(
() => request('ui_schemas:getMenuItems'),
'ui_schemas:getMenuItems',
{
formatResult: (data) => data?.data,
onSuccess(data) {

View File

@ -0,0 +1,25 @@
import React, { createContext, useContext } from 'react';
import { UseRequestProvider } from 'ahooks';
const ClientContext = createContext({
client: null,
});
export function ClientProvider(props) {
const { client } = props;
return (
<ClientContext.Provider value={client}>
<UseRequestProvider
value={{
requestMethod: (service) => client.request(service),
}}
>
{props.children}
</UseRequestProvider>
</ClientContext.Provider>
);
}
export function useClient() {
return useContext(ClientContext);
}

View File

@ -2,3 +2,4 @@ export * from './Collections';
export * from './DesignableSwitch';
export * from './DisplayedMap';
export * from './PageTitle';
export * from './Client';

View File

@ -1,39 +0,0 @@
import { useRequest } from 'ahooks';
import { Spin } from 'antd';
import React, { useMemo } from 'react';
import { MemoryRouter as Router } from 'react-router-dom';
import {
createRouteSwitch,
RouteRedirectProps,
AdminLayout,
AuthLayout,
RouteSchemaRenderer,
} from '../';
import { UseRequestProvider } from 'ahooks';
import { extend } from 'umi-request';
const request = extend({
prefix: process.env.API_URL,
timeout: 30000,
});
request.use(async (ctx, next) => {
const { headers } = ctx.req.options as any;
const token = localStorage.getItem('NOCOBASE_TOKEN');
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
await next();
});
export const RequestProvider = (props) => {
return (
<UseRequestProvider
value={{
requestMethod: (service) => request(service),
}}
>
{props.children}
</UseRequestProvider>
);
};

View File

@ -1,38 +0,0 @@
const api = {
'/api/routes:getAccessible': require('./routes-getAccessible').default,
// '/api/blocks:getSchema/login': require('./blocks-getSchema/login').default,
// '/api/blocks:getSchema/register': require('./blocks-getSchema/register').default,
// '/api/blocks:getSchema/item1': require('./blocks-getSchema/item1').default,
// '/api/blocks:getSchema/item2': require('./blocks-getSchema/item2').default,
// '/api/blocks:getSchema/item22': require('./blocks-getSchema/item22').default,
// '/api/blocks:getSchema/item3': require('./blocks-getSchema/item3').default,
// '/api/blocks:getSchema/item4': require('./blocks-getSchema/item4').default,
// '/api/blocks:getSchema/item5': require('./blocks-getSchema/item5').default,
// '/api/blocks:getSchema/menu': require('./blocks-getSchema/menu').default,
'/api/ui-schemas:getTree/login': require('./ui-schemas-getTree/login').default,
'/api/ui-schemas:getTree/register': require('./ui-schemas-getTree/register').default,
'/api/ui-schemas:getTree/menu': require('./ui-schemas-getTree/menu').default,
}
export function request(service) {
let url = null;
if (typeof service === 'string') {
url = service;
} else if (typeof service === 'object' && service.url) {
url = service.url;
}
console.log('request.url', url)
return new Promise((resolve, reject) => {
setTimeout(() => {
if (api[url]) {
resolve({
data: api[url],
})
} else {
resolve({ data: {} });
}
}, 100)
})
}

View File

@ -1,35 +0,0 @@
export default [
{
type: 'redirect',
from: '/',
to: '/admin',
exact: true,
},
{
type: 'route',
path: '/admin/:name(.+)?',
component: 'AdminLayout',
title: `后台`,
uiSchemaKey: 'qqzzjakwkwl',
},
{
type: 'route',
component: 'AuthLayout',
children: [
{
type: 'route',
path: '/login',
component: 'RouteSchemaRenderer',
title: `登录`,
uiSchemaKey: 'dtf9j0b8p9u',
},
{
type: 'route',
path: '/register',
component: 'RouteSchemaRenderer',
title: `注册`,
uiSchemaKey: '46qlxqam3xk',
},
],
},
];

View File

@ -1,157 +0,0 @@
import { ISchema } from '@formily/json-schema';
import { uid } from '@formily/shared';
export default {
type: 'object',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Row',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
[uid()]: {
type: 'void',
'x-decorator': 'BlockItem',
'x-component': 'Form',
properties: {
[uid()]: {
type: 'void',
'x-decorator': 'Card',
'x-component': 'Grid',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Row',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
[uid()]: {
type: 'string',
required: true,
title: '字段1',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
[uid()]: {
type: 'string',
required: true,
title: '字段2',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
},
},
[uid()]: {
type: 'void',
'x-component': 'Grid.Row',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
[uid()]: {
type: 'string',
required: true,
title: '字段3',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
[uid()]: {
type: 'string',
required: true,
title: '字段4',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
},
},
[uid()]: {
type: 'void',
'x-component': 'Grid.Row',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
[uid()]: {
type: 'string',
required: true,
title: '字段5',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
},
},
},
},
actions: {
type: 'void',
// 'x-decorator': 'Div',
'x-component': 'Space',
properties: {
submit: {
type: 'void',
'x-component': 'Action',
'x-component-props': {
// block: true,
type: 'primary',
useAction: '{{ useLogin }}',
style: {
// width: '100%',
},
},
title: '提交',
},
reset: {
type: 'void',
'x-component': 'Action',
'x-component-props': {
// block: true,
useAction: '{{ useLogin }}',
style: {
// width: '100%',
},
},
title: '重置',
},
},
},
},
},
},
},
},
},
},
},
},
} as ISchema;

View File

@ -1,31 +0,0 @@
import { ISchema } from '@formily/json-schema';
import { uid } from '@formily/shared';
export default {
type: 'object',
properties: {
[uid()]: {
type: 'void',
'x-decorator': 'Card',
'x-component': 'Grid',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Row',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
[uid()]: {
type: 'void',
'x-component': 'AddNew.BlockItem',
},
},
},
},
},
},
},
},
} as ISchema;

View File

@ -1,63 +0,0 @@
export default {
type: 'object',
properties: {
input: {
type: 'string',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Input',
'x-component-props': {
placeholder: '邮箱或用户名',
style: {
// width: 240,
},
},
},
textarea: {
type: 'string',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Password',
'x-component-props': {
placeholder: '密码',
style: {
// width: 240,
},
},
},
actions: {
type: 'void',
// 'x-decorator': 'Div',
'x-component': 'Div',
properties: {
submit: {
type: 'void',
'x-component': 'Action',
'x-component-props': {
block: true,
type: 'primary',
useAction: '{{ useLogin }}',
style: {
width: '100%',
},
},
title: '登录',
},
},
},
registerlink: {
type: 'void',
'x-component': 'Div',
properties: {
link: {
type: 'void',
'x-component': 'Action.Link',
'x-component-props': {
to: '/register',
},
title: '注册账号',
},
},
},
},
}

View File

@ -1,139 +0,0 @@
import { uid } from '@formily/shared';
const schema = {
type: 'object',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Form',
properties: {
[uid()]: {
type: 'void',
'x-decorator': 'Card',
'x-component': 'Grid',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Row',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
[uid()]: {
type: 'string',
required: true,
title: '字段1',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
[uid()]: {
type: 'string',
required: true,
title: '字段2',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
},
},
[uid()]: {
type: 'void',
'x-component': 'Grid.Row',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
[uid()]: {
type: 'string',
required: true,
title: '字段3',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
[uid()]: {
type: 'string',
required: true,
title: '字段4',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
},
},
[uid()]: {
type: 'void',
'x-component': 'Grid.Row',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
[uid()]: {
type: 'string',
required: true,
title: '字段5',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
},
},
},
},
actions: {
type: 'void',
// 'x-decorator': 'Div',
'x-component': 'Space',
properties: {
submit: {
type: 'void',
'x-component': 'Action',
'x-component-props': {
// block: true,
type: 'primary',
useAction: '{{ useLogin }}',
style: {
// width: '100%',
},
},
title: '提交',
},
reset: {
type: 'void',
'x-component': 'Action',
'x-component-props': {
// block: true,
useAction: '{{ useLogin }}',
style: {
// width: '100%',
},
},
title: '重置',
},
},
},
},
},
},
};
export default schema;

View File

@ -1,17 +0,0 @@
export default {
type: 'object',
properties: {
input: {
type: 'string',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Input',
'x-component-props': {
placeholder: '邮箱或用户名',
style: {
// width: 240,
},
},
},
},
}

View File

@ -1,92 +0,0 @@
export default {
name: 'arr',
type: 'array',
'x-component': 'Table',
default: [{ field1: 'a', field2: 'b' }, { field1: 'a', field2: 'b' }],
'x-component-props': {},
properties: {
actionBar1: {
type: 'void',
'x-component': 'Table.ActionBar',
properties: {
action1: {
type: 'object',
title: '按钮1',
'x-component': 'Table.Action.Popover',
'x-component-props': {
},
properties: {
},
},
action2: {
type: 'void',
title: '按钮2',
'x-component': 'Table.Action.Button',
'x-component-props': {
label: '按钮2',
},
},
},
},
actionBar2: {
type: 'void',
'x-component': 'Table.ActionBar',
'x-component-props': {
align: 'bottom',
},
properties: {
pagination: {
type: 'void',
'x-component': 'Table.Pagination',
'x-component-props': {
defaultCurrent: 1,
total: 50,
},
},
},
},
details: {
type: 'void',
'x-component': 'Table.Details',
properties: {},
},
col1: {
type: 'void',
title: '字段1',
'x-component': 'Table.Column',
'x-component-props': {
title: 'z1',
width: 100,
},
properties: {
field1: {
type: 'string',
required: true,
'x-decorator-props': {
feedbackLayout: 'popover',
},
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
col2: {
type: 'void',
title: '字段2',
'x-component': 'Table.Column',
properties: {
field2: {
type: 'string',
title: '字段2',
required: true,
'x-decorator-props': {
feedbackLayout: 'popover',
},
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
},
}

View File

@ -1,62 +0,0 @@
export default {
type: 'object',
properties: {
email: {
type: 'string',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Input',
'x-component-props': {
placeholder: '邮箱或用户名',
style: {
// width: 240,
},
},
},
password: {
type: 'string',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Password',
'x-component-props': {
placeholder: '密码',
style: {
// width: 240,
},
},
},
actions: {
type: 'void',
'x-component': 'Div',
properties: {
submit: {
type: 'void',
'x-component': 'Action',
'x-component-props': {
block: true,
type: 'primary',
useAction: '{{ useLogin }}',
style: {
width: '100%',
},
},
title: '登录',
},
},
},
registerlink: {
type: 'void',
'x-component': 'Div',
properties: {
link: {
type: 'void',
'x-component': 'Action.Link',
'x-component-props': {
to: '/register',
},
title: '注册账号',
},
},
},
},
};

View File

@ -1,107 +0,0 @@
import { uid } from '@formily/shared';
export default {
type: 'void',
name: `menu_${uid()}`,
'x-component': 'Menu',
'x-designable-bar': 'Menu.DesignableBar',
'x-component-props': {
mode: 'mix',
theme: 'dark',
defaultSelectedKeys: '{{ selectedKeys }}',
sideMenuRef: '{{ sideMenuRef }}',
onSelect: '{{ onSelect }}',
},
properties: {
[uid()]: {
type: 'void',
title: `菜单2`,
'x-component': 'Menu.Link',
'x-component-props': {
icon: 'MailOutlined',
},
},
[uid()]: {
type: 'void',
title: `菜单22`,
'x-component': 'Menu.Link',
'x-component-props': {
icon: 'AppstoreOutlined',
// url: 'https://www.google.com',
},
},
[uid()]: {
type: 'void',
title: '菜单组1',
'x-component': 'Menu.SubMenu',
'x-component-props': {
icon: 'SettingOutlined',
},
},
[uid()]: {
type: 'void',
title: '菜单组2',
'x-component': 'Menu.SubMenu',
'x-component-props': {
icon: 'SettingOutlined',
},
properties: {
[uid()]: {
type: 'void',
title: '菜单6',
'x-component': 'Menu.SubMenu',
'x-component-props': {
icon: 'AppstoreOutlined',
},
properties: {
[uid()]: {
type: 'void',
title: '菜单9',
'x-component': 'Menu.SubMenu',
properties: {
[uid()]: {
type: 'void',
title: `子菜单10`,
'x-component': 'Menu.Link',
},
[uid()]: {
type: 'void',
title: `子菜单11`,
'x-component': 'Menu.Link',
},
}
},
[uid()]: {
type: 'void',
title: `子菜单7`,
'x-component': 'Menu.Link',
},
[uid()]: {
type: 'void',
title: `子菜单8`,
'x-component': 'Menu.Link',
},
}
},
[uid()]: {
type: 'void',
title: `子菜单1`,
'x-component': 'Menu.Link',
},
[uid()]: {
type: 'void',
title: `子菜单2`,
'x-component': 'Menu.Link',
},
}
},
[uid()]: {
type: 'void',
title: `菜单1`,
'x-component': 'Menu.Link',
'x-component-props': {
icon: 'SettingOutlined',
},
},
},
}

View File

@ -1,76 +0,0 @@
export default {
type: 'object',
properties: {
username: {
type: 'string',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Input',
'x-component-props': {
placeholder: '用户名',
style: {
// width: 240,
},
},
},
pwd1: {
type: 'string',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Password',
'x-component-props': {
placeholder: '密码',
checkStrength: true,
style: {
// width: 240,
},
},
},
pwd2: {
type: 'string',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Password',
'x-component-props': {
placeholder: '密码',
checkStrength: true,
style: {
// width: 240,
},
},
},
actions: {
type: 'void',
'x-component': 'Div',
properties: {
submit: {
type: 'void',
title: '注册',
'x-component': 'Action',
'x-component-props': {
block: true,
type: 'primary',
useAction: '{{ useRegister }}',
style: {
width: '100%',
},
},
},
},
},
registerlink: {
type: 'void',
'x-component': 'Div',
properties: {
link: {
type: 'void',
'x-component': 'Action.Link',
'x-component-props': {
to: '/login',
},
title: '使用已有账号登录',
},
},
},
},
}

View File

@ -10,6 +10,8 @@ import {
AdminLayout,
AuthLayout,
RouteSchemaRenderer,
ClientProvider,
ClientSDK
} from '../';
import { UseRequestProvider } from 'ahooks';
import { extend } from 'umi-request';
@ -28,6 +30,10 @@ request.use(async (ctx, next) => {
await next();
});
const client = new ClientSDK({
request,
});
console.log('process.env.API_URL', process.env.API_URL);
// console.log = () => {}
@ -60,12 +66,8 @@ const App = () => {
export default () => {
return (
<UseRequestProvider
value={{
requestMethod: (service) => request(service),
}}
>
<ClientProvider client={client}>
<App />
</UseRequestProvider>
</ClientProvider>
);
}

View File

@ -3,3 +3,5 @@ export * from './components/admin-layout';
export * from './components/auth-layout';
export * from './components/route-schema-renderer';
export * from './schemas';
export * from './constate';
export * from './ClientSDK';

View File

@ -2,10 +2,11 @@
title: Action - 操作
nav:
title: 组件
path: /schemas
path: /client
group:
title: 组件
path: /schemas
order: 1
title: Schemas
path: /client/schemas
---
# Action - 操作

View File

@ -2,7 +2,6 @@ import React from 'react';
import { ISchema, SchemaRenderer } from '../../';
import { useSelect, useOptionTagValues } from '../';
import { uid } from '@formily/shared';
import { RequestProvider } from '@nocobase/client/src/demos/RequestProvider';
import { CollectionsProvider } from '@nocobase/client/src/constate';
console.log({ useSelect });
@ -194,13 +193,11 @@ const schema: ISchema = {
export default () => {
return (
<RequestProvider>
<CollectionsProvider>
<SchemaRenderer
scope={{ useSelect, useValues, useOptionTagValues }}
schema={schema}
/>
</CollectionsProvider>
</RequestProvider>
);
};

View File

@ -7,7 +7,6 @@ import {
CollectionsProvider,
DesignableSwitchProvider,
} from '@nocobase/client/src/constate';
import { RequestProvider } from '@nocobase/client/src/demos/RequestProvider';
const schema = {
name: 'table1',
@ -222,13 +221,11 @@ const schema = {
export default () => {
return (
<div>
<RequestProvider>
<DesignableSwitchProvider>
<CollectionsProvider>
<SchemaRenderer schema={schema} />
</CollectionsProvider>
</DesignableSwitchProvider>
</RequestProvider>
</div>
);
};