feat: add custom action (#396)
* feat: add custom operation * feat: add custom operation * fix: fix cancel button hide popup * refactor: save part schema of ActionModal * fix: can not refresh ui * fix: save part schema * fix: revert code * fix: fix pop up * fix: fix pop up * feat: add form custom * fix: acl allow plugins:getPinned * fix: add pop up * feat: fix show callback * fix: update data * refactor: reviert code * fix: update text * feat: finish table custom operation * feat: add form custom operation * fix: refresh update date * refactor: remove default button design item * fix: refresh form values * fix: remove default edit action design item * fix: fix save form values logic error * refactor: refactor code * fix: format schema * fix: table and form update will change all data * fix: insert schema non refresh * fix: fix remote load schema * fix: fix non request while uid unchange * fix: locale change * fix: change x-action to customizePopup * fix: support custom action modal tip content * refactor: refactor custom operation * fix: remove form.setValues * fix: remove stopPropagation * feat: improve translation * feat: popup Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
		
							parent
							
								
									53482c5b22
								
							
						
					
					
						commit
						4cc162d1c1
					
				@ -1,9 +1,11 @@
 | 
			
		||||
import { useField, useFieldSchema, useForm } from '@formily/react';
 | 
			
		||||
import { Modal } from 'antd';
 | 
			
		||||
import { message, Modal } from 'antd';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { useHistory } from 'react-router-dom';
 | 
			
		||||
import { useCollection } from '../../collection-manager';
 | 
			
		||||
import { useRecord } from '../../record-provider';
 | 
			
		||||
import { useActionContext, useCompile } from '../../schema-component';
 | 
			
		||||
import { useCurrentUserContext } from '../../user';
 | 
			
		||||
import { useBlockRequestContext, useFilterByTk } from '../BlockProvider';
 | 
			
		||||
import { useDetailsBlockContext } from '../DetailsBlockProvider';
 | 
			
		||||
import { TableFieldResource } from '../TableFieldProvider';
 | 
			
		||||
@ -65,8 +67,8 @@ export const useCreateActionProps = () => {
 | 
			
		||||
  return {
 | 
			
		||||
    async onClick() {
 | 
			
		||||
      const fieldNames = fields.map((field) => field.name);
 | 
			
		||||
      const skipValidator = actionSchema?.['x-action-settings']?.skipValidator;
 | 
			
		||||
      const overwriteValues = actionSchema?.['x-action-settings']?.overwriteValues;
 | 
			
		||||
      const { assignedValues, onSuccess, overwriteValues, skipValidator } = actionSchema?.['x-action-settings'] ?? {};
 | 
			
		||||
 | 
			
		||||
      if (!skipValidator) {
 | 
			
		||||
        await form.submit();
 | 
			
		||||
      }
 | 
			
		||||
@ -107,28 +109,79 @@ export const useCreateActionProps = () => {
 | 
			
		||||
        values: {
 | 
			
		||||
          ...values,
 | 
			
		||||
          ...overwriteValues,
 | 
			
		||||
          ...assignedValues,
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
      actionField.data.loading = false;
 | 
			
		||||
      __parent?.service?.refresh?.();
 | 
			
		||||
      setVisible?.(false);
 | 
			
		||||
      const onSuccess = actionSchema?.['x-action-settings']?.onSuccess;
 | 
			
		||||
      if (!onSuccess?.successMessage) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      Modal.success({
 | 
			
		||||
        title: compile(onSuccess?.successMessage),
 | 
			
		||||
        onOk: async () => {
 | 
			
		||||
          await form.reset();
 | 
			
		||||
          if (onSuccess?.redirecting && onSuccess?.redirectTo) {
 | 
			
		||||
            if (isURL(onSuccess.redirectTo)) {
 | 
			
		||||
              window.location.href = onSuccess.redirectTo;
 | 
			
		||||
            } else {
 | 
			
		||||
              history.push(onSuccess.redirectTo);
 | 
			
		||||
      if (onSuccess?.manualClose) {
 | 
			
		||||
        Modal.success({
 | 
			
		||||
          title: compile(onSuccess?.successMessage),
 | 
			
		||||
          onOk: async () => {
 | 
			
		||||
            await form.reset();
 | 
			
		||||
            if (onSuccess?.redirecting && onSuccess?.redirectTo) {
 | 
			
		||||
              if (isURL(onSuccess.redirectTo)) {
 | 
			
		||||
                window.location.href = onSuccess.redirectTo;
 | 
			
		||||
              } else {
 | 
			
		||||
                history.push(onSuccess.redirectTo);
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        message.success(compile(onSuccess?.successMessage));
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const useCustomizeUpdateActionProps = () => {
 | 
			
		||||
  const { resource, __parent, service } = useBlockRequestContext();
 | 
			
		||||
  const filterByTk = useFilterByTk();
 | 
			
		||||
  const actionSchema = useFieldSchema();
 | 
			
		||||
  const currentRecord = useRecord();
 | 
			
		||||
  const ctx = useCurrentUserContext();
 | 
			
		||||
  const history = useHistory();
 | 
			
		||||
  const compile = useCompile();
 | 
			
		||||
  const form = useForm();
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    async onClick() {
 | 
			
		||||
      const { assignedValues, onSuccess, skipValidator } = actionSchema?.['x-action-settings'] ?? {};
 | 
			
		||||
      if (skipValidator === false) {
 | 
			
		||||
        await form.submit();
 | 
			
		||||
      }
 | 
			
		||||
      await resource.update({
 | 
			
		||||
        filterByTk,
 | 
			
		||||
        values: { ...assignedValues },
 | 
			
		||||
      });
 | 
			
		||||
      service?.refresh?.();
 | 
			
		||||
      if (!(resource instanceof TableFieldResource)) {
 | 
			
		||||
        __parent?.service?.refresh?.();
 | 
			
		||||
      }
 | 
			
		||||
      if (!onSuccess?.successMessage) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      if (onSuccess?.manualClose) {
 | 
			
		||||
        Modal.success({
 | 
			
		||||
          title: compile(onSuccess?.successMessage),
 | 
			
		||||
          onOk: async () => {
 | 
			
		||||
            if (onSuccess?.redirecting && onSuccess?.redirectTo) {
 | 
			
		||||
              if (isURL(onSuccess.redirectTo)) {
 | 
			
		||||
                window.location.href = onSuccess.redirectTo;
 | 
			
		||||
              } else {
 | 
			
		||||
                history.push(onSuccess.redirectTo);
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        message.success(compile(onSuccess?.successMessage));
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
@ -145,8 +198,8 @@ export const useUpdateActionProps = () => {
 | 
			
		||||
  const actionField = useField();
 | 
			
		||||
  return {
 | 
			
		||||
    async onClick() {
 | 
			
		||||
      const skipValidator = actionSchema?.['x-action-settings']?.skipValidator;
 | 
			
		||||
      const overwriteValues = actionSchema?.['x-action-settings']?.overwriteValues;
 | 
			
		||||
      const { assignedValues, onSuccess, overwriteValues, skipValidator } = actionSchema?.['x-action-settings'] ?? {};
 | 
			
		||||
 | 
			
		||||
      if (!skipValidator) {
 | 
			
		||||
        await form.submit();
 | 
			
		||||
      }
 | 
			
		||||
@ -196,6 +249,7 @@ export const useUpdateActionProps = () => {
 | 
			
		||||
        values: {
 | 
			
		||||
          ...values,
 | 
			
		||||
          ...overwriteValues,
 | 
			
		||||
          ...assignedValues,
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
      actionField.data.loading = false;
 | 
			
		||||
@ -204,8 +258,10 @@ export const useUpdateActionProps = () => {
 | 
			
		||||
        __parent?.__parent?.service?.refresh?.();
 | 
			
		||||
      }
 | 
			
		||||
      setVisible?.(false);
 | 
			
		||||
      const onSuccess = actionSchema?.['x-action-settings']?.onSuccess;
 | 
			
		||||
      if (onSuccess?.successMessage) {
 | 
			
		||||
      if (!onSuccess?.successMessage) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      if (onSuccess?.manualClose) {
 | 
			
		||||
        Modal.success({
 | 
			
		||||
          title: compile(onSuccess?.successMessage),
 | 
			
		||||
          onOk: async () => {
 | 
			
		||||
@ -219,6 +275,8 @@ export const useUpdateActionProps = () => {
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        message.success(compile(onSuccess?.successMessage));
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ import { useCollectionField } from './hooks';
 | 
			
		||||
// TODO: 初步适配
 | 
			
		||||
const InternalField: React.FC = (props) => {
 | 
			
		||||
  const field = useField<Field>();
 | 
			
		||||
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const { name, interface: interfaceType, uiSchema } = useCollectionField();
 | 
			
		||||
  const component = useComponent(uiSchema?.['x-component']);
 | 
			
		||||
 | 
			
		||||
@ -288,4 +288,15 @@ export default {
 | 
			
		||||
 | 
			
		||||
  'Unsaved changes': 'Unsaved changes',
 | 
			
		||||
  'Are you sure you don\'t want to save?': 'Are you sure you don\'t want to save?',
 | 
			
		||||
 | 
			
		||||
  'Popup': 'Popup',
 | 
			
		||||
  'Trigger workflow': 'Trigger workflow',
 | 
			
		||||
  'Request API': 'Request API',
 | 
			
		||||
  'Assign field values': 'Assign field values',
 | 
			
		||||
  'Popup close method': 'Popup close method',
 | 
			
		||||
  'Automatic close': 'Automatic close',
 | 
			
		||||
  'Manually close': 'Manually close',
 | 
			
		||||
  'After successful update': 'After successful update',
 | 
			
		||||
  'Save record': 'Save record',
 | 
			
		||||
  'After successful save': 'After successful save',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -365,7 +365,7 @@ export default {
 | 
			
		||||
  'Tab name': '标签名称',
 | 
			
		||||
  'Current record blocks': '当前数据区块',
 | 
			
		||||
 | 
			
		||||
  'Pop-up message': '弹窗提示消息',
 | 
			
		||||
  'Popup message': '弹窗提示消息',
 | 
			
		||||
 | 
			
		||||
  'Delete role': '删除角色',
 | 
			
		||||
 | 
			
		||||
@ -487,4 +487,22 @@ export default {
 | 
			
		||||
  'Unsaved changes': '未保存修改',
 | 
			
		||||
  'Are you sure you don\'t want to save?': '你确定不保存修改吗?',
 | 
			
		||||
  'Dragging': '拖拽中',
 | 
			
		||||
 | 
			
		||||
  'Popup': '打开弹窗',
 | 
			
		||||
  'Trigger workflow': '触发工作流',
 | 
			
		||||
  'Request API': '请求API',
 | 
			
		||||
  'Assign field values': '字段赋值',
 | 
			
		||||
  'Constant value': '静态值',
 | 
			
		||||
  'Dynamic value': '动态值',
 | 
			
		||||
  'Current user': '当前用户',
 | 
			
		||||
  'Current record': '当前记录',
 | 
			
		||||
  'Popup close method': '弹窗关闭方式',
 | 
			
		||||
  'Automatic close': '自动关闭',
 | 
			
		||||
  'Manually close': '手动关闭',
 | 
			
		||||
  'After successful update': '更新成功后',
 | 
			
		||||
  'Save record': '保存数据',
 | 
			
		||||
  'Updated successfully': '更新成功',
 | 
			
		||||
  'After successful save': '保存成功后',
 | 
			
		||||
  'After clicking the custom button, the following field values will be assigned according to the following form.': '点击当前自定义按钮时,以下字段值将按照以下表单赋值。',
 | 
			
		||||
  'After clicking the custom button, The following fields of the current record will be saved according to the following form.': '点击当前自定义按钮时,当前数据以下字段将按照以下表单保存。',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,121 +1,154 @@
 | 
			
		||||
import { ISchema, useField, useFieldSchema } from '@formily/react';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { isValid } from '@formily/shared';
 | 
			
		||||
import { uid } from '@nocobase/utils';
 | 
			
		||||
import { Menu } from 'antd';
 | 
			
		||||
import React, { useEffect, useState } from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { useDesignable } from '../..';
 | 
			
		||||
import { useActionContext, useCompile, useDesignable } from '../..';
 | 
			
		||||
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
 | 
			
		||||
 | 
			
		||||
const MenuGroup = (props) => {
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const actionType = fieldSchema['x-action'] || '';
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const actionTitles = {
 | 
			
		||||
    'customize:popup': t('Popup'),
 | 
			
		||||
    'customize:update': t('Update record'),
 | 
			
		||||
    'customize:save': t('Save record'),
 | 
			
		||||
  };
 | 
			
		||||
  if (!['customize:popup', 'customize:update', 'customize:save'].includes(actionType)) {
 | 
			
		||||
    return <>{props.children}</>;
 | 
			
		||||
  }
 | 
			
		||||
  return <Menu.ItemGroup title={`${t('Customize')} > ${actionTitles[actionType]}`}>{props.children}</Menu.ItemGroup>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const ActionDesigner = (props) => {
 | 
			
		||||
  const { modalTip, ...restProps } = props;
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const { dn } = useDesignable();
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const isPopupAction = ['create', 'update', 'view'].includes(fieldSchema['x-action'] || '');
 | 
			
		||||
  const compile = useCompile();
 | 
			
		||||
  const isPopupAction = ['create', 'update', 'view', 'customize:popup'].includes(fieldSchema['x-action'] || '');
 | 
			
		||||
  const context = useActionContext();
 | 
			
		||||
  const [initialSchema, setInitialSchema] = useState<ISchema>();
 | 
			
		||||
  const actionType = fieldSchema['x-action'] || '';
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const schemaUid = uid();
 | 
			
		||||
    const schema: ISchema = {
 | 
			
		||||
      type: 'void',
 | 
			
		||||
      'x-uid': schemaUid,
 | 
			
		||||
      'x-component': 'Grid',
 | 
			
		||||
      'x-initializer': 'CustomFormItemInitializers',
 | 
			
		||||
    };
 | 
			
		||||
    setInitialSchema(schema);
 | 
			
		||||
  }, [field.address]);
 | 
			
		||||
 | 
			
		||||
  const tips = {
 | 
			
		||||
    'customize:update': t(
 | 
			
		||||
      'After clicking the custom button, The following fields of the current record will be saved according to the following form.',
 | 
			
		||||
    ),
 | 
			
		||||
    'customize:save': t(
 | 
			
		||||
      'After clicking the custom button, The following fields of the current record will be saved according to the following form.',
 | 
			
		||||
    ),
 | 
			
		||||
  };
 | 
			
		||||
  return (
 | 
			
		||||
    <GeneralSchemaDesigner {...props} disableInitializer>
 | 
			
		||||
      <SchemaSettings.ModalItem
 | 
			
		||||
        title={t('Edit button')}
 | 
			
		||||
        schema={
 | 
			
		||||
          {
 | 
			
		||||
            type: 'object',
 | 
			
		||||
            title: t('Edit button'),
 | 
			
		||||
            properties: {
 | 
			
		||||
              title: {
 | 
			
		||||
                'x-decorator': 'FormItem',
 | 
			
		||||
                'x-component': 'Input',
 | 
			
		||||
                title: t('Button title'),
 | 
			
		||||
                default: fieldSchema.title,
 | 
			
		||||
                'x-component-props': {},
 | 
			
		||||
                // description: `原字段标题:${collectionField?.uiSchema?.title}`,
 | 
			
		||||
              },
 | 
			
		||||
              icon: {
 | 
			
		||||
                'x-decorator': 'FormItem',
 | 
			
		||||
                'x-component': 'IconPicker',
 | 
			
		||||
                title: t('Button icon'),
 | 
			
		||||
                default: fieldSchema?.['x-component-props']?.icon,
 | 
			
		||||
                'x-component-props': {},
 | 
			
		||||
                // description: `原字段标题:${collectionField?.uiSchema?.title}`,
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          } as ISchema
 | 
			
		||||
        }
 | 
			
		||||
        onSubmit={({ title, icon }) => {
 | 
			
		||||
          if (title) {
 | 
			
		||||
            fieldSchema.title = title;
 | 
			
		||||
            field.title = title;
 | 
			
		||||
            field.componentProps.icon = icon;
 | 
			
		||||
            fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
 | 
			
		||||
            fieldSchema['x-component-props'].icon = icon;
 | 
			
		||||
            dn.emit('patch', {
 | 
			
		||||
              schema: {
 | 
			
		||||
                ['x-uid']: fieldSchema['x-uid'],
 | 
			
		||||
                title,
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  ...fieldSchema['x-component-props'],
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            });
 | 
			
		||||
            dn.refresh();
 | 
			
		||||
          }
 | 
			
		||||
        }}
 | 
			
		||||
      />
 | 
			
		||||
      {isPopupAction && (
 | 
			
		||||
        <SchemaSettings.SelectItem
 | 
			
		||||
          title={t('Open mode')}
 | 
			
		||||
          options={[
 | 
			
		||||
            { label: t('Drawer'), value: 'drawer' },
 | 
			
		||||
            { label: t('Dialog'), value: 'modal' },
 | 
			
		||||
          ]}
 | 
			
		||||
          value={fieldSchema?.['x-component-props']?.['openMode']}
 | 
			
		||||
          onChange={(value) => {
 | 
			
		||||
            field.componentProps.openMode = value;
 | 
			
		||||
            fieldSchema['x-component-props']['openMode'] = value;
 | 
			
		||||
            dn.emit('patch', {
 | 
			
		||||
              schema: {
 | 
			
		||||
                'x-uid': fieldSchema['x-uid'],
 | 
			
		||||
                'x-component-props': fieldSchema['x-component-props'],
 | 
			
		||||
              },
 | 
			
		||||
            });
 | 
			
		||||
            dn.refresh();
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
      {fieldSchema?.['x-action-settings'] && (
 | 
			
		||||
        <SchemaSettings.SwitchItem
 | 
			
		||||
          title={t('Skip required validation')}
 | 
			
		||||
          checked={!!fieldSchema?.['x-action-settings']?.skipValidator}
 | 
			
		||||
          onChange={(value) => {
 | 
			
		||||
            fieldSchema['x-action-settings'].skipValidator = value;
 | 
			
		||||
            dn.emit('patch', {
 | 
			
		||||
              schema: {
 | 
			
		||||
                ['x-uid']: fieldSchema['x-uid'],
 | 
			
		||||
                'x-action-settings': {
 | 
			
		||||
                  ...fieldSchema['x-action-settings'],
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            });
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
      {fieldSchema?.['x-action-settings'] && (
 | 
			
		||||
    <GeneralSchemaDesigner {...restProps} disableInitializer>
 | 
			
		||||
      <MenuGroup>
 | 
			
		||||
        <SchemaSettings.ModalItem
 | 
			
		||||
          title={t('Form values')}
 | 
			
		||||
          title={t('Edit button')}
 | 
			
		||||
          schema={
 | 
			
		||||
            {
 | 
			
		||||
              type: 'object',
 | 
			
		||||
              title: t('Edit button'),
 | 
			
		||||
              properties: {
 | 
			
		||||
                overwriteValues: {
 | 
			
		||||
                  title: t('When submitting the following fields, the saved values are'),
 | 
			
		||||
                title: {
 | 
			
		||||
                  'x-decorator': 'FormItem',
 | 
			
		||||
                  'x-component': 'Input.TextArea',
 | 
			
		||||
                  default: JSON.stringify(fieldSchema?.['x-action-settings']?.overwriteValues),
 | 
			
		||||
                  'x-component': 'Input',
 | 
			
		||||
                  title: t('Button title'),
 | 
			
		||||
                  default: fieldSchema.title,
 | 
			
		||||
                  'x-component-props': {},
 | 
			
		||||
                  // description: `原字段标题:${collectionField?.uiSchema?.title}`,
 | 
			
		||||
                },
 | 
			
		||||
                icon: {
 | 
			
		||||
                  'x-decorator': 'FormItem',
 | 
			
		||||
                  'x-component': 'IconPicker',
 | 
			
		||||
                  title: t('Button icon'),
 | 
			
		||||
                  default: fieldSchema?.['x-component-props']?.icon,
 | 
			
		||||
                  'x-component-props': {},
 | 
			
		||||
                  // description: `原字段标题:${collectionField?.uiSchema?.title}`,
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            } as ISchema
 | 
			
		||||
          }
 | 
			
		||||
          onSubmit={({ overwriteValues }) => {
 | 
			
		||||
            try {
 | 
			
		||||
              const values = JSON.parse(overwriteValues);
 | 
			
		||||
              fieldSchema['x-action-settings'].overwriteValues = values;
 | 
			
		||||
          onSubmit={({ title, icon }) => {
 | 
			
		||||
            if (title) {
 | 
			
		||||
              fieldSchema.title = title;
 | 
			
		||||
              field.title = title;
 | 
			
		||||
              field.componentProps.icon = icon;
 | 
			
		||||
              fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
 | 
			
		||||
              fieldSchema['x-component-props'].icon = icon;
 | 
			
		||||
              dn.emit('patch', {
 | 
			
		||||
                schema: {
 | 
			
		||||
                  ['x-uid']: fieldSchema['x-uid'],
 | 
			
		||||
                  title,
 | 
			
		||||
                  'x-component-props': {
 | 
			
		||||
                    ...fieldSchema['x-component-props'],
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
              });
 | 
			
		||||
              dn.refresh();
 | 
			
		||||
            }
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
        {isPopupAction && (
 | 
			
		||||
          <SchemaSettings.SelectItem
 | 
			
		||||
            title={t('Open mode')}
 | 
			
		||||
            options={[
 | 
			
		||||
              { label: t('Drawer'), value: 'drawer' },
 | 
			
		||||
              { label: t('Dialog'), value: 'modal' },
 | 
			
		||||
            ]}
 | 
			
		||||
            value={fieldSchema?.['x-component-props']?.['openMode']}
 | 
			
		||||
            onChange={(value) => {
 | 
			
		||||
              field.componentProps.openMode = value;
 | 
			
		||||
              fieldSchema['x-component-props']['openMode'] = value;
 | 
			
		||||
              dn.emit('patch', {
 | 
			
		||||
                schema: {
 | 
			
		||||
                  'x-uid': fieldSchema['x-uid'],
 | 
			
		||||
                  'x-component-props': fieldSchema['x-component-props'],
 | 
			
		||||
                },
 | 
			
		||||
              });
 | 
			
		||||
              dn.refresh();
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        )}
 | 
			
		||||
 | 
			
		||||
        {isValid(fieldSchema?.['x-action-settings']?.assignedValues) && (
 | 
			
		||||
          <SchemaSettings.ActionModalItem
 | 
			
		||||
            title={t('Assign field values')}
 | 
			
		||||
            initialSchema={initialSchema}
 | 
			
		||||
            initialValues={fieldSchema?.['x-action-settings']?.assignedValues}
 | 
			
		||||
            modalTip={tips[actionType]}
 | 
			
		||||
            uid={fieldSchema?.['x-action-settings']?.schemaUid}
 | 
			
		||||
            onSubmit={(assignedValues) => {
 | 
			
		||||
              fieldSchema['x-action-settings']['assignedValues'] = assignedValues;
 | 
			
		||||
              dn.emit('patch', {
 | 
			
		||||
                schema: {
 | 
			
		||||
                  ['x-uid']: fieldSchema['x-uid'],
 | 
			
		||||
                  'x-action-settings': fieldSchema['x-action-settings'],
 | 
			
		||||
                },
 | 
			
		||||
              });
 | 
			
		||||
              dn.refresh();
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        )}
 | 
			
		||||
        {isValid(fieldSchema?.['x-action-settings']?.skipValidator) && (
 | 
			
		||||
          <SchemaSettings.SwitchItem
 | 
			
		||||
            title={t('Skip required validation')}
 | 
			
		||||
            checked={!!fieldSchema?.['x-action-settings']?.skipValidator}
 | 
			
		||||
            onChange={(value) => {
 | 
			
		||||
              fieldSchema['x-action-settings'].skipValidator = value;
 | 
			
		||||
              dn.emit('patch', {
 | 
			
		||||
                schema: {
 | 
			
		||||
                  ['x-uid']: fieldSchema['x-uid'],
 | 
			
		||||
@ -124,76 +157,123 @@ export const ActionDesigner = (props) => {
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
              });
 | 
			
		||||
              dn.refresh();
 | 
			
		||||
            } catch (e) {}
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
      {fieldSchema?.['x-action-settings'] && (
 | 
			
		||||
        <SchemaSettings.ModalItem
 | 
			
		||||
          title={t('After successful submission')}
 | 
			
		||||
          initialValues={fieldSchema?.['x-action-settings']?.['onSuccess']}
 | 
			
		||||
          schema={
 | 
			
		||||
            {
 | 
			
		||||
              type: 'object',
 | 
			
		||||
              title: t('After successful submission'),
 | 
			
		||||
              properties: {
 | 
			
		||||
                successMessage: {
 | 
			
		||||
                  // default: t('Submitted successfully!'),
 | 
			
		||||
                  title: t('Pop-up message'),
 | 
			
		||||
                  'x-decorator': 'FormItem',
 | 
			
		||||
                  'x-component': 'Input.TextArea',
 | 
			
		||||
                  'x-component-props': {},
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        )}
 | 
			
		||||
        {isValid(fieldSchema?.['x-action-settings']?.overwriteValues) && (
 | 
			
		||||
          <SchemaSettings.ModalItem
 | 
			
		||||
            title={t('Form values')}
 | 
			
		||||
            schema={
 | 
			
		||||
              {
 | 
			
		||||
                type: 'object',
 | 
			
		||||
                properties: {
 | 
			
		||||
                  overwriteValues: {
 | 
			
		||||
                    title: t('When submitting the following fields, the saved values are'),
 | 
			
		||||
                    'x-decorator': 'FormItem',
 | 
			
		||||
                    'x-component': 'Input.TextArea',
 | 
			
		||||
                    default: JSON.stringify(fieldSchema?.['x-action-settings']?.overwriteValues),
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
                redirecting: {
 | 
			
		||||
                  title: t('Then'),
 | 
			
		||||
                  default: false,
 | 
			
		||||
                  enum: [
 | 
			
		||||
                    { label: t('Stay on current page'), value: false },
 | 
			
		||||
                    { label: t('Redirect to'), value: true },
 | 
			
		||||
                  ],
 | 
			
		||||
                  'x-decorator': 'FormItem',
 | 
			
		||||
                  'x-component': 'Radio.Group',
 | 
			
		||||
                  'x-component-props': {},
 | 
			
		||||
                  'x-reactions': {
 | 
			
		||||
                    target: 'redirectTo',
 | 
			
		||||
                    fulfill: {
 | 
			
		||||
                      state: {
 | 
			
		||||
                        visible: '{{!!$self.value}}',
 | 
			
		||||
              } as ISchema
 | 
			
		||||
            }
 | 
			
		||||
            onSubmit={({ overwriteValues }) => {
 | 
			
		||||
              try {
 | 
			
		||||
                const values = JSON.parse(overwriteValues);
 | 
			
		||||
                fieldSchema['x-action-settings'].overwriteValues = values;
 | 
			
		||||
                dn.emit('patch', {
 | 
			
		||||
                  schema: {
 | 
			
		||||
                    ['x-uid']: fieldSchema['x-uid'],
 | 
			
		||||
                    'x-action-settings': {
 | 
			
		||||
                      ...fieldSchema['x-action-settings'],
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
                });
 | 
			
		||||
                dn.refresh();
 | 
			
		||||
              } catch (e) {}
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        )}
 | 
			
		||||
        {isValid(fieldSchema?.['x-action-settings']?.['onSuccess']) && (
 | 
			
		||||
          <SchemaSettings.ModalItem
 | 
			
		||||
            title={
 | 
			
		||||
              compile(fieldSchema?.['x-action-settings']?.['onSuccess']?.['title']) ?? t('After successful submission')
 | 
			
		||||
            }
 | 
			
		||||
            initialValues={fieldSchema?.['x-action-settings']?.['onSuccess']}
 | 
			
		||||
            schema={
 | 
			
		||||
              {
 | 
			
		||||
                type: 'object',
 | 
			
		||||
                title: {
 | 
			
		||||
                  'customize:save': t('After successful save'),
 | 
			
		||||
                  'customize:update': t('After successful update'),
 | 
			
		||||
                }[actionType],
 | 
			
		||||
                properties: {
 | 
			
		||||
                  successMessage: {
 | 
			
		||||
                    title: t('Popup message'),
 | 
			
		||||
                    'x-decorator': 'FormItem',
 | 
			
		||||
                    'x-component': 'Input.TextArea',
 | 
			
		||||
                    'x-component-props': {},
 | 
			
		||||
                  },
 | 
			
		||||
                  manualClose: {
 | 
			
		||||
                    title: t('Popup close method'),
 | 
			
		||||
                    default: false,
 | 
			
		||||
                    enum: [
 | 
			
		||||
                      { label: t('Automatic close'), value: false },
 | 
			
		||||
                      { label: t('Manually close'), value: true },
 | 
			
		||||
                    ],
 | 
			
		||||
                    'x-decorator': 'FormItem',
 | 
			
		||||
                    'x-component': 'Radio.Group',
 | 
			
		||||
                    'x-component-props': {},
 | 
			
		||||
                  },
 | 
			
		||||
                  redirecting: {
 | 
			
		||||
                    title: t('Then'),
 | 
			
		||||
                    default: false,
 | 
			
		||||
                    enum: [
 | 
			
		||||
                      { label: t('Stay on current page'), value: false },
 | 
			
		||||
                      { label: t('Redirect to'), value: true },
 | 
			
		||||
                    ],
 | 
			
		||||
                    'x-decorator': 'FormItem',
 | 
			
		||||
                    'x-component': 'Radio.Group',
 | 
			
		||||
                    'x-component-props': {},
 | 
			
		||||
                    'x-reactions': {
 | 
			
		||||
                      target: 'redirectTo',
 | 
			
		||||
                      fulfill: {
 | 
			
		||||
                        state: {
 | 
			
		||||
                          visible: '{{!!$self.value}}',
 | 
			
		||||
                        },
 | 
			
		||||
                      },
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
                  redirectTo: {
 | 
			
		||||
                    title: t('Link'),
 | 
			
		||||
                    'x-decorator': 'FormItem',
 | 
			
		||||
                    'x-component': 'Input',
 | 
			
		||||
                    'x-component-props': {},
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
                redirectTo: {
 | 
			
		||||
                  title: t('Link'),
 | 
			
		||||
                  'x-decorator': 'FormItem',
 | 
			
		||||
                  'x-component': 'Input',
 | 
			
		||||
                  'x-component-props': {},
 | 
			
		||||
              } as ISchema
 | 
			
		||||
            }
 | 
			
		||||
            onSubmit={(onSuccess) => {
 | 
			
		||||
              fieldSchema['x-action-settings']['onSuccess'] = onSuccess;
 | 
			
		||||
              dn.emit('patch', {
 | 
			
		||||
                schema: {
 | 
			
		||||
                  ['x-uid']: fieldSchema['x-uid'],
 | 
			
		||||
                  'x-action-settings': fieldSchema['x-action-settings'],
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            } as ISchema
 | 
			
		||||
          }
 | 
			
		||||
          onSubmit={(onSuccess) => {
 | 
			
		||||
            fieldSchema['x-action-settings']['onSuccess'] = onSuccess;
 | 
			
		||||
            dn.emit('patch', {
 | 
			
		||||
              schema: {
 | 
			
		||||
                ['x-uid']: fieldSchema['x-uid'],
 | 
			
		||||
                'x-action-settings': fieldSchema['x-action-settings'],
 | 
			
		||||
              },
 | 
			
		||||
            });
 | 
			
		||||
              });
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        )}
 | 
			
		||||
        <SchemaSettings.Divider />
 | 
			
		||||
        <SchemaSettings.Remove
 | 
			
		||||
          removeParentsIfNoChildren
 | 
			
		||||
          breakRemoveOn={(s) => {
 | 
			
		||||
            return s['x-component'] === 'Space' || s['x-component'].endsWith('ActionBar');
 | 
			
		||||
          }}
 | 
			
		||||
          confirm={{
 | 
			
		||||
            title: t('Delete action'),
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
      <SchemaSettings.Divider />
 | 
			
		||||
      <SchemaSettings.Remove
 | 
			
		||||
        removeParentsIfNoChildren
 | 
			
		||||
        breakRemoveOn={(s) => {
 | 
			
		||||
          return s['x-component'] === 'Space' || s['x-component'].endsWith('ActionBar');
 | 
			
		||||
        }}
 | 
			
		||||
        confirm={{
 | 
			
		||||
          title: t('Delete action')
 | 
			
		||||
        }}
 | 
			
		||||
      />
 | 
			
		||||
      </MenuGroup>
 | 
			
		||||
    </GeneralSchemaDesigner>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -25,11 +25,11 @@ export const useActionContext = () => {
 | 
			
		||||
              content: t("Are you sure you don't want to save?"),
 | 
			
		||||
              async onOk() {
 | 
			
		||||
                ctx.setFormValueChanged(false);
 | 
			
		||||
                ctx.setVisible(false);
 | 
			
		||||
                ctx.setVisible?.(false);
 | 
			
		||||
              },
 | 
			
		||||
            });
 | 
			
		||||
          } else {
 | 
			
		||||
            ctx.setVisible(false);
 | 
			
		||||
            ctx?.setVisible?.(false);
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          ctx?.setVisible?.(visible);
 | 
			
		||||
 | 
			
		||||
@ -46,7 +46,7 @@ export const MarkdownVoid: any = observer((props: any) => {
 | 
			
		||||
  const schema = useFieldSchema();
 | 
			
		||||
  const { dn } = useDesignable();
 | 
			
		||||
  const { onSave, onCancel } = props;
 | 
			
		||||
  return field.editable ? (
 | 
			
		||||
  return field?.editable ? (
 | 
			
		||||
    <MarkdownEditor
 | 
			
		||||
      {...props}
 | 
			
		||||
      defaultValue={content}
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@ import { isPlainObj } from '@formily/shared';
 | 
			
		||||
import React, { createContext, useContext } from 'react';
 | 
			
		||||
import { SchemaComponentOptions } from '../schema-component';
 | 
			
		||||
import * as globals from './buttons';
 | 
			
		||||
import * as initializerComponents from './components';
 | 
			
		||||
import * as items from './items';
 | 
			
		||||
import { SchemaInitializer } from './SchemaInitializer';
 | 
			
		||||
 | 
			
		||||
@ -49,7 +50,9 @@ export const SchemaInitializerProvider: React.FC<SchemaInitializerProviderProps>
 | 
			
		||||
  const { initializers, components, children } = props;
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializerContext.Provider value={{ ...globals, ...initializers }}>
 | 
			
		||||
      <SchemaComponentOptions components={{ ...items, ...components }}>{children}</SchemaComponentOptions>
 | 
			
		||||
      <SchemaComponentOptions components={{ ...items, ...components, ...initializerComponents }}>
 | 
			
		||||
        {children}
 | 
			
		||||
      </SchemaComponentOptions>
 | 
			
		||||
    </SchemaInitializerContext.Provider>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,26 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { SchemaInitializer } from '../SchemaInitializer';
 | 
			
		||||
import { gridRowColWrap, useCustomFormItemInitializerFields } from '../utils';
 | 
			
		||||
 | 
			
		||||
// 表单里配置字段
 | 
			
		||||
export const CustomFormItemInitializers = (props: any) => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const { insertPosition, component } = props;
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      wrap={gridRowColWrap}
 | 
			
		||||
      icon={'SettingOutlined'}
 | 
			
		||||
      items={[
 | 
			
		||||
        {
 | 
			
		||||
          type: 'itemGroup',
 | 
			
		||||
          title: t('Configure fields'),
 | 
			
		||||
          children: useCustomFormItemInitializerFields(),
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
      insertPosition={insertPosition}
 | 
			
		||||
      component={component}
 | 
			
		||||
      title={component ? null : t('Configure fields')}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
 | 
			
		||||
// 表单的操作配置
 | 
			
		||||
export const FormActionInitializers = {
 | 
			
		||||
  title: '{{t("Configure actions")}}',
 | 
			
		||||
@ -13,12 +12,7 @@ export const FormActionInitializers = {
 | 
			
		||||
          title: '{{t("Submit")}}',
 | 
			
		||||
          component: 'CreateSubmitActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            'x-action-settings': {
 | 
			
		||||
              initialValues: {},
 | 
			
		||||
              onSuccess: {
 | 
			
		||||
                successMessage: '{{t("Submitted successfully")}}',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            'x-action-settings': {},
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
@ -32,16 +26,74 @@ export const FormActionInitializers = {
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: '{{t("Save action")}}',
 | 
			
		||||
          title: '{{t("Popup")}}',
 | 
			
		||||
          component: 'CustomizeActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: '{{ t("Save") }}',
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            title: '{{ t("Popup") }}',
 | 
			
		||||
            'x-action': 'customize:popup',
 | 
			
		||||
            'x-designer': 'Action.Designer',
 | 
			
		||||
            'x-component': 'Action',
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              openMode: 'drawer',
 | 
			
		||||
            },
 | 
			
		||||
            properties: {
 | 
			
		||||
              drawer: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                title: '{{ t("Popup") }}',
 | 
			
		||||
                'x-component': 'Action.Container',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  className: 'nb-action-popup',
 | 
			
		||||
                },
 | 
			
		||||
                properties: {
 | 
			
		||||
                  tabs: {
 | 
			
		||||
                    type: 'void',
 | 
			
		||||
                    'x-component': 'Tabs',
 | 
			
		||||
                    'x-component-props': {},
 | 
			
		||||
                    'x-initializer': 'TabPaneInitializers',
 | 
			
		||||
                    properties: {
 | 
			
		||||
                      tab1: {
 | 
			
		||||
                        type: 'void',
 | 
			
		||||
                        title: '{{t("Details")}}',
 | 
			
		||||
                        'x-component': 'Tabs.TabPane',
 | 
			
		||||
                        'x-designer': 'Tabs.Designer',
 | 
			
		||||
                        'x-component-props': {},
 | 
			
		||||
                        properties: {
 | 
			
		||||
                          grid: {
 | 
			
		||||
                            type: 'void',
 | 
			
		||||
                            'x-component': 'Grid',
 | 
			
		||||
                            'x-initializer': 'RecordBlockInitializers',
 | 
			
		||||
                            properties: {},
 | 
			
		||||
                          },
 | 
			
		||||
                        },
 | 
			
		||||
                      },
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: '{{t("Save record")}}',
 | 
			
		||||
          component: 'CustomizeActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: '{{ t("Save record") }}',
 | 
			
		||||
            'x-action': 'customize:save',
 | 
			
		||||
            'x-component': 'Action',
 | 
			
		||||
            'x-designer': 'Action.Designer',
 | 
			
		||||
            'x-designer-props': {
 | 
			
		||||
              modalTip:
 | 
			
		||||
                '{{ t("When the button is clicked, the following fields will be assigned and saved together with the fields in the form. If there are overlapping fields, the value here will overwrite the value in the form.") }}',
 | 
			
		||||
            },
 | 
			
		||||
            'x-action-settings': {
 | 
			
		||||
              initialValues: {},
 | 
			
		||||
              assignedValues: {},
 | 
			
		||||
              skipValidator: false,
 | 
			
		||||
              onSuccess: {
 | 
			
		||||
                successMessage: '{{t("Submitted successfully")}}',
 | 
			
		||||
                manualClose: true,
 | 
			
		||||
                redirecting: false,
 | 
			
		||||
                successMessage: '{{t("Saved successfully")}}',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
@ -67,9 +119,7 @@ export const CreateFormActionInitializers = {
 | 
			
		||||
          title: '{{t("Submit")}}',
 | 
			
		||||
          component: 'CreateSubmitActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            'x-action-settings': {
 | 
			
		||||
              overwriteValues: {},
 | 
			
		||||
            },
 | 
			
		||||
            'x-action-settings': {},
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
@ -83,14 +133,75 @@ export const CreateFormActionInitializers = {
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: '{{t("Save action")}}',
 | 
			
		||||
          title: '{{t("Popup")}}',
 | 
			
		||||
          component: 'CustomizeActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: '{{ t("Save") }}',
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            title: '{{ t("Popup") }}',
 | 
			
		||||
            'x-action': 'customize:popup',
 | 
			
		||||
            'x-designer': 'Action.Designer',
 | 
			
		||||
            'x-component': 'Action',
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              openMode: 'drawer',
 | 
			
		||||
            },
 | 
			
		||||
            properties: {
 | 
			
		||||
              drawer: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                title: '{{ t("Popup") }}',
 | 
			
		||||
                'x-component': 'Action.Container',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  className: 'nb-action-popup',
 | 
			
		||||
                },
 | 
			
		||||
                properties: {
 | 
			
		||||
                  tabs: {
 | 
			
		||||
                    type: 'void',
 | 
			
		||||
                    'x-component': 'Tabs',
 | 
			
		||||
                    'x-component-props': {},
 | 
			
		||||
                    'x-initializer': 'TabPaneInitializers',
 | 
			
		||||
                    properties: {
 | 
			
		||||
                      tab1: {
 | 
			
		||||
                        type: 'void',
 | 
			
		||||
                        title: '{{t("Details")}}',
 | 
			
		||||
                        'x-component': 'Tabs.TabPane',
 | 
			
		||||
                        'x-designer': 'Tabs.Designer',
 | 
			
		||||
                        'x-component-props': {},
 | 
			
		||||
                        properties: {
 | 
			
		||||
                          grid: {
 | 
			
		||||
                            type: 'void',
 | 
			
		||||
                            'x-component': 'Grid',
 | 
			
		||||
                            'x-initializer': 'RecordBlockInitializers',
 | 
			
		||||
                            properties: {},
 | 
			
		||||
                          },
 | 
			
		||||
                        },
 | 
			
		||||
                      },
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: '{{t("Save record")}}',
 | 
			
		||||
          component: 'CustomizeActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: '{{ t("Save record") }}',
 | 
			
		||||
            'x-action': 'customize:save',
 | 
			
		||||
            'x-component': 'Action',
 | 
			
		||||
            'x-designer': 'Action.Designer',
 | 
			
		||||
            'x-designer-props': {
 | 
			
		||||
              modalTip:
 | 
			
		||||
                '{{ t("When the button is clicked, the following fields will be assigned and saved together with the fields in the form. If there are overlapping fields, the value here will overwrite the value in the form.") }}',
 | 
			
		||||
            },
 | 
			
		||||
            'x-action-settings': {
 | 
			
		||||
              overwriteValues: {},
 | 
			
		||||
              assignedValues: {},
 | 
			
		||||
              skipValidator: false,
 | 
			
		||||
              onSuccess: {
 | 
			
		||||
                manualClose: true,
 | 
			
		||||
                redirecting: false,
 | 
			
		||||
                successMessage: '{{t("Saved successfully")}}',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              useProps: '{{ useCreateActionProps }}',
 | 
			
		||||
@ -115,9 +226,7 @@ export const UpdateFormActionInitializers = {
 | 
			
		||||
          title: '{{t("Submit")}}',
 | 
			
		||||
          component: 'UpdateSubmitActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            'x-action-settings': {
 | 
			
		||||
              overwriteValues: {},
 | 
			
		||||
            },
 | 
			
		||||
            'x-action-settings': {},
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
@ -131,14 +240,75 @@ export const UpdateFormActionInitializers = {
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: '{{t("Save action")}}',
 | 
			
		||||
          title: '{{t("Popup")}}',
 | 
			
		||||
          component: 'CustomizeActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            title: '{{ t("Popup") }}',
 | 
			
		||||
            'x-action': 'customize:popup',
 | 
			
		||||
            'x-designer': 'Action.Designer',
 | 
			
		||||
            'x-component': 'Action',
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              openMode: 'drawer',
 | 
			
		||||
            },
 | 
			
		||||
            properties: {
 | 
			
		||||
              drawer: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                title: '{{ t("Popup") }}',
 | 
			
		||||
                'x-component': 'Action.Container',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  className: 'nb-action-popup',
 | 
			
		||||
                },
 | 
			
		||||
                properties: {
 | 
			
		||||
                  tabs: {
 | 
			
		||||
                    type: 'void',
 | 
			
		||||
                    'x-component': 'Tabs',
 | 
			
		||||
                    'x-component-props': {},
 | 
			
		||||
                    'x-initializer': 'TabPaneInitializers',
 | 
			
		||||
                    properties: {
 | 
			
		||||
                      tab1: {
 | 
			
		||||
                        type: 'void',
 | 
			
		||||
                        title: '{{t("Details")}}',
 | 
			
		||||
                        'x-component': 'Tabs.TabPane',
 | 
			
		||||
                        'x-designer': 'Tabs.Designer',
 | 
			
		||||
                        'x-component-props': {},
 | 
			
		||||
                        properties: {
 | 
			
		||||
                          grid: {
 | 
			
		||||
                            type: 'void',
 | 
			
		||||
                            'x-component': 'Grid',
 | 
			
		||||
                            'x-initializer': 'RecordBlockInitializers',
 | 
			
		||||
                            properties: {},
 | 
			
		||||
                          },
 | 
			
		||||
                        },
 | 
			
		||||
                      },
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: '{{t("Save record")}}',
 | 
			
		||||
          component: 'CustomizeActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: '{{ t("Save") }}',
 | 
			
		||||
            'x-component': 'Action',
 | 
			
		||||
            'x-action': 'customize:save',
 | 
			
		||||
            'x-designer': 'Action.Designer',
 | 
			
		||||
            'x-designer-props': {
 | 
			
		||||
              modalTip:
 | 
			
		||||
                '{{ t("When the button is clicked, the following fields will be assigned and saved together with the fields in the form. If there are overlapping fields, the value here will overwrite the value in the form.") }}',
 | 
			
		||||
            },
 | 
			
		||||
            'x-action-settings': {
 | 
			
		||||
              overwriteValues: {},
 | 
			
		||||
              assignedValues: {},
 | 
			
		||||
              skipValidator: false,
 | 
			
		||||
              onSuccess: {
 | 
			
		||||
                manualClose: true,
 | 
			
		||||
                redirecting: false,
 | 
			
		||||
                successMessage: '{{t("Saved successfully")}}',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              useProps: '{{ useUpdateActionProps }}',
 | 
			
		||||
 | 
			
		||||
@ -33,5 +33,87 @@ export const ReadPrettyFormActionInitializers = {
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
      type: 'divider',
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      type: 'subMenu',
 | 
			
		||||
      title: '{{t("Customize")}}',
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: '{{t("Popup")}}',
 | 
			
		||||
          component: 'CustomizeActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            title: '{{ t("Popup") }}',
 | 
			
		||||
            'x-action': 'customize:popup',
 | 
			
		||||
            'x-designer': 'Action.Designer',
 | 
			
		||||
            'x-component': 'Action',
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              openMode: 'drawer',
 | 
			
		||||
            },
 | 
			
		||||
            properties: {
 | 
			
		||||
              drawer: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                title: '{{ t("Popup") }}',
 | 
			
		||||
                'x-component': 'Action.Container',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  className: 'nb-action-popup',
 | 
			
		||||
                },
 | 
			
		||||
                properties: {
 | 
			
		||||
                  tabs: {
 | 
			
		||||
                    type: 'void',
 | 
			
		||||
                    'x-component': 'Tabs',
 | 
			
		||||
                    'x-component-props': {},
 | 
			
		||||
                    'x-initializer': 'TabPaneInitializers',
 | 
			
		||||
                    properties: {
 | 
			
		||||
                      tab1: {
 | 
			
		||||
                        type: 'void',
 | 
			
		||||
                        title: '{{t("Details")}}',
 | 
			
		||||
                        'x-component': 'Tabs.TabPane',
 | 
			
		||||
                        'x-designer': 'Tabs.Designer',
 | 
			
		||||
                        'x-component-props': {},
 | 
			
		||||
                        properties: {
 | 
			
		||||
                          grid: {
 | 
			
		||||
                            type: 'void',
 | 
			
		||||
                            'x-component': 'Grid',
 | 
			
		||||
                            'x-initializer': 'RecordBlockInitializers',
 | 
			
		||||
                            properties: {},
 | 
			
		||||
                          },
 | 
			
		||||
                        },
 | 
			
		||||
                      },
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'item',
 | 
			
		||||
          title: '{{t("Update record")}}',
 | 
			
		||||
          component: 'CustomizeActionInitializer',
 | 
			
		||||
          schema: {
 | 
			
		||||
            title: '{{ t("Update record") }}',
 | 
			
		||||
            'x-component': 'Action',
 | 
			
		||||
            'x-designer': 'Action.Designer',
 | 
			
		||||
            'x-action': 'customize:update',
 | 
			
		||||
            'x-action-settings': {
 | 
			
		||||
              assignedValues: {},
 | 
			
		||||
              onSuccess: {
 | 
			
		||||
                manualClose: true,
 | 
			
		||||
                redirecting: false,
 | 
			
		||||
                successMessage: '{{t("Updated successfully")}}',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              useProps: '{{ useCustomizeUpdateActionProps }}',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -70,6 +70,87 @@ export const TableActionColumnInitializers = (props: any) => {
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'divider',
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: 'subMenu',
 | 
			
		||||
          title: '{{t("Customize")}}',
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: '{{t("Popup")}}',
 | 
			
		||||
              component: 'CustomizeActionInitializer',
 | 
			
		||||
              schema: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                title: '{{ t("Popup") }}',
 | 
			
		||||
                'x-action': 'customize:popup',
 | 
			
		||||
                'x-designer': 'Action.Designer',
 | 
			
		||||
                'x-component': 'Action.Link',
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  openMode: 'drawer',
 | 
			
		||||
                },
 | 
			
		||||
                properties: {
 | 
			
		||||
                  drawer: {
 | 
			
		||||
                    type: 'void',
 | 
			
		||||
                    title: '{{ t("Popup") }}',
 | 
			
		||||
                    'x-component': 'Action.Container',
 | 
			
		||||
                    'x-component-props': {
 | 
			
		||||
                      className: 'nb-action-popup',
 | 
			
		||||
                    },
 | 
			
		||||
                    properties: {
 | 
			
		||||
                      tabs: {
 | 
			
		||||
                        type: 'void',
 | 
			
		||||
                        'x-component': 'Tabs',
 | 
			
		||||
                        'x-component-props': {},
 | 
			
		||||
                        'x-initializer': 'TabPaneInitializers',
 | 
			
		||||
                        properties: {
 | 
			
		||||
                          tab1: {
 | 
			
		||||
                            type: 'void',
 | 
			
		||||
                            title: '{{t("Details")}}',
 | 
			
		||||
                            'x-component': 'Tabs.TabPane',
 | 
			
		||||
                            'x-designer': 'Tabs.Designer',
 | 
			
		||||
                            'x-component-props': {},
 | 
			
		||||
                            properties: {
 | 
			
		||||
                              grid: {
 | 
			
		||||
                                type: 'void',
 | 
			
		||||
                                'x-component': 'Grid',
 | 
			
		||||
                                'x-initializer': 'RecordBlockInitializers',
 | 
			
		||||
                                properties: {},
 | 
			
		||||
                              },
 | 
			
		||||
                            },
 | 
			
		||||
                          },
 | 
			
		||||
                        },
 | 
			
		||||
                      },
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: '{{t("Update record")}}',
 | 
			
		||||
              component: 'CustomizeActionInitializer',
 | 
			
		||||
              schema: {
 | 
			
		||||
                title: '{{ t("Update record") }}',
 | 
			
		||||
                'x-component': 'Action.Link',
 | 
			
		||||
                'x-action': 'customize:update',
 | 
			
		||||
                'x-designer': 'Action.Designer',
 | 
			
		||||
                'x-action-settings': {
 | 
			
		||||
                  assignedValues: {},
 | 
			
		||||
                  onSuccess: {
 | 
			
		||||
                    manualClose: true,
 | 
			
		||||
                    redirecting: false,
 | 
			
		||||
                    successMessage: '{{t("Updated successfully")}}',
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
                'x-component-props': {
 | 
			
		||||
                  useProps: '{{ useCustomizeUpdateActionProps }}',
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
      component={<MenuOutlined style={{ cursor: 'pointer' }} />}
 | 
			
		||||
    />
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
export * from './BlockInitializers';
 | 
			
		||||
export * from './CalendarActionInitializers';
 | 
			
		||||
export * from './CreateFormBlockInitializers';
 | 
			
		||||
export * from './CustomFormItemInitializers';
 | 
			
		||||
export * from './DetailsActionInitializers';
 | 
			
		||||
export * from './FormActionInitializers';
 | 
			
		||||
export * from './FormItemInitializers';
 | 
			
		||||
@ -15,4 +16,3 @@ export * from './TableActionInitializers';
 | 
			
		||||
export * from './TableColumnInitializers';
 | 
			
		||||
export * from './TableSelectorInitializers';
 | 
			
		||||
export * from './TabPaneInitializers';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,70 @@
 | 
			
		||||
import { Field } from '@formily/core';
 | 
			
		||||
import { useField, useFieldSchema } from '@formily/react';
 | 
			
		||||
import React, { useEffect, useState } from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { CollectionField, useCollection } from '../../../collection-manager';
 | 
			
		||||
import { useCompile, useFilterOptions } from '../../../schema-component';
 | 
			
		||||
 | 
			
		||||
export const AssignedField = (props: any) => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const compile = useCompile();
 | 
			
		||||
  const field = useField<Field>();
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const [type, setType] = useState<string>('constantValue');
 | 
			
		||||
  const [value, setValue] = useState(field?.value?.value ?? '');
 | 
			
		||||
  const [options, setOptions] = useState<any[]>([]);
 | 
			
		||||
  const { getField } = useCollection();
 | 
			
		||||
  const collectionField = getField(fieldSchema.name);
 | 
			
		||||
  const { uiSchema } = collectionField;
 | 
			
		||||
  const currentUser = useFilterOptions('users');
 | 
			
		||||
  const currentRecord = useFilterOptions(collectionField.collectionName);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const opt = [
 | 
			
		||||
      {
 | 
			
		||||
        name: 'currentUser',
 | 
			
		||||
        title: t('Current user'),
 | 
			
		||||
        children: [...currentUser],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        name: 'currentRecord',
 | 
			
		||||
        title: t('Current record'),
 | 
			
		||||
        children: [...currentRecord],
 | 
			
		||||
      },
 | 
			
		||||
    ];
 | 
			
		||||
    setOptions(compile(opt));
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
  const valueChangeHandler = (val) => {
 | 
			
		||||
    setValue(val);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return <CollectionField {...props} value={field.value} onChange={valueChangeHandler} />;
 | 
			
		||||
 | 
			
		||||
  // return (
 | 
			
		||||
  //   <Space>
 | 
			
		||||
  //     <Select defaultValue={type} value={type} style={{ width: 120 }} onChange={typeChangeHandler}>
 | 
			
		||||
  //       <Select.Option value="constantValue">{t('Constant value')}</Select.Option>
 | 
			
		||||
  //       <Select.Option value="dynamicValue">{t('Dynamic value')}</Select.Option>
 | 
			
		||||
  //     </Select>
 | 
			
		||||
 | 
			
		||||
  //     {type === 'constantValue' ? (
 | 
			
		||||
  //       <CollectionField {...props} onChange={valueChangeHandler} />
 | 
			
		||||
  //     ) : (
 | 
			
		||||
  //       <Cascader
 | 
			
		||||
  //         fieldNames={{
 | 
			
		||||
  //           label: 'title',
 | 
			
		||||
  //           value: 'name',
 | 
			
		||||
  //           children: 'children',
 | 
			
		||||
  //         }}
 | 
			
		||||
  //         style={{
 | 
			
		||||
  //           width: 150,
 | 
			
		||||
  //         }}
 | 
			
		||||
  //         options={options}
 | 
			
		||||
  //         onChange={valueChangeHandler}
 | 
			
		||||
  //         defaultValue={value}
 | 
			
		||||
  //       />
 | 
			
		||||
  //     )}
 | 
			
		||||
  //   </Space>
 | 
			
		||||
  // );
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1 @@
 | 
			
		||||
export * from './AssignedField';
 | 
			
		||||
@ -0,0 +1 @@
 | 
			
		||||
export * from './assigned-field';
 | 
			
		||||
@ -20,7 +20,7 @@ import {
 | 
			
		||||
  createTableSelectorSchema,
 | 
			
		||||
  useCollectionDataSourceItems,
 | 
			
		||||
  useCurrentSchema,
 | 
			
		||||
  useRecordCollectionDataSourceItems
 | 
			
		||||
  useRecordCollectionDataSourceItems,
 | 
			
		||||
} from '../utils';
 | 
			
		||||
 | 
			
		||||
// Block
 | 
			
		||||
 | 
			
		||||
@ -39,6 +39,19 @@ export const removeGridFormItem = (schema, cb) => {
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const useRemoveGridFormItem = () => {
 | 
			
		||||
  const form = useForm();
 | 
			
		||||
  return (schema, cb) => {
 | 
			
		||||
    cb(schema, {
 | 
			
		||||
      removeParentsIfNoChildren: true,
 | 
			
		||||
      breakRemoveOn: {
 | 
			
		||||
        'x-component': 'Grid',
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
    delete form.values?.[schema.name];
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const findTableColumn = (schema: Schema, key: string, action: string, deepth: number = 0) => {
 | 
			
		||||
  return schema.reduceProperties((buf, s) => {
 | 
			
		||||
    if (s[key] === action) {
 | 
			
		||||
@ -92,6 +105,7 @@ export const useFormItemInitializerFields = (options?: any) => {
 | 
			
		||||
  const { getInterface } = useCollectionManager();
 | 
			
		||||
  const form = useForm();
 | 
			
		||||
  const { readPretty = form.readPretty, block = 'Form' } = options || {};
 | 
			
		||||
 | 
			
		||||
  return fields
 | 
			
		||||
    ?.filter((field) => field?.interface)
 | 
			
		||||
    ?.map((field) => {
 | 
			
		||||
@ -119,6 +133,40 @@ export const useFormItemInitializerFields = (options?: any) => {
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const useCustomFormItemInitializerFields = (options?: any) => {
 | 
			
		||||
  const { name, fields } = useCollection();
 | 
			
		||||
  const { getInterface } = useCollectionManager();
 | 
			
		||||
  const form = useForm();
 | 
			
		||||
  const { readPretty = form.readPretty, block = 'Form' } = options || {};
 | 
			
		||||
  const remove = useRemoveGridFormItem();
 | 
			
		||||
  return fields
 | 
			
		||||
    ?.filter((field) => {
 | 
			
		||||
      return field?.interface && !field?.uiSchema?.['x-read-pretty'];
 | 
			
		||||
    })
 | 
			
		||||
    ?.map((field) => {
 | 
			
		||||
      const interfaceConfig = getInterface(field.interface);
 | 
			
		||||
      const schema = {
 | 
			
		||||
        type: 'string',
 | 
			
		||||
        name: field.name,
 | 
			
		||||
        title: field?.uiSchema?.title || field.name,
 | 
			
		||||
        'x-designer': 'FormItem.Designer',
 | 
			
		||||
        'x-component': 'AssignedField',
 | 
			
		||||
        'x-decorator': 'FormItem',
 | 
			
		||||
        'x-collection-field': `${name}.${field.name}`,
 | 
			
		||||
      };
 | 
			
		||||
      return {
 | 
			
		||||
        type: 'item',
 | 
			
		||||
        title: field?.uiSchema?.title || field.name,
 | 
			
		||||
        component: 'CollectionFieldInitializer',
 | 
			
		||||
        remove: remove,
 | 
			
		||||
        schemaInitialize: (s) => {
 | 
			
		||||
          interfaceConfig?.schemaInitialize?.(s, { field, block, readPretty });
 | 
			
		||||
        },
 | 
			
		||||
        schema,
 | 
			
		||||
      } as SchemaInitializerItemOptions;
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const findSchema = (schema: Schema, key: string, action: string) => {
 | 
			
		||||
  return schema.reduceProperties((buf, s) => {
 | 
			
		||||
    if (s[key] === action) {
 | 
			
		||||
 | 
			
		||||
@ -1,25 +1,28 @@
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { FormDialog, FormItem, FormLayout, Input } from '@formily/antd';
 | 
			
		||||
import { GeneralField } from '@formily/core';
 | 
			
		||||
import { ISchema, Schema, SchemaOptionsContext } from '@formily/react';
 | 
			
		||||
import { createForm, GeneralField } from '@formily/core';
 | 
			
		||||
import { ISchema, Schema, SchemaOptionsContext, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
import { Dropdown, Menu, MenuItemProps, Modal, Select, Switch } from 'antd';
 | 
			
		||||
import { Alert, Button, Dropdown, Menu, MenuItemProps, Modal, Select, Space, Switch } from 'antd';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import React, { createContext, useContext, useState } from 'react';
 | 
			
		||||
import { cloneDeep } from 'lodash';
 | 
			
		||||
import React, { createContext, useContext, useMemo, useState } from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import {
 | 
			
		||||
  ActionContext,
 | 
			
		||||
  createDesignable,
 | 
			
		||||
  Designable,
 | 
			
		||||
  FormProvider,
 | 
			
		||||
  RemoteSchemaComponent,
 | 
			
		||||
  SchemaComponent,
 | 
			
		||||
  SchemaComponentOptions,
 | 
			
		||||
  useActionContext,
 | 
			
		||||
  useAPIClient,
 | 
			
		||||
  useCollection
 | 
			
		||||
  useCollection,
 | 
			
		||||
  useCompile
 | 
			
		||||
} from '..';
 | 
			
		||||
import { useSchemaTemplateManager } from '../schema-templates';
 | 
			
		||||
import { useBlockTemplateContext } from '../schema-templates/BlockTemplate';
 | 
			
		||||
 | 
			
		||||
interface SchemaSettingsProps {
 | 
			
		||||
  title?: any;
 | 
			
		||||
  dn?: Designable;
 | 
			
		||||
@ -462,6 +465,83 @@ SchemaSettings.PopupItem = (props) => {
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
SchemaSettings.ActionModalItem = React.memo((props: any) => {
 | 
			
		||||
  const { title, onSubmit, initialValues, initialSchema, modalTip, ...others } = props;
 | 
			
		||||
  const [visible, setVisible] = useState(false);
 | 
			
		||||
  const [schemaUid, setSchemaUid] = useState<string>(props.uid);
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const ctx = useContext(SchemaSettingsContext);
 | 
			
		||||
  const { dn } = useSchemaSettings();
 | 
			
		||||
  const compile = useCompile();
 | 
			
		||||
  const api = useAPIClient();
 | 
			
		||||
  const form = useMemo(
 | 
			
		||||
    () =>
 | 
			
		||||
      createForm({
 | 
			
		||||
        initialValues: cloneDeep(initialValues),
 | 
			
		||||
      }),
 | 
			
		||||
    [],
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const cancelHandler = () => {
 | 
			
		||||
    setVisible(false);
 | 
			
		||||
  };
 | 
			
		||||
  const submitHandler = () => {
 | 
			
		||||
    onSubmit?.(cloneDeep(form.values));
 | 
			
		||||
    setVisible(false);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const openAssignedFieldValueHandler = async () => {
 | 
			
		||||
    if (!schemaUid && initialSchema['x-uid']) {
 | 
			
		||||
      fieldSchema['x-action-settings'].schemaUid = initialSchema['x-uid'];
 | 
			
		||||
      dn.emit('patch', { schema: fieldSchema });
 | 
			
		||||
      await api.resource('uiSchemas').insert({ values: initialSchema });
 | 
			
		||||
      setSchemaUid(initialSchema['x-uid']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ctx.setVisible(false);
 | 
			
		||||
    setVisible(true);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div
 | 
			
		||||
      onClick={(e) => {
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
        e.stopPropagation();
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <SchemaSettings.Item {...others} onClick={openAssignedFieldValueHandler}>
 | 
			
		||||
        {props.children || props.title}
 | 
			
		||||
      </SchemaSettings.Item>
 | 
			
		||||
 | 
			
		||||
      <Modal
 | 
			
		||||
        width={'50%'}
 | 
			
		||||
        title={compile(title)}
 | 
			
		||||
        {...others}
 | 
			
		||||
        destroyOnClose
 | 
			
		||||
        visible={visible}
 | 
			
		||||
        onCancel={cancelHandler}
 | 
			
		||||
        footer={
 | 
			
		||||
          <Space>
 | 
			
		||||
            <Button onClick={cancelHandler}>{t('Cancel')}</Button>
 | 
			
		||||
            <Button type="primary" onClick={submitHandler}>
 | 
			
		||||
              {t('Submit')}
 | 
			
		||||
            </Button>
 | 
			
		||||
          </Space>
 | 
			
		||||
        }
 | 
			
		||||
      >
 | 
			
		||||
        <FormProvider form={form}>
 | 
			
		||||
          <FormLayout layout={'vertical'}>
 | 
			
		||||
            {modalTip && <Alert message={modalTip} />}
 | 
			
		||||
            {modalTip && <br />}
 | 
			
		||||
            {visible && <RemoteSchemaComponent noForm uid={schemaUid} />}
 | 
			
		||||
          </FormLayout>
 | 
			
		||||
        </FormProvider>
 | 
			
		||||
      </Modal>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
SchemaSettings.ModalItem = (props) => {
 | 
			
		||||
  const { hidden, title, components, scope, effects, schema, onSubmit, initialValues, ...others } = props;
 | 
			
		||||
  const options = useContext(SchemaOptionsContext);
 | 
			
		||||
 | 
			
		||||
@ -202,7 +202,7 @@ SettingsForm.Drawer = () => {
 | 
			
		||||
      style={{ width: 200 }}
 | 
			
		||||
      onClick={async () => {
 | 
			
		||||
        setDropdownVisible(false);
 | 
			
		||||
        const values = await FormDrawer('Pop-up form', () => {
 | 
			
		||||
        const values = await FormDrawer('Popup form', () => {
 | 
			
		||||
          return (
 | 
			
		||||
            <SchemaComponentOptions scope={options.scope} components={{ ...options.components, FormItem }}>
 | 
			
		||||
              <FormLayout layout={'vertical'}>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user