feat: add useClient and useResourceRequest hooks

This commit is contained in:
chenos 2021-09-28 18:20:21 +08:00
parent 20d602e2b1
commit 86e2a2802d
37 changed files with 339 additions and 188 deletions

View File

@ -42,9 +42,9 @@ const api = new Server({
const plugins = [
'@nocobase/plugin-saas',
'@nocobase/plugin-collections',
'@nocobase/plugin-ui-router',
'@nocobase/plugin-ui-schema',
'@nocobase/plugin-ui-router',
'@nocobase/plugin-collections',
'@nocobase/plugin-users',
'@nocobase/plugin-action-logs',
'@nocobase/plugin-file-manager',

View File

@ -8,7 +8,8 @@ export class ClientSDK {
}
request(url: string, options?: RequestOptionsInit): RequestMethod {
return this.options.request(url, options);
console.log('this.options.request', this.options.request);
return this.options.request(url, options||{});
}
resource(name) {

View File

@ -0,0 +1,19 @@
import React, { createContext } from 'react'
// import { ConfigProvider as AntdConfigProvider } from 'antd';
// import enUS from 'antd/lib/locale/en_US';
// import zhCN from 'antd/lib/locale/zh_CN';
import { ClientProvider } from './constate';
// import moment from 'moment';
// import 'moment/locale/zh-cn';
// moment.locale('zh-cn');
const ConfigContext = createContext<any>(null);
export function ConfigProvider(props: any) {
const { client } = props;
return (
<ClientProvider client={client}>
{props.children}
</ClientProvider>
)
};

View File

@ -24,6 +24,7 @@ import {
interfaces,
options,
} from '../../../schemas/database-field/interfaces';
import { useResourceRequest } from '../../../constate';
export const RoleContext = createContext(null);
@ -38,7 +39,7 @@ function VisibleProvider(props) {
}
const useResource = () => {
const resource = Resource.make('collections');
const resource = useResourceRequest('collections');
return {
resource,
};
@ -47,7 +48,7 @@ const useResource = () => {
const useCollectionsResource = () => {
const descriptionsContext = useContext(DescriptionsContext);
console.log('descriptionsContext.service', descriptionsContext.service);
const resource = Resource.make('collections');
const resource = useResourceRequest('collections');
return {
resource,
};
@ -63,7 +64,7 @@ class ActionPermissionResource extends Resource {
const useActionPermissionSubmit = () => {
const form = useForm();
const role = useContext(RoleContext);
const resource = Resource.make({
const resource = useResourceRequest({
resourceName: 'roles',
resourceKey: role.name,
});
@ -80,9 +81,9 @@ const useActionPermissionResource = ({ onSuccess }) => {
console.log('RoleContext', role);
// const { props } = useTable();
const ctx = useContext(TableRowContext);
const resource = ActionPermissionResource.make({
const resource = useResourceRequest({
resourceName: 'action_permissions',
});
}, ActionPermissionResource);
const service = useRequest(
(params?: any) => {
return resource.list({
@ -128,7 +129,7 @@ const useActionPermissionResource = ({ onSuccess }) => {
const useDetailsResource = ({ onSuccess }) => {
const { props } = useTable();
const ctx = useContext(TableRowContext);
const resource = Resource.make({
const resource = useResourceRequest({
resourceName: 'collections',
resourceKey: ctx.record[props.rowKey],
});
@ -164,7 +165,7 @@ const useFieldsResource = () => {
});
}
}
const resource = FieldResource.make('fields');
const resource = useResourceRequest('fields', FieldResource);
return {
resource,
};
@ -545,6 +546,7 @@ function CreateFieldButton() {
const form = useMemo(() => createForm(), []);
const [properties, setProperties] = useState({});
const { collections = [], loading } = useCollectionsContext();
const resource = useResourceRequest('fields');
const loadCollections = async (field: any) => {
return collections.map((item: any) => ({
@ -623,7 +625,7 @@ function CreateFieldButton() {
<Button
type={'primary'}
onClick={async () => {
await Resource.make('fields').save(form.values);
await resource.save(form.values);
setVisible(false);
await service.refresh();
await refresh();
@ -659,6 +661,7 @@ function EditFieldButton() {
const form = useMemo(() => createForm(), []);
const schema = interfaces.get(ctx.record.interface);
const { collections = [], loading } = useCollectionsContext();
const resource = useResourceRequest('fields');
const loadCollections = async (field: any) => {
return collections.map((item: any) => ({
@ -714,7 +717,7 @@ function EditFieldButton() {
<Button
type={'primary'}
onClick={async () => {
await Resource.make('fields').save(form.values, {
await resource.save(form.values, {
resourceKey: ctx.record.key,
});
setVisible(false);

View File

@ -2,7 +2,6 @@ import React, { useContext, useEffect } from 'react';
import { Button } from 'antd';
import { SchemaRenderer } from '../schema-renderer';
import { useForm } from '@formily/react';
import { Resource } from '../../resource';
import { useRequest } from 'ahooks';
import { VisibleContext } from '../../context';
import { ISchema } from '../../schemas';

View File

@ -1,4 +1,4 @@
import { SchemaRenderer } from '../../../';
import { SchemaRenderer, useResourceRequest } from '../../../';
import React, { useContext, useEffect } from 'react';
import { FormItem } from '@formily/antd';
import { action } from '@formily/reactive';
@ -58,13 +58,14 @@ const useFieldPermissions = () => {
}) || []
);
};
const resource = useResourceRequest({
associatedName: 'collections',
associatedKey: ctx.record.name,
resourceName: 'fields',
});
const service = useRequest(
() =>
Resource.make({
associatedName: 'collections',
associatedKey: ctx.record.name,
resourceName: 'fields',
}).list({
resource.list({
filter: {
state: 1,
},

View File

@ -6,6 +6,7 @@ import { Resource } from '../../../resource';
import { useContext } from 'react';
import { RoleContext } from '.';
import { useState } from 'react';
import { useResourceRequest } from '../../../constate';
const getKeys = (items: any[]) => {
const keys = [];
@ -31,7 +32,7 @@ export const MenuPermissionTable = observer((props) => {
},
);
console.log('allUiSchemaKyes', allUiSchemaKyes);
const resource = Resource.make({
const resource = useResourceRequest({
associatedName: 'roles',
associatedKey: role.name,
resourceName: 'ui_schemas',
@ -42,6 +43,10 @@ export const MenuPermissionTable = observer((props) => {
setUiSchemaKeys(getKeys(data));
},
});
const resource2 = useResourceRequest({
resourceName: 'roles',
resourceKey: role.name,
});
if (loading) {
return <Spin size={'large'} className={'nb-spin-center'} />;
}
@ -68,17 +73,13 @@ export const MenuPermissionTable = observer((props) => {
allUiSchemaKyes.length === uiSchemaKyes.length
}
onChange={async (e) => {
const resource = Resource.make({
resourceName: 'roles',
resourceKey: role.name,
});
if (e.target.checked) {
await resource.save({
await resource2.save({
ui_schemas: allUiSchemaKyes,
});
setUiSchemaKeys(allUiSchemaKyes);
} else {
await resource.save({
await resource2.save({
ui_schemas: [],
});
setUiSchemaKeys([]);

View File

@ -1,4 +1,4 @@
import { SchemaRenderer } from '../../../';
import { SchemaRenderer, useResourceRequest } from '../../../';
import React, { useContext, useEffect } from 'react';
import { FormItem } from '@formily/antd';
import { action } from '@formily/reactive';
@ -30,7 +30,7 @@ function RoleProvider(props) {
}
const useResource = () => {
const resource = Resource.make('roles');
const resource = useResourceRequest('roles');
return {
resource,
};
@ -39,7 +39,7 @@ const useResource = () => {
const useCollectionsResource = () => {
const descriptionsContext = useContext(DescriptionsContext);
console.log('descriptionsContext.service', descriptionsContext.service);
const resource = Resource.make('collections');
const resource = useResourceRequest('collections');
return {
resource,
};
@ -55,7 +55,7 @@ class ActionPermissionResource extends Resource {
const useActionPermissionSubmit = () => {
const form = useForm();
const role = useContext(RoleContext);
const resource = Resource.make({
const resource = useResourceRequest({
resourceName: 'roles',
resourceKey: role.name,
});
@ -72,9 +72,9 @@ const useActionPermissionResource = ({ onSuccess }) => {
console.log('RoleContext', role);
// const { props } = useTable();
const ctx = useContext(TableRowContext);
const resource = ActionPermissionResource.make({
const resource = useResourceRequest({
resourceName: 'action_permissions',
});
}, ActionPermissionResource);
const service = useRequest(
(params?: any) => {
return resource.list({
@ -120,7 +120,7 @@ const useActionPermissionResource = ({ onSuccess }) => {
const useDetailsResource = ({ onSuccess }) => {
const { props } = useTable();
const ctx = useContext(TableRowContext);
const resource = Resource.make({
const resource = useResourceRequest({
resourceName: 'roles',
resourceKey: ctx.record[props.rowKey],
});

View File

@ -1,15 +1,14 @@
import React, { useContext, useEffect } from 'react';
import { Button, Dropdown, Menu, Spin } from 'antd';
import { useHistory } from 'react-router-dom';
import { request } from '../../schemas';
import { useRequest } from 'ahooks';
import { Resource } from '../../resource';
import { createContext } from 'react';
import { useResourceRequest } from '../../constate';
export const SystemSettingsContext = createContext(null);
export function SystemSettingsProvider(props) {
const resource = Resource.make({
const resource = useResourceRequest({
resourceName: 'system_settings',
resourceKey: 1,
});
@ -25,7 +24,11 @@ export function SystemSettingsProvider(props) {
);
return (
<SystemSettingsContext.Provider value={{ service, resource }}>
{service.loading ? <Spin size={'large'} className={'nb-spin-center'} /> : props.children}
{service.loading ? (
<Spin size={'large'} className={'nb-spin-center'} />
) : (
props.children
)}
</SystemSettingsContext.Provider>
);
}

View File

@ -1,15 +1,17 @@
import React, { useContext, useEffect } from 'react';
import { Button, Dropdown, Menu, Select } from 'antd';
import { useHistory } from 'react-router-dom';
import { request, SchemaField } from '../../schemas';
import { SchemaField } from '../../schemas';
import { AuthContext, useCurrentUser } from './Auth';
import { FormButtonGroup, FormDrawer, FormLayout, Submit } from '@formily/antd';
import { useState } from 'react';
import { useClient } from '../../constate';
export const UserInfo = () => {
const history = useHistory();
const { service, currentUser } = useContext(AuthContext);
const [visible, setVisible] = useState(false);
const { request } = useClient();
return (
<Dropdown
visible={visible}

View File

@ -2,10 +2,11 @@ import React, { useContext, useEffect, useState } from 'react';
import { message, Spin } from 'antd';
import { Helmet } from 'react-helmet';
import { useRequest } from 'ahooks';
import { request, SchemaRenderer } from '../../schemas';
import { SchemaRenderer } from '../../schemas';
import { useForm } from '@formily/react';
import { useHistory, useLocation } from 'react-router-dom';
import { useSystemSettings } from '../admin-layout/SiteTitle';
import { useClient } from '../../constate';
function Div(props) {
return <div {...props}></div>;
@ -17,6 +18,7 @@ export function useLogin() {
const location = useLocation<any>();
const query = new URLSearchParams(location.search);
const redirect = query.get('redirect');
const { request } = useClient();
return {
async run() {
await form.submit();
@ -25,7 +27,7 @@ export function useLogin() {
data: form.values,
});
history.push(redirect || '/admin');
localStorage.setItem('NOCOBASE_TOKEN', data?.data?.token);
localStorage.setItem('NOCOBASE_TOKEN', data?.token);
},
};
}
@ -33,6 +35,7 @@ export function useLogin() {
export function useRegister() {
const form = useForm();
const history = useHistory();
const { request } = useClient();
return {
async run() {
await form.submit();

View File

@ -73,7 +73,11 @@ import { ISchema, FormilyISchema } from '../../schemas';
import { Resource } from '../../resource';
import { useRequest } from 'ahooks';
import { CascaderOptionType } from 'antd/lib/cascader';
import { useCollectionContext } from '../../constate';
import {
useClient,
useCollectionContext,
useResourceRequest,
} from '../../constate';
export const BlockContext = createContext({ dragRef: null });
@ -98,55 +102,56 @@ export const useAsyncDataSource = (service: any) => (field: any) => {
);
};
export const loadChinaRegionDataSource = async (field: ArrayField) => {
if (field.readPretty) {
return [];
}
const maxLevel = field.componentProps.maxLevel || 3;
const resource = Resource.make('china_regions');
const { data } = await resource.list({
perPage: -1,
filter: {
level: 1,
},
});
console.log('loadChinaRegions', data, field.value);
return (
data?.map((item) => {
if (maxLevel !== 1) {
item.isLeaf = false;
}
return item;
}) || []
);
};
export const loadChinaRegionData = (
selectedOptions: CascaderOptionType[],
field: ArrayField,
) => {
const maxLevel = field.componentProps.maxLevel || 3;
const targetOption = selectedOptions[selectedOptions.length - 1];
targetOption.loading = true;
const resource = Resource.make('china_regions');
resource
.list({
export const loadChinaRegionDataSource = function () {
const resource = useResourceRequest('china_regions');
return async (field: ArrayField) => {
if (field.readPretty) {
return [];
}
const maxLevel = field.componentProps.maxLevel || 3;
const { data } = await resource.list({
perPage: -1,
filter: {
parent_code: targetOption['code'],
level: 1,
},
})
.then((data) => {
targetOption.loading = false;
targetOption.children =
data?.data?.map((item) => {
if (maxLevel > item.level) {
item.isLeaf = false;
}
return item;
}) || [];
field.dataSource = [...field.dataSource];
});
console.log('loadChinaRegions', data, field.value);
return (
data?.map((item) => {
if (maxLevel !== 1) {
item.isLeaf = false;
}
return item;
}) || []
);
};
};
export const loadChinaRegionData = function () {
const resource = useResourceRequest('china_regions');
return (selectedOptions: CascaderOptionType[], field: ArrayField) => {
const maxLevel = field.componentProps.maxLevel || 3;
const targetOption = selectedOptions[selectedOptions.length - 1];
targetOption.loading = true;
resource
.list({
perPage: -1,
filter: {
parent_code: targetOption['code'],
},
})
.then((data) => {
targetOption.loading = false;
targetOption.children =
data?.data?.map((item) => {
if (maxLevel > item.level) {
item.isLeaf = false;
}
return item;
}) || [];
field.dataSource = [...field.dataSource];
});
};
};
const useChinaRegionFieldValue = (field: ArrayField) => {
@ -169,7 +174,7 @@ const useAssociationResource = (options) => {
schema['x-component-props'],
);
const { associatedName, resourceName } = schema['x-component-props'] || {};
const resource = Resource.make({
const resource = useResourceRequest({
associatedName,
resourceName,
associatedKey,
@ -188,6 +193,8 @@ export const SchemaField = createSchemaField({
Calendar,
Kanban,
useAsyncDataSource,
useClient,
useResourceRequest,
ChinaRegion: {
useFieldValue: useChinaRegionFieldValue,
loadData: loadChinaRegionData,

View File

@ -1,9 +1,10 @@
import React, { createContext, useContext } from 'react';
import { UseRequestProvider } from 'ahooks';
import { ISchema } from '../schemas';
import { Schema, useField } from '@formily/react';
import { Resource } from '../resource';
const ClientContext = createContext({
client: null,
});
const ClientContext = createContext<any>(null);
export function ClientProvider(props) {
const { client } = props;
@ -20,6 +21,71 @@ export function ClientProvider(props) {
);
}
export function useClient() {
return useContext(ClientContext);
export function useResourceRequest(options, ResourceClass?: any) {
const Cls = ResourceClass || Resource;
const { request } = useClient();
return Cls.make(options, request);;
}
export function useClient() {
const client = useContext(ClientContext);
const request = client.options.request;
return {
client,
request,
async createSchema(schema: ISchema) {
if (!schema) {
return;
}
if (!schema['key']) {
return;
}
return await request('ui_schemas:create', {
method: 'post',
data: schema.toJSON(),
});
},
async collectionMoveToAfter(source, target) {
if (source && target) {
return request(`collections:sort/${source}`, {
method: 'post',
data: {
field: 'sort',
target: {
name: target,
},
},
});
}
},
async updateSchema(schema: ISchema) {
if (!schema) {
return;
}
if (!schema['key']) {
return;
}
return await request(`ui_schemas:update/${schema.key}`, {
method: 'post',
data: Schema.isSchemaInstance(schema) ? schema.toJSON() : schema,
});
},
async removeSchema(schema: ISchema) {
if (!schema['key']) {
return;
}
await request('ui_schemas:destroy', {
method: 'post',
params: {
filter: {
key: schema['key'],
},
},
});
},
};
}

View File

@ -10,7 +10,7 @@ import {
AdminLayout,
AuthLayout,
RouteSchemaRenderer,
ClientProvider,
ConfigProvider,
ClientSDK
} from '../';
import { UseRequestProvider } from 'ahooks';
@ -66,8 +66,8 @@ const App = () => {
export default () => {
return (
<ClientProvider client={client}>
<ConfigProvider client={client}>
<App />
</ClientProvider>
</ConfigProvider>
);
}

View File

@ -1,10 +1,10 @@
import { useEffect } from 'react';
import { useCollectionContext } from '../constate';
import { useCollectionContext, useResourceRequest } from '../constate';
import { Resource } from '../resource';
export const useResource = (options: any = {}) => {
const { collection } = useCollectionContext();
const resource = Resource.make(collection?.name);
const resource = useResourceRequest(collection?.name);
useEffect(() => {
options.onSuccess && options.onSuccess({});
}, []);

View File

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

View File

@ -0,0 +1 @@
export default {}

View File

@ -0,0 +1 @@
export default {}

View File

@ -1,3 +1,4 @@
import { RequestMethod } from 'umi-request';
import { request } from './schemas';
export interface ResourceOptions {
@ -28,19 +29,21 @@ export interface ListOptions {
export class Resource {
public options: ResourceOptions;
public request: RequestMethod;
constructor(options: string | ResourceOptions) {
constructor(options: string | ResourceOptions, request?: any) {
if (typeof options === 'string') {
this.options = { resourceName: options }
} else {
this.options = options;
}
this.request = request || request;
}
sort(options) {
const { resourceName } = this.options;
const { resourceKey, target, field = 'sort' } = options;
return request(`${resourceName}:sort/${resourceKey}`, {
return this.request(`${resourceName}:sort/${resourceKey}`, {
method: 'post',
data: {
target,
@ -56,7 +59,7 @@ export class Resource {
if (associatedName && associatedKey) {
url = `${associatedName}/${associatedKey}/${resourceName}:list`;
}
return request(url, {
return this.request(url, {
method: 'get',
params: {
filter: decodeURIComponent(JSON.stringify({ and: [defaultFilter, filter].filter(Boolean) })),
@ -73,7 +76,7 @@ export class Resource {
return Promise.resolve({ data: {} });
}
const { defaultAppends = [], appends = [], ...others } = options;
return request(`${resourceName}:get/${resourceKey}`, {
return this.request(`${resourceName}:get/${resourceKey}`, {
params: {
...others,
'fields[appends]': defaultAppends.concat(appends).join(','),
@ -87,7 +90,7 @@ export class Resource {
if (associatedKey && associatedName) {
url = `${associatedName}/${associatedKey}/${url}`
}
return request(url, {
return this.request(url, {
method: 'post',
data: values,
});
@ -100,7 +103,7 @@ export class Resource {
if (associatedKey && associatedName) {
url = `${associatedName}/${associatedKey}/${url}`
}
return request(url, {
return this.request(url, {
method: 'post',
data: values,
});
@ -110,7 +113,7 @@ export class Resource {
const { resourceName } = this.options;
const { columns, ...others } = options;
const url = `${resourceName}:export`;
return request(url, {
return this.request(url, {
method: 'post',
params: {
columns: JSON.stringify(columns),
@ -143,7 +146,7 @@ export class Resource {
destroy(filter: any) {
const { resourceName } = this.options;
const url = `${resourceName}:destroy`;
return request(url, {
return this.request(url, {
method: 'get',
params: {
filter
@ -155,20 +158,20 @@ export class Resource {
const { associatedKey, associatedName, resourceName } = this.options;
const { resourceKey } = options;
let url = `${associatedName}/${associatedKey}/${resourceName}:toggle/${resourceKey}`;
return request(url, {
return this.request(url, {
method: 'post',
});
}
static make(options: null | string | Resource | ResourceOptions): Resource | null {
static make(options: null | string | Resource | ResourceOptions, request?: any): Resource | null {
if (typeof options === 'string') {
return new this({ resourceName: options });
return new this({ resourceName: options }, request);
}
if (options instanceof Resource) {
return options;
}
if (typeof options === 'object' && options.resourceName) {
return new this(options);
return new this(options, request);
}
console.warn('resource 初始化参数错误');
return null;

View File

@ -1,7 +1,7 @@
import { DndContext, DragOverlay } from '@dnd-kit/core';
import { observer, RecursionField, Schema } from '@formily/react';
import React, { useState } from 'react';
import { createSchema, ISchema, removeSchema, updateSchema } from '..';
import { ISchema } from '..';
import {
findPropertyByPath,
getSchemaPath,
@ -14,6 +14,7 @@ import SwitchMenuItem from '../../components/SwitchMenuItem';
import { uid } from '@formily/shared';
import { PlusOutlined } from '@ant-design/icons';
import { Droppable, SortableItem } from '../../components/Sortable';
import { useClient } from '../../constate';
export const ActionBar = observer((props: any) => {
const { align = 'top' } = props;
@ -39,6 +40,7 @@ export const ActionBar = observer((props: any) => {
path2,
);
};
const { updateSchema } = useClient();
const [dragOverlayContent, setDragOverlayContent] = useState('');
return (
@ -180,6 +182,7 @@ function AddActionButton() {
const displayed = useDisplayedMapContext();
const { appendChild, remove } = useDesignable();
const { schema, designable } = useDesignable();
const { createSchema, removeSchema } = useClient();
if (!designable) {
return null;
}
@ -216,7 +219,7 @@ function AddActionButton() {
))}
</Menu.ItemGroup>
<Menu.Divider />
<Menu.SubMenu title={'自定义'}>
<Menu.SubMenu disabled title={'自定义'}>
<Menu.Item style={{ minWidth: 120 }}></Menu.Item>
<Menu.Item></Menu.Item>
<Menu.Item></Menu.Item>

View File

@ -49,9 +49,7 @@ import {
import {
createCollectionField,
createOrUpdateCollection,
createSchema,
ISchema,
removeSchema,
useDesignable,
useSchemaPath,
} from '../';
@ -68,6 +66,7 @@ import {
useCollectionContext,
useCollectionsContext,
useDisplayedMapContext,
useClient,
} from '../../constate';
import SwitchMenuItem from '../../components/SwitchMenuItem';
import { BlockSchemaContext } from '../../context';
@ -955,6 +954,7 @@ AddNew.CardItem = observer((props: any) => {
const { schema, insertBefore, insertAfter, appendChild } = useDesignable();
const path = useSchemaPath();
const { collections = [], loading, refresh } = useCollectionsContext();
const { createSchema } = useClient();
return (
<Dropdown
trigger={['hover']}
@ -977,24 +977,24 @@ AddNew.CardItem = observer((props: any) => {
let collectionName = null;
let isNew = false;
if (['addNewTable', 'addNewForm'].includes(info.key)) {
const values = await FormDialog(`创建数据表`, () => {
return (
<FormLayout layout={'vertical'}>
<SchemaField schema={dbSchema} />
</FormLayout>
);
}).open({
initialValues: {
name: `t_${uid()}`,
fields: [],
},
});
await createOrUpdateCollection(values);
isNew = true;
data = generateCardItemSchema(
info.key === 'addNewTable' ? 'Table' : 'Form',
);
collectionName = values.name;
// const values = await FormDialog(`创建数据表`, () => {
// return (
// <FormLayout layout={'vertical'}>
// <SchemaField schema={dbSchema} />
// </FormLayout>
// );
// }).open({
// initialValues: {
// name: `t_${uid()}`,
// fields: [],
// },
// });
// await createOrUpdateCollection(values);
// isNew = true;
// data = generateCardItemSchema(
// info.key === 'addNewTable' ? 'Table' : 'Form',
// );
// collectionName = values.name;
} else if (info.key.startsWith('collection.')) {
const keys = info.key.split('.');
const component = keys.pop();
@ -1062,10 +1062,10 @@ AddNew.CardItem = observer((props: any) => {
</Menu.Item>
))}
</Menu.ItemGroup>
<Menu.Divider></Menu.Divider>
<Menu.Item icon={<PlusOutlined />} key={`addNew${view.key}`}>
{/* <Menu.Divider></Menu.Divider> */}
{/* <Menu.Item icon={<PlusOutlined />} key={`addNew${view.key}`}>
</Menu.Item>
</Menu.Item> */}
</Menu.SubMenu>
))}
{[
@ -1374,6 +1374,8 @@ AddNew.FormItem = observer((props: any) => {
const { collection, fields, refresh } = useCollectionContext();
const [visible, setVisible] = useState(false);
const displayed = useDisplayedMapContext();
const { createSchema, removeSchema } = useClient();
return (
<Dropdown
trigger={['hover']}
@ -1546,6 +1548,7 @@ AddNew.FormItem = observer((props: any) => {
</Menu.ItemGroup>
<Menu.Divider />
<Menu.SubMenu
disabled
popupClassName={'add-new-fields-popup'}
className={'sub-menu-add-new-fields'}
title={'添加字段'}
@ -1672,6 +1675,8 @@ AddNew.PaneItem = observer((props: any) => {
const useResource = `{{ ${blockSchema['x-component']}.useResource }}`;
console.log('AddNew.PaneItem.useResource', useResource);
const { collection, fields } = useCollectionContext();
const { createSchema } = useClient();
return (
<Dropdown
trigger={['hover']}

View File

@ -1,13 +1,13 @@
import { DndContext, DragOverlay } from '@dnd-kit/core';
import { observer, RecursionField, Schema } from '@formily/react';
import React, { useState } from 'react';
import { createSchema, ISchema, removeSchema, updateSchema } from '..';
import { ISchema } from '..';
import {
findPropertyByPath,
getSchemaPath,
useDesignable,
} from '../../components/schema-renderer';
import { DisplayedMapProvider, useDisplayedMapContext } from '../../constate';
import { useClient, DisplayedMapProvider, useDisplayedMapContext } from '../../constate';
import cls from 'classnames';
import { Button, Dropdown, Menu, Space } from 'antd';
import SwitchMenuItem from '../../components/SwitchMenuItem';
@ -39,6 +39,7 @@ export const ActionBar = observer((props: any) => {
path2,
);
};
const { updateSchema } = useClient();
const [dragOverlayContent, setDragOverlayContent] = useState('');
return (
@ -206,6 +207,8 @@ function AddActionButton() {
const displayed = useDisplayedMapContext();
const { appendChild, remove } = useDesignable();
const { schema, designable } = useDesignable();
const { createSchema, removeSchema } = useClient();
if (!designable) {
return null;
}

View File

@ -45,6 +45,7 @@ import {
CollectionProvider,
useCollectionContext,
useDisplayedMapContext,
useResourceRequest,
} from '../../constate';
import { FormButtonGroup, FormDialog, FormLayout, Submit } from '@formily/antd';
import IconPicker from '../../components/icon-picker';
@ -151,7 +152,7 @@ export const Calendar: any = observer((props: any) => {
}
return buf;
}, null);
const resource = Resource.make(collectionName);
const resource = useResourceRequest(collectionName);
const service = useRequest(
(params) => {
if (!collectionName) {
@ -271,7 +272,7 @@ Calendar.useResource = ({ onSuccess }) => {
const { props } = useCalendar();
const { collection } = useCollectionContext();
const record = useContext(RecordContext);
const resource = Resource.make({
const resource = useResourceRequest({
resourceName: collection?.name || props.collectionName,
resourceKey: record['id'],
});

View File

@ -7,7 +7,7 @@ import { uid } from '@formily/shared';
import { useField } from '@formily/react';
import { useEffect } from 'react';
import { useRequest } from 'ahooks';
import { Resource } from '@nocobase/client/src/resource';
import { Resource } from '../../../resource';
const options = [
{

View File

@ -43,7 +43,6 @@ import { clone, cloneDeep, get } from 'lodash';
import { useEffect } from 'react';
import { useRequest } from 'ahooks';
import {
collectionMoveToAfter,
createOrUpdateCollection,
deleteCollection,
} from '..';
@ -55,6 +54,7 @@ import {
} from '../../components/Sortable';
import { DndContext, DragOverlay } from '@dnd-kit/core';
import { createPortal } from 'react-dom';
import { useClient } from '../../constate';
interface SelectOptionProps {
id: any;
@ -100,6 +100,7 @@ export const DatabaseCollection = observer((props) => {
const [newValue, setNewValue] = useState('');
const { loading, refresh, collections = [] } = useCollectionsContext();
const [dragOverlayContent, setDragOverlayContent] = useState('');
const { collectionMoveToAfter } = useClient();
useEffect(() => {
field.setValue(collections);

View File

@ -20,7 +20,7 @@ export const chinaRegion: FieldOptions = {
'x-component': 'Cascader',
'x-component-props': {
changeOnSelectLast: false,
loadData: '{{ ChinaRegion.loadData }}',
loadData: '{{ ChinaRegion.loadData() }}',
labelInValue: true,
maxLevel: 3,
fieldNames: {
@ -30,8 +30,8 @@ export const chinaRegion: FieldOptions = {
},
},
'x-reactions': [
'{{ChinaRegion.useFieldValue}}',
'{{useAsyncDataSource(ChinaRegion.loadDataSource)}}',
'{{ ChinaRegion.useFieldValue }}',
'{{ useAsyncDataSource(ChinaRegion.loadDataSource()) }}',
],
'x-decorator': 'FormItem',
'x-designable-bar': 'Cascader.DesignableBar',

View File

@ -24,14 +24,9 @@ import { Droppable, SortableItem } from '../../components/Sortable';
import { uid } from '@formily/shared';
import cls from 'classnames';
import './style.less';
import {
createSchema,
FormilyISchema,
ISchema,
removeSchema,
updateSchema,
} from '..';
import { FormilyISchema, ISchema } from '..';
import { DesignableBar } from './DesignableBar';
import { useClient } from '../../constate';
const GridRowContext = createContext<any>(null);
const GridColContext = createContext<any>(null);
@ -60,6 +55,7 @@ export const Grid: any = observer((props: any) => {
const [clientWidths, setClientWidths] = useState([0, 0]);
const { addNewComponent } = props;
const AddNewComponent = useSchemaComponent(addNewComponent);
const { createSchema, removeSchema, updateSchema } = useClient();
// const sensors = useSensors(useSensor(MouseSensor));
const rows = Object.values(schema.properties || {}).filter((item) => {
return !item['x-hidden'];

View File

@ -15,9 +15,7 @@ import {
useSchemaPath,
SchemaField,
useDesignable,
removeSchema,
ISchema,
createSchema,
} from '../';
import get from 'lodash/get';
import { Button, Dropdown, Menu, Space } from 'antd';
@ -36,6 +34,7 @@ import {
useCollection,
useCollectionContext,
useDisplayedMapContext,
useClient,
} from '../../constate';
import { useTable } from '../table';
import SwitchMenuItem from '../../components/SwitchMenuItem';
@ -50,6 +49,7 @@ export const CardDesignableBar = observer((props) => {
const displayed = useDisplayedMapContext();
console.log('useDisplayedMapContext', schema);
const { service } = useKanban();
const { createSchema, removeSchema } = useClient();
return (
<div className={cls('designable-bar', { active: visible })}>
<span

View File

@ -29,7 +29,7 @@ import { useState } from 'react';
import { CSS } from '@dnd-kit/utilities';
import cls from 'classnames';
import './style.less';
import { CollectionProvider, useCollectionContext } from '../../constate';
import { CollectionProvider, useCollectionContext, useResourceRequest } from '../../constate';
import { Resource } from '../../resource';
import { useRequest } from 'ahooks';
import { Action } from '../action';
@ -167,7 +167,7 @@ const InternalKanban = observer((props: any) => {
);
const groups = groupBy(field.value, groupField.name);
const { collectionName } = props;
const resource = Resource.make(collectionName);
const resource = useResourceRequest(collectionName);
const service = useRequest(
(params) => {
if (!collectionName) {
@ -420,7 +420,7 @@ Kanban.useCreateResource = ({ onSuccess }) => {
const { props } = useKanban();
const column = useContext(KanbanColumnContext);
const { collection } = useCollectionContext();
const resource = Resource.make({
const resource = useResourceRequest({
resourceName: collection?.name || props.collectionName,
});
const groupField = props.groupField;
@ -476,7 +476,7 @@ Kanban.useRowResource = ({ onSuccess }) => {
const { props } = useKanban();
const { collection } = useCollectionContext();
const ctx = useContext(KanbanCardContext);
const resource = Resource.make({
const resource = useResourceRequest({
resourceName: collection?.name || props.collectionName,
resourceKey: ctx?.record?.id,
});
@ -518,7 +518,7 @@ Kanban.useSingleResource = ({ onSuccess }) => {
const { schema } = useDesignable();
const [visible] = useContext(VisibleContext);
const resource = Resource.make({
const resource = useResourceRequest({
resourceName: collection?.name || props.collectionName,
resourceKey: ctx?.record?.id,
});

View File

@ -52,7 +52,7 @@ import {
LockOutlined,
} from '@ant-design/icons';
import { IconPicker } from '../../components/icon-picker';
import { createSchema, removeSchema, updateSchema, useDefaultAction } from '..';
import { useDefaultAction } from '..';
import { useMount } from 'ahooks';
import './style.less';
import { findPropertyByPath, getSchemaPath, useSchemaPath } from '../../';
@ -70,6 +70,7 @@ import {
import { DndContext, DragOverlay } from '@dnd-kit/core';
import { createPortal } from 'react-dom';
import { Resource } from '../../resource';
import { useClient } from '../../constate';
export interface MenuContextProps {
schema?: Schema;
@ -93,6 +94,7 @@ const SideMenu = (props: any) => {
if (!child || child['x-component'] !== 'Menu.SubMenu') {
return null;
}
return (
<MenuModeContext.Provider value={'inline'}>
<AntdMenu
@ -157,6 +159,7 @@ export const Menu: any = observer((props: any) => {
const path = useSchemaPath();
const child = schema.properties && schema.properties[selectedKey];
const isSubMenu = child && child['x-component'] === 'Menu.SubMenu';
const { updateSchema } = useClient();
useMount(() => {
if (mode !== 'mix') {
@ -430,6 +433,7 @@ Menu.SubMenu = observer((props: any) => {
Menu.AddNew = observer((props: any) => {
const { designable, appendChild } = useDesignable(props.path);
const { createSchema, removeSchema, updateSchema } = useClient();
if (!designable) {
return null;
}
@ -686,6 +690,7 @@ Menu.DesignableBar = (props) => {
const isSubMenu = schema['x-component'] === 'Menu.SubMenu';
const ctx = useContext(MenuContext);
const mode = useContext(MenuModeContext);
const { createSchema, removeSchema, updateSchema } = useClient();
return (
<div className={cls('designable-bar', { active: visible })}>
@ -964,7 +969,7 @@ Menu.DesignableBar = (props) => {
</AntdMenu.Item>
</AntdMenu.SubMenu>
)}
<AntdMenu.Divider />
{/* <AntdMenu.Divider />
<AntdMenu.Item
icon={<LockOutlined />}
onClick={async () => {
@ -1021,7 +1026,7 @@ Menu.DesignableBar = (props) => {
}}
>
</AntdMenu.Item>
</AntdMenu.Item> */}
<AntdMenu.Divider />
<AntdMenu.Item
key={'delete'}

View File

@ -25,7 +25,7 @@ import { BlockSchemaContext, VisibleContext } from '../../context';
import { SchemaRenderer } from '../../components/schema-renderer';
import { uid } from '@formily/shared';
import { CollectionFieldContext } from '../table';
import { CollectionProvider, useCollectionContext } from '../../constate';
import { CollectionProvider, useCollectionContext, useResourceRequest } from '../../constate';
import { Resource } from '../../resource';
import { useRequest } from 'ahooks';
import constate from 'constate';
@ -469,7 +469,7 @@ Select.Drawer = connect(
Select.Drawer.useResource = ({ onSuccess }) => {
const { collection } = useCollectionContext();
const ctx = useContext(OptionTagContext);
const resource = Resource.make({
const resource = useResourceRequest({
resourceName: collection?.name,
resourceKey: ctx.data.id,
});

View File

@ -13,9 +13,6 @@ import { useContext } from 'react';
import { createContext } from 'react';
import {
useDesignable,
updateSchema,
removeSchema,
createSchema,
createCollectionField,
ISchema,
} from '..';
@ -55,6 +52,8 @@ import {
useCollectionContext,
useCollectionsContext,
useDisplayedMapContext,
useClient,
useResourceRequest,
} from '../../constate';
import { useResource as useGeneralResource } from '../../hooks/useResource';
import SwitchMenuItem from '../../components/SwitchMenuItem';
@ -409,6 +408,8 @@ function AddColumn() {
const { collection, fields, refresh } = useCollectionContext();
const displayed = useDisplayedMapContext();
const { service } = useTable();
const { createSchema, removeSchema, updateSchema } = useClient();
return (
<Dropdown
trigger={['hover']}
@ -579,6 +580,7 @@ function AddColumn() {
</Menu.ItemGroup>
<Menu.Divider />
<Menu.SubMenu
disabled
popupClassName={'add-new-fields-popup'}
title={'添加字段'}
>
@ -1208,6 +1210,8 @@ function AddActionButton() {
const displayed = useDisplayedMapContext();
const { appendChild, remove } = useDesignable();
const { schema, designable } = useDesignable();
const { createSchema, removeSchema, updateSchema } = useClient();
if (!designable || !schema['x-designable-bar']) {
return null;
}
@ -1324,6 +1328,7 @@ Table.ActionBar = observer((props: any) => {
path2,
);
};
const { createSchema, removeSchema, updateSchema } = useClient();
const [dragOverlayContent, setDragOverlayContent] = useState('');
return (
@ -1514,6 +1519,7 @@ Table.Filter.DesignableBar = () => {
const displayed = useDisplayedMapContext();
const { fields } = useCollectionContext();
const field = useField();
const { createSchema, removeSchema, updateSchema } = useClient();
let fieldNames = field.componentProps.fieldNames || [];
if (fieldNames.length === 0) {
fieldNames = fields.map((field) => field.name);
@ -1643,6 +1649,7 @@ Table.ExportActionDesignableBar = () => {
const displayed = useDisplayedMapContext();
const { fields } = useCollectionContext();
const field = useField();
const { createSchema, removeSchema, updateSchema } = useClient();
let fieldNames = field.componentProps.fieldNames || [];
if (fieldNames.length === 0) {
fieldNames = fields.map((field) => field.name);
@ -1786,6 +1793,8 @@ Table.Operation.DesignableBar = () => {
const groupPath = getSchemaPath(groupSchema);
const { schema, remove, refresh, appendChild } = useDesignable(groupPath);
const [visible, setVisible] = useState(false);
const { createSchema, removeSchema, updateSchema } = useClient();
const map = new Map();
schema.mapProperties((s) => {
if (!s['x-action-type']) {
@ -1862,6 +1871,7 @@ Table.Action.DesignableBar = () => {
const inActionBar = schema.parent['x-component'] === 'Table.ActionBar';
const displayed = useDisplayedMapContext();
const field = useField();
const { createSchema, removeSchema, updateSchema } = useClient();
const popupComponent = popupSchema?.['x-component'] || 'Action.Drawer';
return (
<div className={cls('designable-bar', { active: visible })}>
@ -2065,6 +2075,7 @@ Table.Column.DesignableBar = () => {
const displayed = useDisplayedMapContext();
const { getFieldsByCollection } = useCollectionsContext();
const collectionField = useContext(CollectionFieldContext);
const { createSchema, removeSchema, updateSchema } = useClient();
console.log('displayed.map', displayed.map);
return (
<div className={cls('designable-bar', { active: visible })}>
@ -2223,6 +2234,7 @@ Table.DesignableBar = observer((props) => {
field?.componentProps?.pagination?.defaultPageSize || 10;
const collectionName = field?.componentProps?.collectionName;
const { collection, fields } = useCollection({ collectionName });
const { createSchema, removeSchema, updateSchema } = useClient();
console.log({ collectionName });
return (
<div className={cls('designable-bar', { active: visible })}>
@ -2486,7 +2498,7 @@ Table.useResource = ({ onSuccess, manual = true }) => {
const { props } = useTable();
const { collection } = useCollectionContext();
const ctx = useContext(TableRowContext);
const resource = Resource.make({
const resource = useResourceRequest({
resourceName: collection?.name || props.collectionName,
resourceKey: ctx.record[props.rowKey],
});
@ -2530,7 +2542,7 @@ Table.useActionLogDetailsResource = ({ onSuccess }) => {
const { props } = useTable();
const { collection } = useCollectionContext();
const ctx = useContext(TableRowContext);
const resource = Resource.make({
const resource = useResourceRequest({
resourceName: 'action_logs',
resourceKey: ctx.record[props.rowKey],
});
@ -2581,7 +2593,7 @@ const useActionLogsResource = (options: any = {}) => {
}
}
const resource = ActionLogoResource.make('action_logs');
const resource = useResourceRequest('action_logs', ActionLogoResource);
return {
resource,

View File

@ -19,7 +19,7 @@ import { Schema, SchemaKey } from '@formily/react';
import { PlusOutlined, MenuOutlined } from '@ant-design/icons';
import { useState } from 'react';
import cls from 'classnames';
import { createSchema, removeSchema, updateSchema } from '..';
import { useClient } from '../../constate';
import './style.less';
import { uid } from '@formily/shared';
import { DragHandle, SortableItem } from '../../components/Sortable';
@ -64,6 +64,7 @@ export const Tabs: any = observer((props: any) => {
} = useDesignable();
const tabs = useTabs({ singleton });
const [dragOverlayContent, setDragOverlayContent] = useState('');
const { createSchema, removeSchema, updateSchema } = useClient();
const moveToAfter = (path1, path2) => {
if (!path1 || !path2) {
@ -226,6 +227,7 @@ Tabs.DesignableBar = () => {
const { schema, remove, refresh, insertAfter } = useDesignable();
const [visible, setVisible] = useState(false);
const field = useField();
const { createSchema, removeSchema, updateSchema } = useClient();
return (
<div className={cls('designable-bar', { active: visible })}>
<span
@ -275,6 +277,7 @@ Tabs.TabPane.DesignableBar = () => {
const { schema, remove, refresh, insertAfter } = useDesignable();
const [visible, setVisible] = useState(false);
const field = useField();
const { createSchema, removeSchema, updateSchema } = useClient();
return (
<div className={cls('designable-bar', { active: visible })}>
<span

View File

@ -22,7 +22,7 @@ function createApp(opts) {
acquire: 60000,
idle: 10000,
},
logging: process.env.DB_LOG_SQL === 'on' ? console.log : false,
// logging: process.env.DB_LOG_SQL === 'on' ? console.log : false,
define: {},
sync: {
force: false,
@ -31,6 +31,7 @@ function createApp(opts) {
},
},
},
bodyParser: false,
// dataWrapping: false,
resourcer: {
prefix: `/api/saas/${name}`,
@ -57,9 +58,9 @@ function createApp(opts) {
});
const plugins = [
'@nocobase/plugin-collections',
'@nocobase/plugin-ui-router',
'@nocobase/plugin-ui-schema',
'@nocobase/plugin-ui-router',
'@nocobase/plugin-collections',
'@nocobase/plugin-users',
'@nocobase/plugin-action-logs',
'@nocobase/plugin-file-manager',
@ -100,10 +101,22 @@ function multiApps({ getAppName }) {
await app.load();
apps.set(appName, app);
}
const app = apps.get(appName);
console.log('..........................start........................')
// 完全隔离的做法
const app = apps.get(appName) as Application;
const bodyParser = async (ctx2, next) => {
// @ts-ignore
ctx2.request.body = ctx.request.body || {};
await next();
};
app.middleware.unshift(bodyParser);
const handleRequest = app.callback();
await handleRequest(ctx.req, ctx.res);
const index = app.middleware.indexOf(bodyParser);
app.middleware.splice(index, 1);
console.log('..........................end........................')
// await next();
};
}

View File

@ -29,8 +29,8 @@ export class UISchema extends Model {
const data = _.cloneDeep(value);
const keys = [
'properties',
...Object.keys(this.rawAttributes),
...Object.keys(this.associations),
...Object.keys(this.rawAttributes||{}),
...Object.keys(this.associations||{}),
];
const attrs = _.pick(data, keys);
const options = _.omit(data, keys);

View File

@ -15,7 +15,7 @@ export async function check(ctx: Context, next: Next) {
export async function login(ctx: Context, next: Next) {
const { uniqueField = 'email', values } = ctx.action.params;
// console.log(values);
console.log('login.values', values);
if (!values[uniqueField]) {
ctx.throw(401, '请填写邮箱账号');
}
@ -36,9 +36,7 @@ export async function login(ctx: Context, next: Next) {
user.token = cryptoRandomString({ length: 20 });
await user.save();
}
ctx.body = {
data: user,
};
ctx.body = user;
await next();
}
@ -52,9 +50,7 @@ export async function register(ctx: Context, next: Next) {
const { values } = ctx.action.params;
try {
const user = await User.create(values);
ctx.body = {
data: user,
};
ctx.body = user;
} catch (error) {
if (error.errors) {
console.log(error.errors.map(data => data.message));

View File

@ -69,11 +69,13 @@ export class Application<
this.resourcer = new Resourcer({ ...options.resourcer });
this.cli = new Command();
this.use(
bodyParser({
...options.bodyParser,
}),
);
if (options.bodyParser !== false) {
this.use(
bodyParser({
...options.bodyParser,
}),
);
}
this.use(
cors({