gchust ae6b801132
feat: new block template plugin (#5920)
* feat: new block template plugin

* fix: build error

* fix: support nested template in blocks

* fix: remove undefined x-component properties from schema during template processing [skip ci]

* feat: reset action for template block

* fix: skip dnd error[skip ci]

* fix: dupliate template action[skip ci]

* fix: plugin not shown in test env

* fix: reset action not been shown

* fix: no permission error

* fix: loading error in production env

* fix: cross env dev error

* fix: blocks not shown in production env

* fix: insert template failing for the first time

* chore: merge

* fix: association record option not working correctly

* fix: setting error

* fix: setting

* fix: linkage error

* fix: association settings error

* fix: association record error

* feat: support edit form tpl

* fix: support more blocks

* fix: avoid nested template

* chore: re org codes

* chore: refactor[skip ci]

* chore: required comment for loading template [skip ci]

* refactor: simplify schema handling and add axios interceptors for template blocks[skip ci]

* fix: i18n [skip ci]

* feat: support showing template title in block

* fix: revert to template will lost the template title

* fix: delete operation removing blocks not working

* fix: template label

* fix: i18n error

* fix: form type should be shown only when current record

* feat: show template in the add new popup

* fix: form type switch should not be shown in add new block popup

* fix: missing i18n

* fix: associate fields should be shown only having current record

* fix: switching form not working in cn

* fix: incorrect form associate setting

* fix: uniq action issue

* fix: uniq fields/actions[skip ci]

* fix: style issue

* fix: error in configure actions

* fix: bulk destroy when no records selected

* fix: only show revert to template config in the block level

* fix: table refresh pagination incorrect after deletion

* fix: be able to input name of template

* fix: bulk destroy

* fix: reset setting will sync with template

* fix: block template table style

* fix: missing translatation

* fix: cache issue

* fix: blocks not shown in the popup after modifing the template

* feat: add search for template initializers

* fix: some blocks are missing template related setting

* fix: hide save as template in template configure view

* chore: revert incorrect commit

* fix: batchpatch error

* fix: mobile support

* fix: build error

* fix: limit one template one block

* feat: show revert to template for fields and actions

* fix: build error

* fix: revert to template not refreshing the ui for actions

* fix: revert to template not working for form

* fix: duplicate revert to setting setting item

* chore: rename reset to revert

* feat: disallow delete template's blocks in page

* feat: add colorTemplateBgSettingsHover for template block hover state

* fix: build error

* chore: hide convert to block template setting item for page

* fix: data template should be hidden in edit form

* fix: fields switch should be disabled

* chore: rename var [skip ci]

* fix: should not be able remove field in block

* fix: after revert settings, is able to remove block in template

* fix: revert settings

* fix: nested template block error

* refactor: cache

* fix: template key has not been validated in client side

* fix: only show template that has been configured

* feat: show template name in edit form

* chore: update package.json

* fix: duplicated fields after dnd in form

* fix: duplicated fields shown in form

* chore: hide old block template menu

* feat: support mobile block template [skip ci]

* fix: filter for type options [skip ci]

* fix: incorrect create new  button style [skip ci]

* feat: add mobile block support

* fix: can't restrict one template one block [skip ci]

* fix: template title not synced after editing template

* fix: keep block deletion should transform the template block to normal block

* fix: insert template fails for the first time

* fix: destroy error

* fix: deploy failure [skip ci]

* fix: destory error in subapp with sub domain

* fix: destroy error

* fix: popup action should be hidden in create new form [skip ci]

* fix: possible crash when converting template to block [skip ci]

* fix: some properties have not been revert in real time

* fix: fitler action condition error

* fix: useDataBlockResource error

* fix: revert settings not refresh filter action form [skip ci]

* fix: new template properties clear

* fix: custom request action can't be shown

* fix: template tab should not be removable

* fix: duplicated delete action in table column

* fix: field link popup not shown in block template page

* fix: page configure link not working correctly

* chore: revert useContextVaraible [skip ci]

* fix(popup): fix configured page not taking effect

* fix: add blocks  button shown in block settings

* fix: only loading 20 templates

* fix: add block icon has been shown [skip ci]

* fix: association not shown in block template configure page

* fix: edit association form error [skip ci]

* fix: console error [skip ci]

* fix: only current field has been refreshed after revert to template [skip ci]

* chore: remove incorrect commit file [skip ci]

* fix: some action delete action still be shown for template block [skip ci]

* fix: template block style[skip ci]

* fix: keep position when rever setting[skip ci]

* fix: revert to template error when already deleted from block [skip ci]

* fix: revert still works even the template has been deleted

* fix: popup not shown as template block [skip ci]

* fix: bulk destory can't keep blocks[skip ci]

* fix: after dnd some unique blocks may be duplicated in the client [skip ci]

* fix: duplicate fields error in form

* fix: revert setting incorrect [skip ci]

* fix: duplicated sub form

* refactor: simplify by moving template loading to backend [skip  ci]

* fix: failing to add template block [skip ci]

* fix: assign fields values in bulk update action [skip ci]

* fix: can't add fields in nester popup subform [skip ci]

* fix: sub-table sub-form not merged correctly [skip ci]

* fix: subtable not highlight unique fields correctly [skip ci]

* fix: block title will not be synced correctly [skip ci]

* fix: can't add block into template [skip ci]

* fix: revert setting not refreshed [skip ci]

* fix: block template title not correct in some cases [skip ci]

* fix: field link's popup merge[skip ci]

* fix: cannot read properties of null in some popup [skip ci]

* fix: position of ui components have not been saved after dnd [skip ci]

* fix: dnd position not saved correctly in some cases [skip ci]

* fix: dnd undefined type error [skip ci]

* fix: can't swtich form type

* fix: some form type switch error [skip ci]

* fix: hide chart block from templates [skip ci]

* feat: support hide some blocks from template [skip ci]

* fix: react error for revert submit button of edit form [skip ci]

* fix: hide workflow and approvar block from template

* fix: hide connect data block from template [skip ci]

* fix: error [skip ci]

* fix: associate record options have not been shown for create form [skip ci]

* fix: creat form popup will be shown after refresh if switch form type [skip ci]

* fix: associate record settings error [skip ci]

* fix: mobile template setting page can not open popup [skip ci]

* fix: mobile content overflow [skip ci]

* chore: update templates menu style [skip ci]

* fix: unique disassociate btn [skip ci]

* feat: save collection and component info while update template

* fix: clear template context info after remove block

* chore: update template block entry point

* fix: incorrect association field template block [skip ci]

* fix: template title only shown after refresh

* fix: tooltip can't be revert correctly after moving entry to submenu [skip ci]

* fix: incorrect behavior after adding collection submenu entries [skip ci]

* fix: edit form support

* fix: support current details [skip ci]

* fix: edit form btn not correct [skip ci]

* fix: create form action params [skip ci]

* fix: hide template menu entry in block template configure page [skip ci]

* fix: incorrect association [skip ci]

* fix: nested template [skip ci]

* fix: can't insert template in mobile [skip ci]

* fix: association title not correct for details block [skip ci]

* chore: remove incorrect submodules commit [skip ci]

* fix: create form is using post method [skip ci]

* fix: association hasone and belongsto details block error [skip ci]

* fix: edit form not able load data [skip ci]

* chore: hide tab bar in mobile template configure page [skip ci]

* fix: don't show no accessible pages for template configure page [skip ci]

* fix: not able to see template list on the first time opening popup [skip ci]

* fix: able to remove related approvals template block [skip ci]

* fix: data not loading for details hasone relationship [skip ci]

* fix: dnd position may not be saved [skip ci]

* fix: multi-step-form is able to delete template step[skip ci]

* fix: hide rever setting in multi step form step name [skip ci]

* fix: extrol wrap when adding blocks from template [skip ci]

* fix: nested schema patch [skip ci]

* fix: x-acl-action not correct[skip ci]

* fix: diassociate action should be unique [skip ci]

* fix: disassociate action not unique [skip ci]

* fix: mobile popup by url not working [skip ci]

* chore: code clean

* chore: update delete setting position [skip ci]

* chore: keep revert btn position consistant in all places [skip ci]

* chore: hide template from workflow setting page [skip ci]

* chore: update setting menu icon [skip ci]

* chore: rename provider name to avoid duplicated with core [skip ci]

* chore: move block template menu to an upper level [skip ci]

* fix: hide other block templates menu [skip ci]

* fix: hide other blocks when creating template

* fix: duplicate revert to template option

* fix: mail manager template block not shown in popup

* fix: main block not showing in popup

* chore: mark old template features as deprecated

* chore: hide deprecated templates in block template configure page

* fix: read x-virtual from null

* fix: ci test error

* fix: skip old templates e2e test cases

* fix: skip old templates e2e test cases

---------

Co-authored-by: Zeke Zhang <958414905@qq.com>
2025-02-20 22:23:07 +08:00

219 lines
7.9 KiB
TypeScript

/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import {
SchemaSettingsItem,
useAPIClient,
useDesignable,
useFormBlockProps,
usePlugin,
SchemaSettingsDivider,
} from '@nocobase/client';
import { useFieldSchema, useForm, useField } from '@formily/react';
import { App } from 'antd';
import React from 'react';
import _ from 'lodash';
import { blockKeepProps, convertTplBlock, formSchemaPatch } from '../initializers/TemplateBlockInitializer';
import { Schema } from '@formily/json-schema';
import { useT } from '../locale';
import PluginBlockTemplateClient from '..';
import { addToolbarClass, syncExtraTemplateInfo } from '../utils/template';
import { uid } from '@nocobase/utils/client';
const findInsertPosition = (parentSchema, uid) => {
const postion = {
insertPosition: 'beforeBegin',
insertTarget: null,
};
const properties = Object.values(parentSchema.properties || {}).sort((a, b) => {
return (a as any)['x-index'] - (b as any)['x-index'];
});
for (let i = 0; i < properties.length; i++) {
const property = properties[i];
if ((property as any)['x-uid'] === uid) {
postion.insertPosition = 'beforeBegin';
if (i === properties.length - 1) {
postion.insertPosition = 'beforeEnd';
postion.insertTarget = parentSchema['x-uid'];
} else {
postion.insertPosition = 'beforeBegin';
postion.insertTarget = (properties[i + 1] as any)['x-uid'];
}
}
}
return postion;
};
const findParentRootTemplateSchema = (fieldSchema) => {
if (!fieldSchema) {
return null;
}
if (fieldSchema['x-template-root-uid']) {
return fieldSchema;
} else {
return findParentRootTemplateSchema(fieldSchema.parent);
}
};
export const RevertSetting = () => {
const { refresh, remove } = useDesignable();
const plugin = usePlugin(PluginBlockTemplateClient);
const t = useT();
const api = useAPIClient();
const form = useForm();
const field = useField();
// const { runAsync } = useDataBlockRequest();
const { form: blockForm } = useFormBlockProps();
const fieldSchema = useFieldSchema();
const { modal, message } = App.useApp();
return (
<>
<SchemaSettingsDivider />
<SchemaSettingsItem
title={t('Revert to template')}
onClick={() => {
modal.confirm({
title: t('Revert to template'),
content: t('Are you sure you want to revert all changes from the template?'),
...confirm,
async onOk() {
const templateSchemaId = _.get(fieldSchema, 'x-template-uid');
const res = await api.request({
url: `/uiSchemas:getJsonSchema/${templateSchemaId}`,
});
const templateSchema = res.data?.data;
if (!templateSchema?.['x-uid']) {
// this means the template has already been deleted
remove(null, {
removeParentsIfNoChildren: true,
breakRemoveOn: {
'x-component': 'Grid',
},
});
refresh({ refreshParentSchema: true });
form.reset();
form.clearFormGraph();
blockForm?.clearFormGraph();
message.success(t('Reset successfully'), 0.2);
return;
}
const rootSchema = findParentRootTemplateSchema(fieldSchema);
const isRoot = rootSchema === fieldSchema;
if (isRoot) {
plugin.setTemplateCache(templateSchema);
} else {
// patch the edit form button schema, keep same as the form
if (fieldSchema['x-settings']?.includes('updateSubmit')) {
templateSchema['x-settings'] = 'actionSettings:updateSubmit';
templateSchema['x-use-component-props'] = 'useUpdateActionProps';
}
}
// patch filter block
// remove this when multiple blocks template supported
if (fieldSchema['x-filter-targets']) {
templateSchema['x-filter-targets'] = fieldSchema['x-filter-targets'];
}
const newSchema = convertTplBlock(
templateSchema,
false,
isRoot,
rootSchema?.['x-uid'],
rootSchema?.['x-block-template-key'],
);
newSchema['x-index'] = fieldSchema['x-index'];
for (const p of blockKeepProps) {
if (_.hasIn(fieldSchema, p)) {
_.set(newSchema, p, _.get(fieldSchema, p));
}
}
if (
fieldSchema['x-decorator'] === 'FormBlockProvider' &&
fieldSchema['x-use-decorator-props'] === 'useEditFormBlockDecoratorProps'
) {
formSchemaPatch(newSchema, {
collectionName: fieldSchema['x-decorator-props']['collection'],
dataSourceName: fieldSchema['x-decorator-props']['dataSource'],
association: fieldSchema['x-decorator-props']['association'],
currentRecord: true,
});
}
// remove old schema
const position = findInsertPosition(fieldSchema.parent, fieldSchema['x-uid']);
await api.request({
url: `/uiSchemas:remove/${fieldSchema['x-uid']}`,
});
// insertAdjacent
const schema = new Schema(newSchema);
schema.name = fieldSchema.name;
await api.request({
url: `/uiSchemas:insertAdjacent/${position.insertTarget}?position=${position.insertPosition}`,
method: 'post',
data: {
schema,
},
});
// this is a hack to make the schema component refresh to the new schema
fieldSchema.toJSON = () => {
let ret;
if (schema['x-template-root-uid'] || fieldSchema.parent?.['x-template-root-uid']) {
ret = schema.toJSON();
} else {
const mergedSchema = _.merge(templateSchema, schema.toJSON());
ret = mergedSchema;
}
addToolbarClass(ret);
syncExtraTemplateInfo(ret, plugin.templateInfos, plugin.savedSchemaUids);
return ret;
};
refresh({ refreshParentSchema: true });
// set componentProps, otherwise some components props will not be refreshed
field['componentProps'] = {
...templateSchema['x-component-props'],
key: uid(),
};
if (field.parent?.['componentProps']) {
field.parent['componentProps'] = {
...field.parent['componentProps'],
key: uid(),
};
}
// set decoratorProps, otherwise title will not be refreshed
field['decoratorProps'] = {
...field['decoratorProps'],
...templateSchema['x-decorator-props'],
key: uid(),
};
if (field.parent?.['decoratorProps']) {
field.parent['decoratorProps'] = {
...field.parent['decoratorProps'],
key: uid(),
};
}
form.reset();
blockForm?.reset();
form.clearFormGraph('*', false);
blockForm?.clearFormGraph('*', false);
message.success(t('Reset successfully'), 0.2);
},
});
}}
>
{t('Revert to template')}
</SchemaSettingsItem>
</>
);
};