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 = [ const plugins = [
'@nocobase/plugin-saas', '@nocobase/plugin-saas',
'@nocobase/plugin-collections',
'@nocobase/plugin-ui-router',
'@nocobase/plugin-ui-schema', '@nocobase/plugin-ui-schema',
'@nocobase/plugin-ui-router',
'@nocobase/plugin-collections',
'@nocobase/plugin-users', '@nocobase/plugin-users',
'@nocobase/plugin-action-logs', '@nocobase/plugin-action-logs',
'@nocobase/plugin-file-manager', '@nocobase/plugin-file-manager',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -73,7 +73,11 @@ import { ISchema, FormilyISchema } from '../../schemas';
import { Resource } from '../../resource'; import { Resource } from '../../resource';
import { useRequest } from 'ahooks'; import { useRequest } from 'ahooks';
import { CascaderOptionType } from 'antd/lib/cascader'; import { CascaderOptionType } from 'antd/lib/cascader';
import { useCollectionContext } from '../../constate'; import {
useClient,
useCollectionContext,
useResourceRequest,
} from '../../constate';
export const BlockContext = createContext({ dragRef: null }); export const BlockContext = createContext({ dragRef: null });
@ -98,55 +102,56 @@ export const useAsyncDataSource = (service: any) => (field: any) => {
); );
}; };
export const loadChinaRegionDataSource = async (field: ArrayField) => { export const loadChinaRegionDataSource = function () {
if (field.readPretty) { const resource = useResourceRequest('china_regions');
return []; return async (field: ArrayField) => {
} if (field.readPretty) {
const maxLevel = field.componentProps.maxLevel || 3; return [];
const resource = Resource.make('china_regions'); }
const { data } = await resource.list({ const maxLevel = field.componentProps.maxLevel || 3;
perPage: -1, const { data } = await resource.list({
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({
perPage: -1, perPage: -1,
filter: { 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) => { const useChinaRegionFieldValue = (field: ArrayField) => {
@ -169,7 +174,7 @@ const useAssociationResource = (options) => {
schema['x-component-props'], schema['x-component-props'],
); );
const { associatedName, resourceName } = schema['x-component-props'] || {}; const { associatedName, resourceName } = schema['x-component-props'] || {};
const resource = Resource.make({ const resource = useResourceRequest({
associatedName, associatedName,
resourceName, resourceName,
associatedKey, associatedKey,
@ -188,6 +193,8 @@ export const SchemaField = createSchemaField({
Calendar, Calendar,
Kanban, Kanban,
useAsyncDataSource, useAsyncDataSource,
useClient,
useResourceRequest,
ChinaRegion: { ChinaRegion: {
useFieldValue: useChinaRegionFieldValue, useFieldValue: useChinaRegionFieldValue,
loadData: loadChinaRegionData, loadData: loadChinaRegionData,

View File

@ -1,9 +1,10 @@
import React, { createContext, useContext } from 'react'; import React, { createContext, useContext } from 'react';
import { UseRequestProvider } from 'ahooks'; import { UseRequestProvider } from 'ahooks';
import { ISchema } from '../schemas';
import { Schema, useField } from '@formily/react';
import { Resource } from '../resource';
const ClientContext = createContext({ const ClientContext = createContext<any>(null);
client: null,
});
export function ClientProvider(props) { export function ClientProvider(props) {
const { client } = props; const { client } = props;
@ -20,6 +21,71 @@ export function ClientProvider(props) {
); );
} }
export function useClient() { export function useResourceRequest(options, ResourceClass?: any) {
return useContext(ClientContext); 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, AdminLayout,
AuthLayout, AuthLayout,
RouteSchemaRenderer, RouteSchemaRenderer,
ClientProvider, ConfigProvider,
ClientSDK ClientSDK
} from '../'; } from '../';
import { UseRequestProvider } from 'ahooks'; import { UseRequestProvider } from 'ahooks';
@ -66,8 +66,8 @@ const App = () => {
export default () => { export default () => {
return ( return (
<ClientProvider client={client}> <ConfigProvider client={client}>
<App /> <App />
</ClientProvider> </ConfigProvider>
); );
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,7 +22,7 @@ function createApp(opts) {
acquire: 60000, acquire: 60000,
idle: 10000, idle: 10000,
}, },
logging: process.env.DB_LOG_SQL === 'on' ? console.log : false, // logging: process.env.DB_LOG_SQL === 'on' ? console.log : false,
define: {}, define: {},
sync: { sync: {
force: false, force: false,
@ -31,6 +31,7 @@ function createApp(opts) {
}, },
}, },
}, },
bodyParser: false,
// dataWrapping: false, // dataWrapping: false,
resourcer: { resourcer: {
prefix: `/api/saas/${name}`, prefix: `/api/saas/${name}`,
@ -57,9 +58,9 @@ function createApp(opts) {
}); });
const plugins = [ const plugins = [
'@nocobase/plugin-collections',
'@nocobase/plugin-ui-router',
'@nocobase/plugin-ui-schema', '@nocobase/plugin-ui-schema',
'@nocobase/plugin-ui-router',
'@nocobase/plugin-collections',
'@nocobase/plugin-users', '@nocobase/plugin-users',
'@nocobase/plugin-action-logs', '@nocobase/plugin-action-logs',
'@nocobase/plugin-file-manager', '@nocobase/plugin-file-manager',
@ -100,10 +101,22 @@ function multiApps({ getAppName }) {
await app.load(); await app.load();
apps.set(appName, app); 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(); const handleRequest = app.callback();
await handleRequest(ctx.req, ctx.res); 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 data = _.cloneDeep(value);
const keys = [ const keys = [
'properties', 'properties',
...Object.keys(this.rawAttributes), ...Object.keys(this.rawAttributes||{}),
...Object.keys(this.associations), ...Object.keys(this.associations||{}),
]; ];
const attrs = _.pick(data, keys); const attrs = _.pick(data, keys);
const options = _.omit(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) { export async function login(ctx: Context, next: Next) {
const { uniqueField = 'email', values } = ctx.action.params; const { uniqueField = 'email', values } = ctx.action.params;
// console.log(values); console.log('login.values', values);
if (!values[uniqueField]) { if (!values[uniqueField]) {
ctx.throw(401, '请填写邮箱账号'); ctx.throw(401, '请填写邮箱账号');
} }
@ -36,9 +36,7 @@ export async function login(ctx: Context, next: Next) {
user.token = cryptoRandomString({ length: 20 }); user.token = cryptoRandomString({ length: 20 });
await user.save(); await user.save();
} }
ctx.body = { ctx.body = user;
data: user,
};
await next(); await next();
} }
@ -52,9 +50,7 @@ export async function register(ctx: Context, next: Next) {
const { values } = ctx.action.params; const { values } = ctx.action.params;
try { try {
const user = await User.create(values); const user = await User.create(values);
ctx.body = { ctx.body = user;
data: user,
};
} catch (error) { } catch (error) {
if (error.errors) { if (error.errors) {
console.log(error.errors.map(data => data.message)); console.log(error.errors.map(data => data.message));

View File

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