feat: support action add

This commit is contained in:
Jian Lu 2025-01-23 17:23:19 +08:00
parent e973756d5a
commit c86d084f5a
6 changed files with 209 additions and 68 deletions

View File

@ -7,10 +7,10 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { ArrayField as ArrayFieldModel, VoidField } from '@formily/core';
import { ArrayField as ArrayFieldModel, VoidField, ObjectField as ObjectFieldModel } from '@formily/core';
import { ArrayField, ObjectField, observer, useField } from '@formily/react';
import { Space, TreeSelect } from 'antd';
import React, { useCallback, useMemo } from 'react';
import { Button, Cascader, Input, Space, TreeSelect } from 'antd';
import React, { useCallback, useContext, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import {
@ -20,40 +20,64 @@ import {
} from './LinkageRuleAction';
import { RemoveActionContext } from './context';
import { useControllableValue } from 'ahooks';
import { CloseCircleOutlined } from '@ant-design/icons';
import { useActionOptions } from './hooks/useActionOptions';
const ActionSelect = (props) => {
const { t } = useTranslation();
const { definitions, className } = props;
const [state, setState] = useControllableValue<String>(props, {
defaultValue: undefined,
});
let treeData = definitions?.map((module) => ({
value: module.name,
title: module.title + ' - ' + module.uid,
selectable: false,
children:
module?.events?.map((event) => ({
value: module.name + '.' + event.name,
title: event.title,
})) || [],
}));
treeData = treeData?.filter((item) => item.children.length > 0);
const ActionParams = observer((props) => {
const field = useField<ArrayFieldModel>();
return (
<TreeSelect
value={state}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
placeholder="Please select"
allowClear
treeDefaultExpandAll
onChange={(value) => {
setState(value);
}}
treeData={treeData}
className={className}
/>
<div>
{field?.value?.map((item, index) => (
<div key={index}>
<Input />
</div>
))}
</div>
);
});
export const ActionRow = observer(
(props: any): any => {
const { onRemove } = props;
const options = useActionOptions();
const field = useField<any>();
const onClick = useCallback(() => {
console.log('field2', field);
// const f = field.query('.params').take() as ObjectFieldModel;
// field.val = field.data || {};
// field.data.params = field.data.params || [];
// field.data.params.push({});
// const items = f.value || [];
// items.push({});
// f.value = items;
// f.initialValue = items;
}, [field]);
return (
<div>
<Space>
<Cascader
// value={state}
options={options}
onChange={(value) => {
console.log('value', value);
// setState(value);
}}
></Cascader>
<div>
<ArrayField name={'params'} component={[ActionParams, {}]} disabled={false} />
<Button onClick={onClick}></Button>
</div>
{!props.disabled && (
<a role="button" aria-label="icon-close">
<CloseCircleOutlined onClick={onRemove} style={{ color: '#bfbfbf' }} />
</a>
)}
</Space>
</div>
);
},
{ displayName: 'ActionRow' },
);
};
export const Action = observer(
(props: any): any => {
@ -67,13 +91,16 @@ export const Action = observer(
field: FormFieldLinkageRuleAction,
style: FormStyleLinkageRuleAction,
};
// console.log('field?.value', field.value);
return field?.value?.map((item, index) => {
return (
<RemoveActionContext.Provider key={index} value={() => field.remove(index)}>
<ObjectField name={index} component={[ActionSelect, { ...props, options: linkageOptions }]} />
<ObjectField name={index} component={[ActionRow]} />
</RemoveActionContext.Provider>
);
});
},
{ displayName: 'LinkageRuleActions' },
{ displayName: 'Action' },
);

View File

@ -0,0 +1,45 @@
/**
* 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 { Field, ObjectField, observer, useField } from '@formily/react';
import { Button, Input, Space } from 'antd';
import React from 'react';
import { ArrayField as ArrayFieldModel } from '@formily/core';
import { CloseCircleOutlined } from '@ant-design/icons';
const ActionParams = observer((props: any) => {
return (
<Space>
<Field name="name" component={[Input]} />
<span></span>
<Field name="value" component={[Input]} />
{!props.disabled && (
<a role="button" aria-label="icon-close">
<CloseCircleOutlined onClick={props.onRemove} style={{ color: '#bfbfbf' }} />
</a>
)}
</Space>
);
});
export const ActionParamsField = observer((props: { action: string }) => {
const field = useField<ArrayFieldModel>();
const { action } = props;
console.log('ActionParamsField action', props);
return (
<Space direction="vertical">
{field?.value?.map((item, index) => (
<ObjectField key={index} name={index} component={[ActionParams, { onRemove: () => field.remove(index) }]} />
))}
<Button type="link" onClick={() => field.push({})}>
</Button>
</Space>
);
});

View File

@ -8,13 +8,15 @@
*/
import { ArrayField as ArrayFieldModel, VoidField } from '@formily/core';
import { ArrayField, ObjectField, observer, useField } from '@formily/react';
import { Space } from 'antd';
import { ArrayField, ObjectField, observer, useField, Field } from '@formily/react';
import { Space, Button, Cascader } from 'antd';
import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { Action } from './Action';
import { ArrayBase } from '@formily/antd-v5';
import { useActionOptions } from './hooks/useActionOptions';
import { CloseCircleOutlined } from '@ant-design/icons';
import { ActionParamsField } from './ActionParams';
interface LinkageRuleActionGroupProps {
type: 'button' | 'field' | 'style';
@ -22,34 +24,48 @@ interface LinkageRuleActionGroupProps {
collectionName: string;
}
export const Actions = withDynamicSchemaProps(
(props: LinkageRuleActionGroupProps) => {
const { t } = useTranslation();
const field = useField<VoidField>();
const { category, elementType, linkageOptions, collectionName } = props;
const components = useMemo(
() => [Action, { category, elementType, linkageOptions, collectionName }],
[collectionName, linkageOptions, category, elementType],
);
const spaceStyle = useMemo(() => ({ marginTop: 8, marginBottom: 8 }), []);
const style = useMemo(() => ({ marginLeft: 10 }), []);
const onClick = useCallback(() => {
const f = field.query('.actions').take() as ArrayFieldModel;
const items = f.value || [];
items.push({});
f.value = items;
f.initialValue = items;
}, [field]);
const Action = observer(
(props: any): any => {
const { onRemove } = props;
const options = useActionOptions();
const field = useField<any>();
field.onFieldChange = (field) => {
console.log('field', field);
};
return (
<div style={style}>
<ArrayField name={'actions'} component={components} disabled={false} />
<Space size={16} style={spaceStyle}>
<a onClick={onClick}>{t('添加动作')}</a>
<Space align="start">
<Field name="action" component={[Cascader, { options, placeholder: '选择动作' }]} />
<ArrayField name={'params'} component={[ActionParamsField, { action: field.value.action?.value }]} />
{!props.disabled && (
<a role="button" aria-label="icon-close">
<CloseCircleOutlined onClick={onRemove} style={{ color: '#bfbfbf' }} />
</a>
)}
</Space>
</div>
);
},
{ displayName: 'ActionRow' },
);
const Actions = withDynamicSchemaProps(
observer((props: LinkageRuleActionGroupProps) => {
const { t } = useTranslation();
const field = useField<ArrayFieldModel>();
return (
<Space style={{ paddingLeft: 10 }} direction="vertical">
{field?.value?.map((item, index) => {
return <ObjectField key={index} name={index} component={[Action, { onRemove: () => field.remove(index) }]} />;
})}
<a onClick={() => field.push({})}>{t('添加动作')}</a>
</Space>
);
}),
{ displayName: 'Actions' },
);
export const ActionsField = withDynamicSchemaProps(
observer((props: LinkageRuleActionGroupProps) => {
return <ArrayField name={'actions'} component={[Actions]} />;
}),
{ displayName: 'ActionsField' },
);

View File

@ -0,0 +1,27 @@
/**
* 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 { useEvent } from '../../../hooks/useEvent';
export function useActionOptions() {
const { definitions } = useEvent();
let treeData = definitions?.map((module) => ({
value: module.name,
label: module.title + ' - ' + module.uid,
children:
module?.actions?.map((event) => ({
value: `${module.name}.${event.name}${module.uid ? `.${module.uid}` : ''}`,
label: event.title,
})) || [],
}));
treeData = treeData?.filter((item) => item.children.length > 0);
return treeData;
}

View File

@ -0,0 +1,27 @@
/**
* 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 { useEvent } from '../../../hooks/useEvent';
export function useActionOptions() {
const { definitions } = useEvent();
let treeData = definitions?.map((module) => ({
value: module.name,
label: module.title + ' - ' + module.uid,
children:
module?.actions?.map((event) => ({
value: `${module.name}.${event.name}${module.uid ? `.${module.uid}` : ''}`,
label: event.title,
})) || [],
}));
treeData = treeData?.filter((item) => item.children.length > 0);
return treeData;
}

View File

@ -20,7 +20,7 @@ import { SubFormProvider } from '../../../schema-component/antd/association-fiel
import { DynamicComponentProps } from '../../../schema-component/antd/filter/DynamicComponent';
import { FilterContext } from '../../../schema-component/antd/filter/context';
import { VariableInput, getShouldChange } from '../../../schema-settings/VariableInput/VariableInput';
import { Actions } from './Actions';
import { ActionsField } from './Actions';
import { FormProvider, createSchemaField } from '@formily/react';
import { ArrayCollapse } from '../components/LinkageHeader';
import { Filter } from '../Filter';
@ -126,7 +126,6 @@ export const ActionsSetting = withDynamicSchemaProps(
getAllCollectionsInheritChain,
})}
returnScope={(scope) => {
// console.log('scope', [...scope, ...variableOptions]);
return uniqBy([...scope, ...variableOptions], 'key');
}}
/>
@ -140,7 +139,7 @@ export const ActionsSetting = withDynamicSchemaProps(
},
actions: {
type: 'void',
'x-component': (_props) => <Actions {..._props} {...props} />,
'x-component': ActionsField,
},
},
},