mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-07-02 11:12:20 +08:00
feat: actions 2.0 (#7105)
* refactor: streamline AddNewActionModel and remove unused imports in TableModel * feat: add LinkPopupActionModel and update PopupActionModel usage * feat: add PopupRecordActionModel and update index export * feat: remove LinkPopupActionModel * refactor: update ViewActionModel to extend RecordActionModel and remove LinkPopupActionModel export * fix: correct import path for ReactiveField in FormFieldModel * fix: correct import path for ReactiveField in FormFieldModel * refactor: update ActionModel to improve button rendering and props handling * refactor: simplify AddNewActionModel by removing unused imports and streamlining flow registration * refactor: streamline DeleteActionModel by removing unnecessary confirmation steps * feat: enhance LinkActionModel with new navigation and parameter handling features * feat: add Emotion CSS support to LinkActionModel * refactor: update BulkDeleteActionModel to improve flow registration and event handling * refactor: update AddNewActionModel and BulkDeleteActionModel to use title and icon props * refactor: update RefreshActionModel to use title and icon props, and improve flow registration * refactor: rename LinkActionModel to LinkRecordActionModel * feat: add LinkGlobalActionModel and register flow for link handling * feat: implement openLinkAction and integrate with LinkGlobalActionModel and LinkRecordActionModel * feat: add CustomRequestRecordActionModel and update index export * feat: add CustomRequestGlobalActionModel and update index export * feat: add BulkEditActionModel and update index export
This commit is contained in:
parent
1e28346b0e
commit
78d4b27690
94
packages/core/client/src/flow/actions/openLinkAction.tsx
Normal file
94
packages/core/client/src/flow/actions/openLinkAction.tsx
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/**
|
||||||
|
* 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 { css } from '@emotion/css';
|
||||||
|
import { Variable } from '../../schema-component/antd/variable/Variable';
|
||||||
|
|
||||||
|
export const openLinkAction = {
|
||||||
|
title: '编辑链接',
|
||||||
|
uiSchema: {
|
||||||
|
url: {
|
||||||
|
title: 'URL',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': Variable.TextArea,
|
||||||
|
description: 'Do not concatenate search params in the URL',
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
type: 'array',
|
||||||
|
'x-component': 'ArrayItems',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
title: `Search parameters`,
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
space: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Space',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
maxWidth: '100%',
|
||||||
|
},
|
||||||
|
className: css`
|
||||||
|
& > .ant-space-item:first-child,
|
||||||
|
& > .ant-space-item:last-child {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-component-props': {
|
||||||
|
placeholder: `{{t("Name")}}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': Variable.TextArea,
|
||||||
|
'x-component-props': {
|
||||||
|
placeholder: `{{t("Value")}}`,
|
||||||
|
useTypedConstant: true,
|
||||||
|
changeOnSelect: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
remove: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ArrayItems.Remove',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
add: {
|
||||||
|
type: 'void',
|
||||||
|
title: 'Add parameter',
|
||||||
|
'x-component': 'ArrayItems.Addition',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
openInNewWindow: {
|
||||||
|
type: 'boolean',
|
||||||
|
'x-content': 'Open in new window',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Checkbox',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
handler(ctx, params) {
|
||||||
|
ctx.globals.modal.confirm({
|
||||||
|
title: `TODO`,
|
||||||
|
content: JSON.stringify(params, null, 2),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
@ -8,63 +8,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ButtonProps } from 'antd';
|
import { ButtonProps } from 'antd';
|
||||||
import React from 'react';
|
|
||||||
import { FlowPage } from '../../FlowPage';
|
|
||||||
import { GlobalActionModel } from '../base/ActionModel';
|
import { GlobalActionModel } from '../base/ActionModel';
|
||||||
|
import { openModeAction } from '../../actions/openModeAction';
|
||||||
|
|
||||||
export class AddNewActionModel extends GlobalActionModel {
|
export class AddNewActionModel extends GlobalActionModel {
|
||||||
defaultProps: ButtonProps = {
|
defaultProps: ButtonProps = {
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
children: 'Add new',
|
title: 'Add new',
|
||||||
|
icon: 'PlusOutlined',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
AddNewActionModel.registerFlow({
|
AddNewActionModel.registerFlow({
|
||||||
sort: 200,
|
sort: 200,
|
||||||
title: '事件',
|
title: '点击事件',
|
||||||
key: 'event1',
|
key: 'handleClick',
|
||||||
on: {
|
on: {
|
||||||
eventName: 'click',
|
eventName: 'click',
|
||||||
},
|
},
|
||||||
steps: {
|
steps: {
|
||||||
step1: {
|
open: openModeAction,
|
||||||
title: '弹窗配置',
|
|
||||||
uiSchema: {
|
|
||||||
width: {
|
|
||||||
type: 'number',
|
|
||||||
title: '宽度',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'NumberPicker',
|
|
||||||
'x-component-props': {
|
|
||||||
placeholder: '请输入宽度',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultParams: {
|
|
||||||
width: 800,
|
|
||||||
},
|
|
||||||
handler(ctx, params) {
|
|
||||||
// eslint-disable-next-line prefer-const
|
|
||||||
let currentDrawer: any;
|
|
||||||
|
|
||||||
function DrawerContent() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<FlowPage
|
|
||||||
parentId={ctx.model.uid}
|
|
||||||
sharedContext={{ parentBlockModel: ctx.shared.currentBlockModel, currentDrawer }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentDrawer = ctx.globals.drawer.open({
|
|
||||||
// title: '命令式 Drawer',
|
|
||||||
header: null,
|
|
||||||
width: params.width,
|
|
||||||
content: <DrawerContent />,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -10,20 +10,25 @@
|
|||||||
import { MultiRecordResource } from '@nocobase/flow-engine';
|
import { MultiRecordResource } from '@nocobase/flow-engine';
|
||||||
import { ButtonProps } from 'antd';
|
import { ButtonProps } from 'antd';
|
||||||
import { GlobalActionModel } from '../base/ActionModel';
|
import { GlobalActionModel } from '../base/ActionModel';
|
||||||
|
import { secondaryConfirmationAction } from '../../actions/secondaryConfirmationAction';
|
||||||
|
import { refreshOnCompleteAction } from '../../actions/refreshOnCompleteAction';
|
||||||
|
|
||||||
export class BulkDeleteActionModel extends GlobalActionModel {
|
export class BulkDeleteActionModel extends GlobalActionModel {
|
||||||
defaultProps: ButtonProps = {
|
defaultProps: ButtonProps = {
|
||||||
children: 'Delete',
|
title: 'Delete',
|
||||||
|
icon: 'DeleteOutlined',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
BulkDeleteActionModel.registerFlow({
|
BulkDeleteActionModel.registerFlow({
|
||||||
key: 'event1',
|
key: 'handleClick',
|
||||||
|
title: '点击事件',
|
||||||
on: {
|
on: {
|
||||||
eventName: 'click',
|
eventName: 'click',
|
||||||
},
|
},
|
||||||
steps: {
|
steps: {
|
||||||
step1: {
|
secondaryConfirmationAction,
|
||||||
|
delete: {
|
||||||
async handler(ctx, params) {
|
async handler(ctx, params) {
|
||||||
if (!ctx.shared?.currentBlockModel?.resource) {
|
if (!ctx.shared?.currentBlockModel?.resource) {
|
||||||
ctx.globals.message.error('No resource selected for deletion.');
|
ctx.globals.message.error('No resource selected for deletion.');
|
||||||
@ -38,5 +43,6 @@ BulkDeleteActionModel.registerFlow({
|
|||||||
ctx.globals.message.success('Selected records deleted successfully.');
|
ctx.globals.message.success('Selected records deleted successfully.');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
refreshOnCompleteAction,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* 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 { MultiRecordResource } from '@nocobase/flow-engine';
|
||||||
|
import { ButtonProps } from 'antd';
|
||||||
|
import { GlobalActionModel } from '../base/ActionModel';
|
||||||
|
import { openModeAction } from '../../actions/openModeAction';
|
||||||
|
|
||||||
|
export class BulkEditActionModel extends GlobalActionModel {
|
||||||
|
defaultProps: ButtonProps = {
|
||||||
|
title: 'Bulk edit',
|
||||||
|
icon: 'EditOutlined',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
BulkEditActionModel.registerFlow({
|
||||||
|
key: 'handleClick',
|
||||||
|
title: '点击事件',
|
||||||
|
on: {
|
||||||
|
eventName: 'click',
|
||||||
|
},
|
||||||
|
steps: {
|
||||||
|
openModeAction,
|
||||||
|
bulkEdit: {
|
||||||
|
title: '更新的数据',
|
||||||
|
uiSchema: {
|
||||||
|
updateMode: {
|
||||||
|
'x-component': 'Radio.Group',
|
||||||
|
'x-component-props': {
|
||||||
|
options: [
|
||||||
|
{ label: '更新选中行', value: 'selected' },
|
||||||
|
{ label: '更新所有行', value: 'all' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultParams(ctx) {
|
||||||
|
return {
|
||||||
|
updateMode: 'selected',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async handler(ctx, params) {
|
||||||
|
if (!ctx.shared?.currentBlockModel?.resource) {
|
||||||
|
ctx.globals.message.error('No resource selected for bulk edit.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const resource = ctx.shared.currentBlockModel.resource as MultiRecordResource;
|
||||||
|
if (resource.getSelectedRows().length === 0) {
|
||||||
|
ctx.globals.message.warning('No records selected for bulk edit.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await resource.destroySelectedRows();
|
||||||
|
ctx.globals.message.success('Successfully.');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
@ -15,9 +15,8 @@ import { refreshOnCompleteAction } from '../../actions/refreshOnCompleteAction';
|
|||||||
import { secondaryConfirmationAction } from '../../actions/secondaryConfirmationAction';
|
import { secondaryConfirmationAction } from '../../actions/secondaryConfirmationAction';
|
||||||
import { GlobalActionModel } from '../base/ActionModel';
|
import { GlobalActionModel } from '../base/ActionModel';
|
||||||
|
|
||||||
export class CustomRequestActionModel extends GlobalActionModel {
|
export class CustomRequestGlobalActionModel extends GlobalActionModel {
|
||||||
defaultProps: ButtonProps = {
|
defaultProps: ButtonProps = {
|
||||||
type: 'link',
|
|
||||||
title: 'Custom request',
|
title: 'Custom request',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -35,7 +34,7 @@ const useVariableProps = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
CustomRequestActionModel.registerFlow({
|
CustomRequestGlobalActionModel.registerFlow({
|
||||||
key: 'handleClick',
|
key: 'handleClick',
|
||||||
title: '点击事件',
|
title: '点击事件',
|
||||||
on: {
|
on: {
|
@ -0,0 +1,304 @@
|
|||||||
|
/**
|
||||||
|
* 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 type { ButtonProps } from 'antd/es/button';
|
||||||
|
import { useGlobalVariable } from '../../../application/hooks/useGlobalVariable';
|
||||||
|
import { BlocksSelector } from '../../../schema-component/antd/action/Action.Designer';
|
||||||
|
import { useAfterSuccessOptions } from '../../../schema-component/antd/action/hooks/useGetAfterSuccessVariablesOptions';
|
||||||
|
import { refreshOnCompleteAction } from '../../actions/refreshOnCompleteAction';
|
||||||
|
import { secondaryConfirmationAction } from '../../actions/secondaryConfirmationAction';
|
||||||
|
import { RecordActionModel } from '../base/ActionModel';
|
||||||
|
|
||||||
|
export class CustomRequestRecordActionModel extends RecordActionModel {
|
||||||
|
defaultProps: ButtonProps = {
|
||||||
|
type: 'link',
|
||||||
|
title: 'Custom request',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const fieldNames = {
|
||||||
|
value: 'value',
|
||||||
|
label: 'label',
|
||||||
|
};
|
||||||
|
const useVariableProps = () => {
|
||||||
|
const environmentVariables = useGlobalVariable('$env');
|
||||||
|
const scope = useAfterSuccessOptions();
|
||||||
|
return {
|
||||||
|
scope: [environmentVariables, ...scope].filter(Boolean),
|
||||||
|
fieldNames,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
CustomRequestRecordActionModel.registerFlow({
|
||||||
|
key: 'handleClick',
|
||||||
|
title: '点击事件',
|
||||||
|
on: {
|
||||||
|
eventName: 'click',
|
||||||
|
},
|
||||||
|
steps: {
|
||||||
|
secondaryConfirmation: secondaryConfirmationAction,
|
||||||
|
request: {
|
||||||
|
title: '请求设置',
|
||||||
|
uiSchema: {
|
||||||
|
method: {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
title: 'HTTP method',
|
||||||
|
'x-decorator-props': {
|
||||||
|
tooltip:
|
||||||
|
'When the HTTP method is Post, Put or Patch, and this custom request inside the form, the request body will be automatically filled in with the form data',
|
||||||
|
},
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Select',
|
||||||
|
'x-component-props': {
|
||||||
|
showSearch: false,
|
||||||
|
allowClear: false,
|
||||||
|
className: 'auto-width',
|
||||||
|
},
|
||||||
|
enum: [
|
||||||
|
{ label: 'GET', value: 'GET' },
|
||||||
|
{ label: 'POST', value: 'POST' },
|
||||||
|
{ label: 'PUT', value: 'PUT' },
|
||||||
|
{ label: 'PATCH', value: 'PATCH' },
|
||||||
|
{ label: 'DELETE', value: 'DELETE' },
|
||||||
|
],
|
||||||
|
default: 'POST',
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
title: 'URL',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Variable.TextArea',
|
||||||
|
'x-use-component-props': useVariableProps,
|
||||||
|
'x-component-props': {
|
||||||
|
placeholder: 'https://www.nocobase.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
type: 'array',
|
||||||
|
'x-component': 'ArrayItems',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
title: 'Headers',
|
||||||
|
description: '"Content-Type" only support "application/json", and no need to specify',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
space: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Space',
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-component-props': {
|
||||||
|
placeholder: 'Name',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Variable.TextArea',
|
||||||
|
'x-use-component-props': useVariableProps,
|
||||||
|
},
|
||||||
|
remove: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ArrayItems.Remove',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
add: {
|
||||||
|
type: 'void',
|
||||||
|
title: 'Add request header',
|
||||||
|
'x-component': 'ArrayItems.Addition',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
type: 'array',
|
||||||
|
'x-component': 'ArrayItems',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
title: 'Parameters',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
space: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Space',
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-component-props': {
|
||||||
|
placeholder: 'Name',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Variable.TextArea',
|
||||||
|
'x-use-component-props': useVariableProps,
|
||||||
|
},
|
||||||
|
remove: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ArrayItems.Remove',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
add: {
|
||||||
|
type: 'void',
|
||||||
|
title: 'Add parameter',
|
||||||
|
'x-component': 'ArrayItems.Addition',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Body',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-decorator-props': {},
|
||||||
|
'x-component': 'Variable.JSON',
|
||||||
|
'x-component-props': {
|
||||||
|
scope: '{{useCustomRequestVariableOptions}}',
|
||||||
|
fieldNames: {
|
||||||
|
value: 'name',
|
||||||
|
label: 'title',
|
||||||
|
},
|
||||||
|
changeOnSelect: true,
|
||||||
|
autoSize: {
|
||||||
|
minRows: 10,
|
||||||
|
},
|
||||||
|
placeholder: 'Input request data',
|
||||||
|
},
|
||||||
|
description: 'Only support standard JSON data',
|
||||||
|
},
|
||||||
|
timeout: {
|
||||||
|
type: 'number',
|
||||||
|
title: 'Timeout config',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-decorator-props': {},
|
||||||
|
'x-component': 'InputNumber',
|
||||||
|
'x-component-props': {
|
||||||
|
addonAfter: 'ms',
|
||||||
|
min: 1,
|
||||||
|
step: 1000,
|
||||||
|
defaultValue: 5000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responseType: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Response type',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-decorator-props': {},
|
||||||
|
'x-component': 'Select',
|
||||||
|
default: 'json',
|
||||||
|
enum: [
|
||||||
|
{ value: 'json', label: 'JSON' },
|
||||||
|
{ value: 'stream', label: 'Stream' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async handler(ctx, params) {
|
||||||
|
ctx.globals.modal({
|
||||||
|
title: 'TODO: Custom request action handler',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
afterSuccess: {
|
||||||
|
title: '提交成功后',
|
||||||
|
uiSchema: {
|
||||||
|
successMessage: {
|
||||||
|
title: 'Popup message',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input.TextArea',
|
||||||
|
'x-component-props': {},
|
||||||
|
},
|
||||||
|
manualClose: {
|
||||||
|
title: 'Message popup close method',
|
||||||
|
enum: [
|
||||||
|
{ label: 'Automatic close', value: false },
|
||||||
|
{ label: 'Manually close', value: true },
|
||||||
|
],
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Radio.Group',
|
||||||
|
'x-component-props': {},
|
||||||
|
},
|
||||||
|
redirecting: {
|
||||||
|
title: 'Then',
|
||||||
|
'x-hidden': true,
|
||||||
|
enum: [
|
||||||
|
{ label: 'Stay on current page', value: false },
|
||||||
|
{ label: 'Redirect to', value: true },
|
||||||
|
],
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Radio.Group',
|
||||||
|
'x-component-props': {},
|
||||||
|
'x-reactions': {
|
||||||
|
target: 'redirectTo',
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
visible: '{{!!$self.value}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actionAfterSuccess: {
|
||||||
|
title: 'Action after successful submission',
|
||||||
|
enum: [
|
||||||
|
{ label: 'Stay on the current popup or page', value: 'stay' },
|
||||||
|
{ label: 'Return to the previous popup or page', value: 'previous' },
|
||||||
|
{ label: 'Redirect to', value: 'redirect' },
|
||||||
|
],
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Radio.Group',
|
||||||
|
'x-component-props': {},
|
||||||
|
'x-reactions': {
|
||||||
|
target: 'redirectTo',
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
visible: "{{$self.value==='redirect'}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
redirectTo: {
|
||||||
|
title: 'Link',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Variable.TextArea',
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
'x-use-component-props': () => useVariableProps(),
|
||||||
|
},
|
||||||
|
blocksToRefresh: {
|
||||||
|
type: 'array',
|
||||||
|
title: 'Refresh data blocks',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-use-decorator-props': () => {
|
||||||
|
return {
|
||||||
|
tooltip: 'After successful submission, the selected data blocks will be automatically refreshed.',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
'x-component': BlocksSelector,
|
||||||
|
// 'x-hidden': isInBlockTemplateConfigPage, // 模板配置页面暂不支持该配置
|
||||||
|
},
|
||||||
|
},
|
||||||
|
handler(ctx, params) {},
|
||||||
|
},
|
||||||
|
refresh: refreshOnCompleteAction,
|
||||||
|
},
|
||||||
|
});
|
@ -7,54 +7,28 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { MultiRecordResource } from '@nocobase/flow-engine';
|
import type { ButtonProps } from 'antd/es/button';
|
||||||
import type { ButtonProps } from 'antd';
|
|
||||||
import { RecordActionModel } from '../base/ActionModel';
|
import { RecordActionModel } from '../base/ActionModel';
|
||||||
|
import { secondaryConfirmationAction } from '../../actions/secondaryConfirmationAction';
|
||||||
|
import { MultiRecordResource } from '@nocobase/flow-engine';
|
||||||
|
import { refreshOnCompleteAction } from '../../actions/refreshOnCompleteAction';
|
||||||
|
|
||||||
export class DeleteActionModel extends RecordActionModel {
|
export class DeleteActionModel extends RecordActionModel {
|
||||||
defaultProps: ButtonProps = {
|
defaultProps: ButtonProps = {
|
||||||
children: 'Delete',
|
|
||||||
type: 'link',
|
type: 'link',
|
||||||
|
title: 'Delete',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
DeleteActionModel.registerFlow({
|
DeleteActionModel.registerFlow({
|
||||||
key: 'event1',
|
key: 'handleClick',
|
||||||
|
title: '点击事件',
|
||||||
on: {
|
on: {
|
||||||
eventName: 'click',
|
eventName: 'click',
|
||||||
},
|
},
|
||||||
steps: {
|
steps: {
|
||||||
confirm: {
|
secondaryConfirmation: secondaryConfirmationAction,
|
||||||
uiSchema: {
|
delete: {
|
||||||
title: {
|
|
||||||
type: 'string',
|
|
||||||
title: 'Confirm title',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
content: {
|
|
||||||
type: 'string',
|
|
||||||
title: 'Confirm content',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input.TextArea',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultParams: {
|
|
||||||
title: 'Confirm Deletion',
|
|
||||||
content: 'Are you sure you want to delete this record?',
|
|
||||||
},
|
|
||||||
async handler(ctx, params) {
|
|
||||||
const confirmed = await ctx.globals.modal.confirm({
|
|
||||||
title: params.title,
|
|
||||||
content: params.content,
|
|
||||||
});
|
|
||||||
if (!confirmed) {
|
|
||||||
ctx.globals.message.info('Deletion cancelled.');
|
|
||||||
return ctx.exit();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
step1: {
|
|
||||||
async handler(ctx, params) {
|
async handler(ctx, params) {
|
||||||
if (!ctx.shared?.currentBlockModel?.resource) {
|
if (!ctx.shared?.currentBlockModel?.resource) {
|
||||||
ctx.globals.message.error('No resource selected for deletion.');
|
ctx.globals.message.error('No resource selected for deletion.');
|
||||||
@ -69,5 +43,6 @@ DeleteActionModel.registerFlow({
|
|||||||
ctx.globals.message.success('Record deleted successfully.');
|
ctx.globals.message.success('Record deleted successfully.');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
refresh: refreshOnCompleteAction,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* 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 type { ButtonProps } from 'antd';
|
||||||
|
import { GlobalActionModel } from '../base/ActionModel';
|
||||||
|
import { openLinkAction } from '../../actions/openLinkAction';
|
||||||
|
|
||||||
|
export class LinkGlobalActionModel extends GlobalActionModel {
|
||||||
|
defaultProps: ButtonProps = {
|
||||||
|
title: 'Link',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkGlobalActionModel.registerFlow({
|
||||||
|
key: 'handleClick',
|
||||||
|
title: '点击事件',
|
||||||
|
on: {
|
||||||
|
eventName: 'click',
|
||||||
|
},
|
||||||
|
steps: {
|
||||||
|
navigate: openLinkAction,
|
||||||
|
},
|
||||||
|
});
|
@ -9,22 +9,22 @@
|
|||||||
|
|
||||||
import type { ButtonProps } from 'antd';
|
import type { ButtonProps } from 'antd';
|
||||||
import { RecordActionModel } from '../base/ActionModel';
|
import { RecordActionModel } from '../base/ActionModel';
|
||||||
|
import { openLinkAction } from '../../actions/openLinkAction';
|
||||||
|
|
||||||
export class LinkActionModel extends RecordActionModel {
|
export class LinkRecordActionModel extends RecordActionModel {
|
||||||
defaultProps: ButtonProps = {
|
defaultProps: ButtonProps = {
|
||||||
type: 'link',
|
type: 'link',
|
||||||
children: 'Link',
|
children: 'Link',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkActionModel.registerFlow({
|
LinkRecordActionModel.registerFlow({
|
||||||
key: 'event1',
|
key: 'handleClick',
|
||||||
|
title: '点击事件',
|
||||||
on: {
|
on: {
|
||||||
eventName: 'click',
|
eventName: 'click',
|
||||||
},
|
},
|
||||||
steps: {
|
steps: {
|
||||||
step1: {
|
navigate: openLinkAction,
|
||||||
handler(ctx, params) {},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
@ -11,14 +11,13 @@ import type { ButtonProps } from 'antd/es/button';
|
|||||||
import { openModeAction } from '../../actions/openModeAction';
|
import { openModeAction } from '../../actions/openModeAction';
|
||||||
import { RecordActionModel } from '../base/ActionModel';
|
import { RecordActionModel } from '../base/ActionModel';
|
||||||
|
|
||||||
export class PopupActionModel extends RecordActionModel {
|
export class PopupRecordActionModel extends RecordActionModel {
|
||||||
defaultProps: ButtonProps = {
|
defaultProps: ButtonProps = {
|
||||||
type: 'link',
|
|
||||||
title: 'Popup',
|
title: 'Popup',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
PopupActionModel.registerFlow({
|
PopupRecordActionModel.registerFlow({
|
||||||
key: 'handleClick',
|
key: 'handleClick',
|
||||||
title: '点击事件',
|
title: '点击事件',
|
||||||
on: {
|
on: {
|
@ -9,20 +9,24 @@
|
|||||||
|
|
||||||
import { ButtonProps } from 'antd';
|
import { ButtonProps } from 'antd';
|
||||||
import { GlobalActionModel } from '../base/ActionModel';
|
import { GlobalActionModel } from '../base/ActionModel';
|
||||||
|
import { secondaryConfirmationAction } from '../../actions/secondaryConfirmationAction';
|
||||||
|
|
||||||
export class RefreshActionModel extends GlobalActionModel {
|
export class RefreshActionModel extends GlobalActionModel {
|
||||||
defaultProps: ButtonProps = {
|
defaultProps: ButtonProps = {
|
||||||
children: 'Refresh',
|
title: 'Refresh',
|
||||||
|
icon: 'ReloadOutlined',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
RefreshActionModel.registerFlow({
|
RefreshActionModel.registerFlow({
|
||||||
key: 'event1',
|
key: 'handleClick',
|
||||||
|
title: '点击事件',
|
||||||
on: {
|
on: {
|
||||||
eventName: 'click',
|
eventName: 'click',
|
||||||
},
|
},
|
||||||
steps: {
|
steps: {
|
||||||
step1: {
|
secondaryConfirmationAction,
|
||||||
|
refresh: {
|
||||||
async handler(ctx, params) {
|
async handler(ctx, params) {
|
||||||
if (!ctx.shared?.currentBlockModel?.resource) {
|
if (!ctx.shared?.currentBlockModel?.resource) {
|
||||||
ctx.globals.message.error('No resource selected for refresh.');
|
ctx.globals.message.error('No resource selected for refresh.');
|
||||||
|
@ -7,50 +7,24 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ButtonProps } from 'antd';
|
import type { ButtonProps } from 'antd/es/button';
|
||||||
import React from 'react';
|
|
||||||
import { FlowPage } from '../../FlowPage';
|
|
||||||
import { RecordActionModel } from '../base/ActionModel';
|
import { RecordActionModel } from '../base/ActionModel';
|
||||||
|
import { openModeAction } from '../../actions/openModeAction';
|
||||||
|
|
||||||
export class ViewActionModel extends RecordActionModel {
|
export class ViewActionModel extends RecordActionModel {
|
||||||
defaultProps: ButtonProps = {
|
defaultProps: ButtonProps = {
|
||||||
children: 'View',
|
|
||||||
type: 'link',
|
type: 'link',
|
||||||
|
title: 'View',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewActionModel.registerFlow({
|
ViewActionModel.registerFlow({
|
||||||
key: 'event1',
|
key: 'handleClick',
|
||||||
|
title: '点击事件',
|
||||||
on: {
|
on: {
|
||||||
eventName: 'click',
|
eventName: 'click',
|
||||||
},
|
},
|
||||||
steps: {
|
steps: {
|
||||||
step1: {
|
open: openModeAction,
|
||||||
handler(ctx, params) {
|
|
||||||
// eslint-disable-next-line prefer-const
|
|
||||||
let currentDrawer: any;
|
|
||||||
|
|
||||||
function DrawerContent() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<FlowPage
|
|
||||||
parentId={ctx.model.uid}
|
|
||||||
sharedContext={{
|
|
||||||
currentDrawer,
|
|
||||||
parentRecord: ctx.extra.currentRecord,
|
|
||||||
parentBlockModel: ctx.shared.currentBlockModel,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentDrawer = ctx.globals.drawer.open({
|
|
||||||
// title: '命令式 Drawer',
|
|
||||||
width: 800,
|
|
||||||
content: <DrawerContent />,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -9,13 +9,16 @@
|
|||||||
|
|
||||||
export * from './AddNewActionModel';
|
export * from './AddNewActionModel';
|
||||||
export * from './BulkDeleteActionModel';
|
export * from './BulkDeleteActionModel';
|
||||||
export * from './CustomRequestActionModel';
|
export * from './BulkEditActionModel';
|
||||||
|
export * from './CustomRequestRecordActionModel';
|
||||||
|
export * from './CustomRequestGlobalActionModel';
|
||||||
export * from './DeleteActionModel';
|
export * from './DeleteActionModel';
|
||||||
export * from './DuplicateActionModel';
|
export * from './DuplicateActionModel';
|
||||||
export * from './EditActionModel';
|
export * from './EditActionModel';
|
||||||
export * from './FilterActionModel';
|
export * from './FilterActionModel';
|
||||||
export * from './LinkActionModel';
|
export * from './LinkRecordActionModel';
|
||||||
export * from './PopupActionModel';
|
export * from './LinkGlobalActionModel';
|
||||||
|
export * from './PopupRecordActionModel';
|
||||||
export * from './RefreshActionModel';
|
export * from './RefreshActionModel';
|
||||||
export * from './UpdateRecordActionModel';
|
export * from './UpdateRecordActionModel';
|
||||||
export * from './ViewActionModel';
|
export * from './ViewActionModel';
|
||||||
|
@ -11,44 +11,56 @@ import { FlowModel } from '@nocobase/flow-engine';
|
|||||||
import { Button } from 'antd';
|
import { Button } from 'antd';
|
||||||
import type { ButtonProps } from 'antd/es/button';
|
import type { ButtonProps } from 'antd/es/button';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import IconPicker from '../../../schema-component/antd/icon-picker/IconPicker';
|
||||||
|
import { Icon } from '../../../icon/Icon';
|
||||||
|
|
||||||
export class ActionModel extends FlowModel {
|
export class ActionModel extends FlowModel {
|
||||||
|
declare props: ButtonProps;
|
||||||
|
|
||||||
defaultProps: ButtonProps = {
|
defaultProps: ButtonProps = {
|
||||||
type: 'default',
|
type: 'default',
|
||||||
children: 'Action',
|
title: 'Action',
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <Button {...this.defaultProps} {...this.props} />;
|
const props = { ...this.defaultProps, ...this.props };
|
||||||
|
const icon = <Icon type={props.icon as any} />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button {...props} icon={icon}>
|
||||||
|
{props.children || props.title}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionModel.registerFlow({
|
ActionModel.registerFlow({
|
||||||
key: 'default',
|
key: 'default',
|
||||||
|
title: '通用配置',
|
||||||
auto: true,
|
auto: true,
|
||||||
title: '基础',
|
|
||||||
sort: 100,
|
|
||||||
steps: {
|
steps: {
|
||||||
step1: {
|
buttonProps: {
|
||||||
title: '编辑按钮',
|
title: '编辑按钮',
|
||||||
uiSchema: {
|
uiSchema: {
|
||||||
children: {
|
title: {
|
||||||
type: 'string',
|
|
||||||
title: '标题',
|
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'Input',
|
'x-component': 'Input',
|
||||||
'x-component-props': {
|
title: 'Button title',
|
||||||
placeholder: '请输入标题',
|
},
|
||||||
},
|
icon: {
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': IconPicker,
|
||||||
|
title: 'Button icon',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultParams(ctx) {
|
defaultParams(ctx) {
|
||||||
return {
|
return {
|
||||||
type: 'default',
|
title: ctx.model.defaultProps.title,
|
||||||
...ctx.model.defaultProps,
|
icon: ctx.model.defaultProps.icon,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
handler(ctx, params) {
|
handler(ctx, params) {
|
||||||
ctx.model.setProps('children', params.children);
|
ctx.model.setProps(params);
|
||||||
ctx.model.setProps('onClick', (event) => {
|
ctx.model.setProps('onClick', (event) => {
|
||||||
ctx.model.dispatchEvent('click', {
|
ctx.model.dispatchEvent('click', {
|
||||||
...ctx.extra,
|
...ctx.extra,
|
||||||
|
@ -11,7 +11,6 @@ import { SettingOutlined } from '@ant-design/icons';
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import {
|
import {
|
||||||
AddActionButton,
|
AddActionButton,
|
||||||
AddActionModel,
|
|
||||||
AddFieldButton,
|
AddFieldButton,
|
||||||
Collection,
|
Collection,
|
||||||
FlowModelRenderer,
|
FlowModelRenderer,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user