nocobase/packages/core/client/src/schema-templates/SchemaTemplateManagerProvider.tsx
ChengLei Shao 39ee4b8873
feat: application supervisor (#2353)
* chore: skip sync localization-management plugin enable status

* chore: unSyncPlugins array

* chore: remove install at dev

* chore: gateway and supervisor

* chore: install command

* chore: remove app manager

* chore: share plugin

* chore: wsserver

* chore: websocket server

* chore: websocket connection with app status

* feat: socket server at gateway

* chore: loading message

* chore: ready status

* chore: handle app error

* feat: restart app at supervisor

* feat: health check endpoint

* chore: test

* chore: test

* chore: test

* chore: test

* chore: build

* chore: test

* chore: build

* chore: application ready status

* chore: error message

* chore: handle application error

* chore: handle error in load

* chore: report error in websocket

* chore: ws error

* chore: ws error

* chore: typo

* chore: switch app ready status at install

* chore: test

* chore: test

* chore: test

* chore: test

* feat: add WebSocket client

* chore: start gateway

* chore: start command in application

* chore: code

* chore: pm command

* chore: run start after load sub app

* feat: application fsm

* refactor: server life cycle (#2402)

* refactor: server life cycle

* fix: test error

* fix: test error

* fix: test error

* fix: app.start

* fix: cronjob stop

* fix: db.sync before upgrade

* fix: pm.get

* fix: test error

* fix: test error

* fix: test error

* test: add test cases

* fix: remove PluginType

* chore: start application after install

* chore: fsm

* chore: working status

* chore: working command

* chore: remove swith app ready status

* chore: switch status after working done

* chore: ws status

* chore: gateway error

* chore: test

* chore: stopping status

* chore: test

* chore: test

* feat: app proxy

* chore: application destory

* chore: application message changed with status

* chore: test

* chore: test timeout

* test: remove listener add by plugin

* test: remove listener add by plugin

* chore: test

* feat: app maintaining

* fix: add AppMaintainingDialog

* feat: off

* test: gateway http response

* test: gateway with errors

* chore: unkown error

* chore: websocket message

* chore: ws message

* chore: code

* chore: error format

* chore: delay app load

* feat: improve code

* chore: application initializing status

* chore: supervisor with app status

* chore: command status response

* chore: test

* chore: ws message

* chore: test

* fix: command running message

* feat: restart

* chore: code

* chore: status transition

* chore: test

* fix: improve code

* fix: error

* fix: restart

* fix: command

* chore: reset client app tag when app selector changed

* chore: error report

* fix: application status

* fix: build

* chore: disable help command dispatch

* chore: test

* test: multi apps test

* fix: improve code

* fix: test

* fix: test

* fix: multi apps single running

* fix: improve code

* fix: app status

* chore: move plugin static file to gateway

* feat: static file handler

* chore: test

* chore: enable plugins in share collection

* chore: gateway serve upload files

* fix: improve client

* chore: ws nginx config

* fix: gateway with naonoid

* fix: db sync

* fix: loading

* fix: ping

* fix: locale load

* fix: yarn start --quickstart

* fix: add debug log

* chore: application started event

* chore: running working message payload

* chore: nginx log

* chore: nginxconf

* chore: working message log

* feat: logs

* feat: compression

* fix: remove koa-send and koa-static

* fix: remove -e

* fix: remove nginx

* fix: remove -e

* fix: __appName

* chore: delay install sub application

* chore: sync plugin status

* fix: boot sub app

* fix: main app reload

* fix: test

* fix: app status

* test: field.bind block event loop

* feat: newrelic

* feat: debug log

* chore: upgrade

* fix(file-manager): test error

* fix: default app selector

* fix: reload after maintained

* chore: boot sub app

* chore: application destroy command

* chore: destroy command

* chore: clean code

* chore: package.json

* chore: maintaining message

* chore: test

* fix: collection.sync

* feat: add test cases

* chore: application

* fix: test error

* feat: improve codes and add test cases

* fix: test error

* fix: pm enable and disable

* fix: pm.disable

* feat: update docs

* chore: update dockerfile

---------

Co-authored-by: chenos <chenlinxh@gmail.com>
2023-08-24 17:47:45 +08:00

171 lines
5.2 KiB
TypeScript

import { ISchema, useFieldSchema } from '@formily/react';
import { uid } from '@formily/shared';
import { cloneDeep } from 'lodash';
import React, { ReactNode, createContext, useContext, useMemo } from 'react';
import { useAPIClient, useRequest } from '../api-client';
import { Plugin } from '../application/Plugin';
import { useAppSpin } from '../application/hooks/useAppSpin';
import { useCollectionManager } from '../collection-manager';
import { BlockTemplate } from './BlockTemplate';
export const SchemaTemplateManagerContext = createContext<any>({});
export const SchemaTemplateManagerProvider: React.FC<any> = (props) => {
const { templates, refresh } = props;
return (
<SchemaTemplateManagerContext.Provider value={{ templates, refresh }}>
{props.children}
</SchemaTemplateManagerContext.Provider>
);
};
const regenerateUid = (s: ISchema) => {
s['name'] = s['x-uid'] = uid();
Object.keys(s.properties || {}).forEach((key) => {
regenerateUid(s.properties[key]);
});
};
export const useSchemaTemplate = () => {
const { getTemplateBySchema, templates } = useSchemaTemplateManager();
const fieldSchema = useFieldSchema();
const schemaId = fieldSchema['x-uid'];
const templateKey = fieldSchema['x-template-key'];
// console.log('templateKey', { schemaId, templateKey })
return useMemo(() => getTemplateBySchema(fieldSchema), [schemaId, templateKey]);
};
export const useSchemaTemplateManager = () => {
const { getInheritCollections } = useCollectionManager();
const { refresh, templates = [] } = useContext(SchemaTemplateManagerContext);
const api = useAPIClient();
return {
templates,
refresh,
async getTemplateSchemaByMode(options) {
const { mode, template } = options;
if (mode === 'copy') {
const { data } = await api.request({
url: `/uiSchemas:getJsonSchema/${template.uid}?includeAsyncNode=true`,
});
const s = data?.data || {};
regenerateUid(s);
return cloneDeep(s);
} else if (mode === 'reference') {
return {
type: 'void',
'x-component': 'BlockTemplate',
'x-component-props': {
templateId: template.key,
},
};
}
},
async copyTemplateSchema(template) {
const { data } = await api.request({
url: `/uiSchemas:getJsonSchema/${template.uid}?includeAsyncNode=true`,
});
const s = data?.data || {};
regenerateUid(s);
return cloneDeep(s);
},
async saveAsTemplate(values) {
const { uid: schemaId } = values;
const key = uid();
await api.resource('uiSchemas').saveAsTemplate({
filterByTk: schemaId,
values: {
key,
...values,
},
});
await refresh();
return { key };
},
getTemplateBySchema(schema) {
const templateKey = schema['x-template-key'];
if (templateKey) {
return templates?.find((template) => template.key === templateKey);
}
const schemaId = schema['x-uid'];
if (schemaId) {
return templates?.find((template) => template.uid === schemaId);
}
},
getTemplateBySchemaId(schemaId) {
if (!schemaId) {
return null;
}
return templates?.find((template) => template.uid === schemaId);
},
getTemplateById(key) {
return templates?.find((template) => template.key === key);
},
getTemplatesByCollection(collectionName: string, resourceName: string = null) {
const parentCollections = getInheritCollections(collectionName);
const totalCollections = parentCollections.concat([collectionName]);
const items = templates?.filter?.((template) => totalCollections.includes(template.collectionName));
return items || [];
},
getTemplatesByComponentName(componentName: string): Array<any> {
const items = templates?.filter?.((template) => template.componentName === componentName);
return items || [];
},
};
};
export const RemoteSchemaTemplateManagerProvider: React.FC<{ children?: ReactNode }> = (props) => {
const api = useAPIClient();
const { render } = useAppSpin();
const options = {
resource: 'uiSchemaTemplates',
action: 'list',
params: {
appends: ['collection'],
paginate: false,
},
};
const service = useRequest<{
data: any[];
}>(options);
if (service.loading) {
return render();
}
return (
<SchemaTemplateManagerProvider
refresh={async () => {
const { data } = await api.request(options);
service.mutate(data);
}}
templates={service?.data?.data}
>
{props.children}
</SchemaTemplateManagerProvider>
);
};
export class RemoteSchemaTemplateManagerPlugin extends Plugin {
async load() {
this.addRoutes();
this.addComponents();
this.app.use(RemoteSchemaTemplateManagerProvider);
}
addComponents() {
this.app.addComponents({
BlockTemplate,
});
}
addRoutes() {
this.app.router.add('admin.plugins.block-templates', {
path: '/admin/plugins/block-templates',
Component: 'BlockTemplatePage',
});
this.app.router.add('admin.plugins.block-templates-key', {
path: '/admin/plugins/block-templates/:key',
Component: 'BlockTemplateDetails',
});
}
}