feat: workbench block (#4555)

* feat: workbench block

* feat: mobilePage

* fix: update WorkbenchAction

* feat: improve code

* fix: iconColor

* fix: Improve code

* feat: Improve code

* fix: version
This commit is contained in:
chenos 2024-06-12 09:40:14 +08:00 committed by GitHub
parent 431df8ec98
commit 585fea650e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 884 additions and 5 deletions

View File

@ -2,9 +2,7 @@
"version": "1.0.1-alpha.3",
"npmClient": "yarn",
"useWorkspaces": true,
"npmClientArgs": [
"--ignore-engines"
],
"npmClientArgs": ["--ignore-engines"],
"command": {
"version": {
"forcePublish": true,

View File

@ -62,6 +62,7 @@ export * from './variables';
export { withDynamicSchemaProps } from './hoc/withDynamicSchemaProps';
export { SchemaSettingsActionLinkItem } from './modules/actions/link/customizeLinkActionSettings';
export * from './modules/blocks/BlockSchemaToolbar';
export * from './modules/blocks/data-blocks/form';
export * from './modules/blocks/data-blocks/table';

View File

@ -79,6 +79,14 @@ export function ButtonEditor(props) {
'x-visible': !isLink,
// description: `原字段标题:${collectionField?.uiSchema?.title}`,
},
iconColor: {
title: t('Color'),
required: true,
default: fieldSchema?.['x-component-props']?.iconColor || '#1677FF',
'x-hidden': !props.hasIconColor,
'x-component': 'ColorPicker',
'x-decorator': 'FormItem',
},
type: {
'x-decorator': 'FormItem',
'x-component': 'Radio.Group',
@ -93,18 +101,20 @@ export function ButtonEditor(props) {
{ value: 'primary', label: '{{t("Highlight")}}' },
{ value: 'danger', label: '{{t("Danger red")}}' },
],
'x-visible': !isLink,
'x-visible': !props.hasIconColor && !isLink,
},
},
} as ISchema
}
onSubmit={({ title, icon, type }) => {
onSubmit={({ title, icon, type, iconColor }) => {
fieldSchema.title = title;
field.title = title;
field.componentProps.iconColor = iconColor;
field.componentProps.icon = icon;
field.componentProps.danger = type === 'danger';
field.componentProps.type = type || field.componentProps.type;
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
fieldSchema['x-component-props'].iconColor = iconColor;
fieldSchema['x-component-props'].icon = icon;
fieldSchema['x-component-props'].danger = type === 'danger';
fieldSchema['x-component-props'].type = type || field.componentProps.type;

View File

@ -0,0 +1,2 @@
/node_modules
/src

View File

@ -0,0 +1 @@
# @nocobase/plugin-block-workbench

View File

@ -0,0 +1,2 @@
export * from './dist/client';
export { default } from './dist/client';

View File

@ -0,0 +1 @@
module.exports = require('./dist/client/index.js');

View File

@ -0,0 +1,11 @@
{
"name": "@nocobase/plugin-block-workbench",
"version": "1.0.1-alpha.3",
"main": "dist/server/index.js",
"dependencies": {},
"peerDependencies": {
"@nocobase/client": "1.x",
"@nocobase/server": "1.x",
"@nocobase/test": "1.x"
}
}

View File

@ -0,0 +1,2 @@
export * from './dist/server';
export { default } from './dist/server';

View File

@ -0,0 +1 @@
module.exports = require('./dist/server/index.js');

View File

@ -0,0 +1,99 @@
/**
* 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 { useForm } from '@formily/react';
import {
Action,
ActionContextProvider,
ISchema,
SchemaComponent,
SchemaInitializerItem,
useSchemaInitializer,
} from '@nocobase/client';
import { uid } from '@nocobase/utils/client';
import React, { useMemo, useState } from 'react';
export function ModalActionSchemaInitializerItem(props) {
const { modalSchema = {}, ...otherProps } = props;
const { properties, ...others } = modalSchema;
const [visible, setVisible] = useState(false);
const { setVisible: setSchemaInitializerVisible } = useSchemaInitializer();
const schema: ISchema = useMemo(() => {
return {
name: uid(),
'x-component': 'Action.Modal',
'x-component-props': {
width: '520px',
},
type: 'void',
'x-decorator': 'FormV2',
'x-decorator-props': {},
...others,
properties: {
...properties,
footer1: {
'x-component': 'Action.Modal.Footer',
type: 'void',
properties: {
close: {
title: 'Cancel',
'x-component': 'Action',
'x-component-props': {
type: 'default',
},
'x-use-component-props': () => {
return {
onClick() {
setVisible(false);
props?.onCancel?.();
},
};
},
},
submit: {
title: 'OK',
'x-component': 'Action',
'x-component-props': {
type: 'primary',
},
'x-use-component-props': () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const form = useForm();
return {
async onClick() {
await form.submit();
setVisible(false);
props?.onSubmit?.(form.values);
},
};
},
},
},
},
},
};
}, []);
return (
<>
<SchemaInitializerItem
{...otherProps}
onClick={(e) => {
setSchemaInitializerVisible(false);
setVisible(true);
props?.onClick?.(e);
}}
/>
<ActionContextProvider value={{ visible, setVisible }}>
<SchemaComponent components={{ Action }} schema={schema} />
</ActionContextProvider>
</>
);
}

View File

@ -0,0 +1,47 @@
/**
* 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 { useFieldSchema } from '@formily/react';
import { Action, Icon, withDynamicSchemaProps } from '@nocobase/client';
import { Avatar } from 'antd';
import { createStyles } from 'antd-style';
import React from 'react';
const useStyles = createStyles(({ token, css }) => ({
// 支持 css object 的写法
action: css`
background-color: transparent;
border: 0;
height: auto;
box-shadow: none;
`,
title: css`
margin-top: ${token.marginSM}px;
`,
}));
function Button() {
const fieldSchema = useFieldSchema();
const icon = fieldSchema['x-component-props']?.['icon'];
const backgroundColor = fieldSchema['x-component-props']?.['iconColor'];
const { styles, cx } = useStyles();
return (
<div>
<Avatar style={{ backgroundColor }} size={64} icon={<Icon type={icon} />} />
<div className={cx(styles.title)}>{fieldSchema.title}</div>
</div>
);
}
export const WorkbenchAction = withDynamicSchemaProps((props) => {
const { className, ...others } = props;
const { styles, cx } = useStyles();
return <Action className={cx(className, styles.action)} {...others} icon={null} title={<Button />} />;
});

View File

@ -0,0 +1,66 @@
/**
* 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 { RecursionField, observer, useFieldSchema } from '@formily/react';
import {
DndContext,
SchemaComponentOptions,
useDesignable,
useSchemaInitializerRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Space } from 'antd';
import React from 'react';
import { WorkbenchAction } from './WorkbenchAction';
const ConfigureActionsButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'WorkbenchConfigureActionsButton' },
);
const InternalIcons = () => {
const fieldSchema = useFieldSchema();
const { designable } = useDesignable();
return (
<div style={{ marginBottom: designable ? '1rem' : 0 }}>
<DndContext>
<Space wrap>
{fieldSchema.mapProperties((s, key) => (
<RecursionField name={key} schema={s} />
))}
</Space>
</DndContext>
</div>
);
};
export const WorkbenchBlock: any = withDynamicSchemaProps(
(props) => {
return (
<div>
<SchemaComponentOptions components={{ WorkbenchAction }}>{props.children}</SchemaComponentOptions>
</div>
);
},
{ displayName: 'WorkbenchBlock' },
);
WorkbenchBlock.ActionBar = () => {
return (
<>
<InternalIcons />
<ConfigureActionsButton />
</>
);
};

View File

@ -0,0 +1,97 @@
/**
* 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 {
ButtonEditor,
SchemaSettings,
SchemaSettingsActionLinkItem,
useSchemaInitializer,
useSchemaInitializerItem,
} from '@nocobase/client';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ModalActionSchemaInitializerItem } from './ModalActionSchemaInitializerItem';
export const workbenchActionSettingsLink = new SchemaSettings({
name: 'workbench:actionSettings:link',
items: [
{
name: 'editButton',
Component: ButtonEditor,
useComponentProps() {
return { hasIconColor: true };
},
},
{
name: 'editLink',
Component: SchemaSettingsActionLinkItem,
},
{
sort: 800,
name: 'd1',
type: 'divider',
},
{
sort: 900,
type: 'remove',
name: 'remove',
},
],
});
export function WorkbenchLinkActionSchemaInitializerItem(props) {
const itemConfig = useSchemaInitializerItem();
// 调用插入功能
const { insert } = useSchemaInitializer();
const { t } = useTranslation();
return (
<ModalActionSchemaInitializerItem
title={itemConfig.title}
modalSchema={{
title: t('Add link'),
properties: {
title: {
title: t('Title'),
required: true,
'x-component': 'Input',
'x-decorator': 'FormItem',
},
icon: {
title: t('Icon'),
required: true,
'x-component': 'IconPicker',
'x-decorator': 'FormItem',
},
iconColor: {
title: t('Color'),
required: true,
default: '#1677FF',
'x-component': 'ColorPicker',
'x-decorator': 'FormItem',
},
},
}}
onSubmit={(values) => {
insert({
type: 'void',
title: values.title,
'x-action': 'customize:link',
'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'workbench:actionSettings:link',
'x-component': 'WorkbenchAction',
'x-use-component-props': 'useLinkActionProps',
'x-component-props': {
icon: values.icon,
iconColor: values.iconColor,
},
});
}}
/>
);
}

View File

@ -0,0 +1,84 @@
/**
* 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 { ButtonEditor, SchemaSettings, useSchemaInitializer, useSchemaInitializerItem } from '@nocobase/client';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ModalActionSchemaInitializerItem } from './ModalActionSchemaInitializerItem';
export const workbenchActionSettingsScanQrCode = new SchemaSettings({
name: 'workbench:actionSettings:scanQrCode',
items: [
{
name: 'editButton',
Component: ButtonEditor,
useComponentProps() {
return { hasIconColor: true };
},
},
{
name: 'd1',
type: 'divider',
},
{
type: 'remove',
name: 'remove',
},
],
});
export function WorkbenchScanActionSchemaInitializerItem(props) {
const itemConfig = useSchemaInitializerItem();
// 调用插入功能
const { insert } = useSchemaInitializer();
const { t } = useTranslation();
return (
<ModalActionSchemaInitializerItem
title={itemConfig.title}
modalSchema={{
title: 'Add Scan Qr code',
properties: {
title: {
title: t('Title'),
required: true,
'x-component': 'Input',
'x-decorator': 'FormItem',
},
icon: {
title: t('Icon'),
required: true,
'x-component': 'IconPicker',
'x-decorator': 'FormItem',
},
iconColor: {
title: t('Color'),
required: true,
default: '#1677FF',
'x-component': 'ColorPicker',
'x-decorator': 'FormItem',
},
},
}}
onSubmit={(values) => {
console.log('values', values);
insert({
type: 'void',
title: values.title,
'x-component': 'WorkbenchAction',
'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'workbench:actionSettings:scanQrCode',
'x-component-props': {
icon: values.icon,
iconColor: values.iconColor,
},
});
}}
/>
);
}

View File

@ -0,0 +1,24 @@
/**
* 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 { ISchema } from '@nocobase/client';
export const blockSchema: ISchema = {
type: 'void',
'x-decorator': 'CardItem',
'x-settings': 'blockSettings:workbench',
'x-schema-toolbar': 'BlockSchemaToolbar',
'x-component': 'WorkbenchBlock',
properties: {
actions: {
'x-component': 'WorkbenchBlock.ActionBar',
'x-initializer': 'workbench:configureActions',
},
},
};

View File

@ -0,0 +1,249 @@
/**
* 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.
*/
// CSS modules
type CSSModuleClasses = { readonly [key: string]: string };
declare module '*.module.css' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.scss' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.sass' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.less' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.styl' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.stylus' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.pcss' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.sss' {
const classes: CSSModuleClasses;
export default classes;
}
// CSS
declare module '*.css' { }
declare module '*.scss' { }
declare module '*.sass' { }
declare module '*.less' { }
declare module '*.styl' { }
declare module '*.stylus' { }
declare module '*.pcss' { }
declare module '*.sss' { }
// Built-in asset types
// see `src/node/constants.ts`
// images
declare module '*.apng' {
const src: string;
export default src;
}
declare module '*.png' {
const src: string;
export default src;
}
declare module '*.jpg' {
const src: string;
export default src;
}
declare module '*.jpeg' {
const src: string;
export default src;
}
declare module '*.jfif' {
const src: string;
export default src;
}
declare module '*.pjpeg' {
const src: string;
export default src;
}
declare module '*.pjp' {
const src: string;
export default src;
}
declare module '*.gif' {
const src: string;
export default src;
}
declare module '*.svg' {
const src: string;
export default src;
}
declare module '*.ico' {
const src: string;
export default src;
}
declare module '*.webp' {
const src: string;
export default src;
}
declare module '*.avif' {
const src: string;
export default src;
}
// media
declare module '*.mp4' {
const src: string;
export default src;
}
declare module '*.webm' {
const src: string;
export default src;
}
declare module '*.ogg' {
const src: string;
export default src;
}
declare module '*.mp3' {
const src: string;
export default src;
}
declare module '*.wav' {
const src: string;
export default src;
}
declare module '*.flac' {
const src: string;
export default src;
}
declare module '*.aac' {
const src: string;
export default src;
}
declare module '*.opus' {
const src: string;
export default src;
}
declare module '*.mov' {
const src: string;
export default src;
}
declare module '*.m4a' {
const src: string;
export default src;
}
declare module '*.vtt' {
const src: string;
export default src;
}
// fonts
declare module '*.woff' {
const src: string;
export default src;
}
declare module '*.woff2' {
const src: string;
export default src;
}
declare module '*.eot' {
const src: string;
export default src;
}
declare module '*.ttf' {
const src: string;
export default src;
}
declare module '*.otf' {
const src: string;
export default src;
}
// other
declare module '*.webmanifest' {
const src: string;
export default src;
}
declare module '*.pdf' {
const src: string;
export default src;
}
declare module '*.txt' {
const src: string;
export default src;
}
// wasm?init
declare module '*.wasm?init' {
const initWasm: (options?: WebAssembly.Imports) => Promise<WebAssembly.Instance>;
export default initWasm;
}
// web worker
declare module '*?worker' {
const workerConstructor: {
new(options?: { name?: string }): Worker;
};
export default workerConstructor;
}
declare module '*?worker&inline' {
const workerConstructor: {
new(options?: { name?: string }): Worker;
};
export default workerConstructor;
}
declare module '*?worker&url' {
const src: string;
export default src;
}
declare module '*?sharedworker' {
const sharedWorkerConstructor: {
new(options?: { name?: string }): SharedWorker;
};
export default sharedWorkerConstructor;
}
declare module '*?sharedworker&inline' {
const sharedWorkerConstructor: {
new(options?: { name?: string }): SharedWorker;
};
export default sharedWorkerConstructor;
}
declare module '*?sharedworker&url' {
const src: string;
export default src;
}
declare module '*?raw' {
const src: string;
export default src;
}
declare module '*?url' {
const src: string;
export default src;
}
declare module '*?inline' {
const src: string;
export default src;
}

View File

@ -0,0 +1,57 @@
/**
* 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 { Plugin } from '@nocobase/client';
import { WorkbenchBlock } from './WorkbenchBlock';
import { workbenchActionSettingsLink } from './WorkbenchLinkActionSchemaInitializerItem';
// import {
// WorkbenchScanActionSchemaInitializerItem,
// workbenchActionSettingsScanQrCode,
// } from './WorkbenchScanActionSchemaInitializerItem';
import { workbenchBlockInitializerItem } from './workbenchBlockInitializerItem';
import { workbenchBlockSettings } from './workbenchBlockSettings';
import { workbenchConfigureActions } from './workbenchConfigureActions';
export class PluginBlockWorkbenchClient extends Plugin {
async load() {
this.app.addComponents({ WorkbenchBlock });
// 新增工作台区块的设置器
this.app.schemaSettingsManager.add(workbenchBlockSettings);
// 工作台的配置操作埋点
this.app.schemaInitializerManager.add(workbenchConfigureActions);
// 添加到页面的 Add block 里
this.app.schemaInitializerManager.addItem(
'page:addBlock',
`otherBlocks.${workbenchBlockInitializerItem.name}`,
workbenchBlockInitializerItem,
);
// 添加到移动端的 Add block 里
this.app.schemaInitializerManager.addItem(
'mobilePage:addBlock',
`otherBlocks.${workbenchBlockInitializerItem.name}`,
workbenchBlockInitializerItem,
);
// link 操作
this.app.schemaSettingsManager.add(workbenchActionSettingsLink);
// 扫码操作
// this.app.schemaSettingsManager.add(workbenchActionSettingsScanQrCode);
// this.app.schemaInitializerManager.addItem('workbench:configureActions', `qrcode`, {
// title: 'Scan Qr code',
// Component: WorkbenchScanActionSchemaInitializerItem,
// });
}
}
export default PluginBlockWorkbenchClient;

View File

@ -0,0 +1,28 @@
/**
* 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 { SchemaInitializerItemType, useSchemaInitializer } from '@nocobase/client';
import { useTranslation } from 'react-i18next';
import { blockSchema } from './blockSchema';
export const workbenchBlockInitializerItem: SchemaInitializerItemType = {
type: 'item',
name: 'workbenchBlock',
icon: 'FileImageOutlined',
useComponentProps() {
const { t } = useTranslation('@nocobase/plugin-block-workbench');
const { insert } = useSchemaInitializer();
return {
title: t('Workbench'),
onClick: () => {
insert(blockSchema);
},
};
},
};

View File

@ -0,0 +1,20 @@
/**
* 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 { SchemaSettings } from '@nocobase/client';
export const workbenchBlockSettings = new SchemaSettings({
name: 'blockSettings:workbench',
items: [
{
type: 'remove',
name: 'remove',
},
],
});

View File

@ -0,0 +1,25 @@
/**
* 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 { SchemaInitializer } from '@nocobase/client';
import { WorkbenchLinkActionSchemaInitializerItem } from './WorkbenchLinkActionSchemaInitializerItem';
export const workbenchConfigureActions = new SchemaInitializer({
name: 'workbench:configureActions',
title: '{{t("Configure actions")}}',
// 插入位置
insertPosition: 'beforeEnd',
items: [
{
name: 'link',
title: '{{t("Link")}}',
Component: WorkbenchLinkActionSchemaInitializerItem,
},
],
});

View File

@ -0,0 +1,11 @@
/**
* 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.
*/
export * from './server';
export { default } from './server';

View File

@ -0,0 +1,3 @@
{
"Workbench": "工作台"
}

View File

@ -0,0 +1,10 @@
/**
* 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.
*/
export { default } from './plugin';

View File

@ -0,0 +1,28 @@
/**
* 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 { Plugin } from '@nocobase/server';
export class PluginBlockWorkbenchServer extends Plugin {
async afterAdd() {}
async beforeLoad() {}
async load() {}
async install() {}
async afterEnable() {}
async afterDisable() {}
async remove() {}
}
export default PluginBlockWorkbenchServer;

View File

@ -20,6 +20,7 @@
"@nocobase/plugin-auth-sms": "1.0.1-alpha.3",
"@nocobase/plugin-backup-restore": "1.0.1-alpha.3",
"@nocobase/plugin-block-iframe": "1.0.1-alpha.3",
"@nocobase/plugin-block-workbench": "1.0.1-alpha.3",
"@nocobase/plugin-calendar": "1.0.1-alpha.3",
"@nocobase/plugin-charts": "1.0.1-alpha.3",
"@nocobase/plugin-client": "1.0.1-alpha.3",

View File

@ -39,6 +39,7 @@ export class PresetNocoBase extends Plugin {
'action-export',
'backup-restore',
'block-iframe',
'block-workbench',
'field-formula',
'data-visualization',
'auth',