diff --git a/packages/core/client/src/schema-component/antd/variable/TextArea.tsx b/packages/core/client/src/schema-component/antd/variable/TextArea.tsx
index 0952d742f..d888117a6 100644
--- a/packages/core/client/src/schema-component/antd/variable/TextArea.tsx
+++ b/packages/core/client/src/schema-component/antd/variable/TextArea.tsx
@@ -2,7 +2,7 @@ import { css, cx } from '@emotion/css';
import { useForm } from '@formily/react';
import { Input } from 'antd';
import { cloneDeep } from 'lodash';
-import React, { useEffect, useMemo, useRef, useState } from 'react';
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import sanitizeHTML from 'sanitize-html';
import { error } from '@nocobase/utils/client';
@@ -228,26 +228,30 @@ export function TextArea(props) {
}
const sel = window.getSelection?.();
if (sel) {
- const children = Array.from(current.childNodes) as HTMLElement[];
- if (children.length) {
- if (range[0] === -1) {
- if (range[1]) {
- nextRange.setStartAfter(children[range[1] - 1]);
+ try {
+ const children = Array.from(current.childNodes) as HTMLElement[];
+ if (children.length) {
+ if (range[0] === -1) {
+ if (range[1]) {
+ nextRange.setStartAfter(children[range[1] - 1]);
+ }
+ } else {
+ nextRange.setStart(children[range[0]], range[1]);
}
- } else {
- nextRange.setStart(children[range[0]], range[1]);
- }
- if (range[2] === -1) {
- if (range[3]) {
- nextRange.setEndAfter(children[range[3] - 1]);
+ if (range[2] === -1) {
+ if (range[3]) {
+ nextRange.setEndAfter(children[range[3] - 1]);
+ }
+ } else {
+ nextRange.setEnd(children[range[2]], range[3]);
}
- } else {
- nextRange.setEnd(children[range[2]], range[3]);
}
+ nextRange.collapse(true);
+ sel.removeAllRanges();
+ sel.addRange(nextRange);
+ } catch (ex) {
+ // console.error(ex);
}
- nextRange.collapse(true);
- sel.removeAllRanges();
- sel.addRange(nextRange);
}
} else {
const { lastChild } = current;
@@ -262,39 +266,45 @@ export function TextArea(props) {
}
}, [html]);
- function onInsert(paths: string[]) {
- const variable: string[] = paths.filter((key) => Boolean(key.trim()));
- const { current } = inputRef;
- if (!current || !variable) {
- return;
- }
+ const onInsert = useCallback(
+ function (paths: string[]) {
+ const variable: string[] = paths.filter((key) => Boolean(key.trim()));
+ const { current } = inputRef;
+ if (!current || !variable) {
+ return;
+ }
- current.focus();
+ current.focus();
- const content = createVariableTagHTML(variable.join('.'), keyLabelMap);
- pasteHTML(current, content, {
- range,
- });
+ const content = createVariableTagHTML(variable.join('.'), keyLabelMap);
+ pasteHTML(current, content, {
+ range,
+ });
- setChanged(true);
- setRange(getCurrentRange(current));
- onChange(getValue(current));
- }
+ setChanged(true);
+ setRange(getCurrentRange(current));
+ onChange(getValue(current));
+ },
+ [keyLabelMap, onChange, range],
+ );
- function onInput({ currentTarget }) {
- if (ime) {
- return;
- }
- setChanged(true);
+ const onInput = useCallback(
+ function ({ currentTarget }) {
+ if (ime) {
+ return;
+ }
+ setChanged(true);
+ setRange(getCurrentRange(currentTarget));
+ onChange(getValue(currentTarget));
+ },
+ [ime, onChange],
+ );
+
+ const onBlur = useCallback(function ({ currentTarget }) {
setRange(getCurrentRange(currentTarget));
- onChange(getValue(currentTarget));
- }
+ }, []);
- function onBlur({ currentTarget }) {
- setRange(getCurrentRange(currentTarget));
- }
-
- function onKeyDown(ev) {
+ const onKeyDown = useCallback(function (ev) {
if (ev.key === 'Enter') {
ev.preventDefault();
}
@@ -305,37 +315,40 @@ export function TextArea(props) {
// if (ev.key === 'Alt') {
// console.debug(getCurrentRange(ev.currentTarget));
// }
- }
+ }, []);
- function onPaste(ev) {
- ev.preventDefault();
- const input = ev.clipboardData.getData('text/html') || ev.clipboardData.getData('text');
- const sanitizedHTML = sanitizeHTML(input, {
- allowedTags: ['span'],
- allowedAttributes: {
- span: ['data-variable', 'contenteditable'],
- },
- allowedClasses: {
- span: ['ant-tag', 'ant-tag-*'],
- },
- transformTags: {
- span(tagName, attribs) {
- return attribs['data-variable']
- ? {
- tagName: tagName,
- attribs,
- }
- : {};
+ const onPaste = useCallback(
+ function (ev) {
+ ev.preventDefault();
+ const input = ev.clipboardData.getData('text/html') || ev.clipboardData.getData('text');
+ const sanitizedHTML = sanitizeHTML(input, {
+ allowedTags: ['span'],
+ allowedAttributes: {
+ span: ['data-variable', 'contenteditable'],
},
- },
- }).replace(/\n/g, ' ');
- // ev.clipboardData.setData('text/html', sanitizedHTML);
- // console.log(input, sanitizedHTML);
- setChanged(true);
- pasteHTML(ev.currentTarget, sanitizedHTML);
- setRange(getCurrentRange(ev.currentTarget));
- onChange(getValue(ev.currentTarget));
- }
+ allowedClasses: {
+ span: ['ant-tag', 'ant-tag-*'],
+ },
+ transformTags: {
+ span(tagName, attribs) {
+ return attribs['data-variable']
+ ? {
+ tagName: tagName,
+ attribs,
+ }
+ : {};
+ },
+ },
+ }).replace(/\n/g, ' ');
+ // ev.clipboardData.setData('text/html', sanitizedHTML);
+ // console.log(input, sanitizedHTML);
+ setChanged(true);
+ pasteHTML(ev.currentTarget, sanitizedHTML);
+ setRange(getCurrentRange(ev.currentTarget));
+ onChange(getValue(ev.currentTarget));
+ },
+ [onChange],
+ );
const disabled = props.disabled || form.disabled;
diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/index.tsx b/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/index.tsx
index cb9ebe945..9589baf2a 100644
--- a/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/index.tsx
+++ b/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/index.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useContext, useMemo, useState } from 'react';
+import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { DeleteOutlined } from '@ant-design/icons';
import { cloneDeep } from 'lodash';
import { createForm } from '@formily/core';
@@ -8,6 +8,7 @@ import { useTranslation } from 'react-i18next';
import {
ActionContextProvider,
+ FormProvider,
SchemaComponent,
SchemaInitializerItemOptions,
css,
@@ -273,6 +274,10 @@ export function JobButton() {
);
}
+function useNodeFormProps() {
+ return { form: useForm() };
+}
+
export function NodeDefaultView(props) {
const { data, children } = props;
const compile = useCompile();
@@ -292,15 +297,14 @@ export function NodeDefaultView(props) {
const values = cloneDeep(data.config);
return createForm({
initialValues: values,
- values,
disabled: workflow.executed,
});
}, [data, workflow]);
const resetForm = useCallback(
- (changed) => {
- setFormValueChanged(changed);
- if (!changed) {
+ (editing) => {
+ setEditingConfig(editing);
+ if (!editing) {
form.reset();
}
},
@@ -366,123 +370,129 @@ export function NodeDefaultView(props) {
-
- {data.title}
-
-
- {data.key}
-
-
-
- ),
- 'x-decorator': 'FormV2',
- 'x-decorator-props': {
- form,
- },
- 'x-component': 'Action.Drawer',
- properties: {
- ...(instruction.description
- ? {
- description: {
- type: 'void',
- 'x-component': DrawerDescription,
- 'x-component-props': {
- label: lang('Node type'),
- title: instruction.title,
- description: instruction.description,
- },
- },
- }
- : {}),
- fieldset: {
- type: 'void',
- 'x-component': 'fieldset',
- 'x-component-props': {
- className: css`
- .ant-input,
- .ant-select,
- .ant-cascader-picker,
- .ant-picker,
- .ant-input-number,
- .ant-input-affix-wrapper {
- &.auto-width {
- width: auto;
- min-width: 6em;
- }
- }
- `,
- },
- properties: instruction.fieldset,
+
+
+ {data.title}
+
+
+ {data.key}
+
+
+
+ ),
+ 'x-decorator': 'FormV2',
+ 'x-decorator-props': {
+ // form,
+ useProps: '{{ useNodeFormProps }}',
+ },
+ 'x-component': 'Action.Drawer',
+ properties: {
+ ...(instruction.description
+ ? {
+ description: {
+ type: 'void',
+ 'x-component': DrawerDescription,
'x-component-props': {
- useAction: '{{ cm.useCancelAction }}',
+ label: lang('Node type'),
+ title: instruction.title,
+ description: instruction.description,
},
},
- submit: {
- title: '{{t("Submit")}}',
- 'x-component': 'Action',
- 'x-component-props': {
- type: 'primary',
- useAction: useUpdateAction,
+ }
+ : {}),
+ fieldset: {
+ type: 'void',
+ 'x-component': 'fieldset',
+ 'x-component-props': {
+ className: css`
+ .ant-input,
+ .ant-select,
+ .ant-cascader-picker,
+ .ant-picker,
+ .ant-input-number,
+ .ant-input-affix-wrapper {
+ &.auto-width {
+ width: auto;
+ min-width: 6em;
+ }
+ }
+ `,
+ },
+ properties: instruction.fieldset,
+ },
+ actions: workflow.executed
+ ? null
+ : {
+ type: 'void',
+ 'x-component': 'Action.Drawer.Footer',
+ properties: {
+ cancel: {
+ title: '{{t("Cancel")}}',
+ 'x-component': 'Action',
+ 'x-component-props': {
+ useAction: '{{ cm.useCancelAction }}',
+ },
+ },
+ submit: {
+ title: '{{t("Submit")}}',
+ 'x-component': 'Action',
+ 'x-component-props': {
+ type: 'primary',
+ useAction: useUpdateAction,
+ },
},
},
},
- },
- },
- } as ISchema,
- },
- }}
- />
+ },
+ } as ISchema,
+ },
+ }}
+ />
+
{children}
diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/manual/SchemaConfig.tsx b/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/manual/SchemaConfig.tsx
index b5aa34e1d..b9ea4e8ef 100644
--- a/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/manual/SchemaConfig.tsx
+++ b/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/manual/SchemaConfig.tsx
@@ -1,8 +1,8 @@
+import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { FormLayout } from '@formily/antd-v5';
import { createForm } from '@formily/core';
import { FormProvider, ISchema, Schema, useFieldSchema, useForm } from '@formily/react';
import { Alert, Button, Modal, Space } from 'antd';
-import React, { useContext, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
@@ -450,22 +450,27 @@ export function SchemaConfig({ value, onChange }) {
[],
);
+ const refresh = useCallback(
+ function refresh() {
+ // ctx.refresh?.();
+ const { tabs } = lodash.get(schema.toJSON(), 'properties.drawer.properties') as { tabs: ISchema };
+ const forms = Array.from(manualFormTypes.getValues()).reduce(
+ (result, item: ManualFormType) => Object.assign(result, item.config.parseFormOptions(tabs)),
+ {},
+ );
+ form.setValuesIn('forms', forms);
+
+ onChange(tabs.properties);
+ },
+ [form, onChange, schema],
+ );
+
return (
Object.assign(result, item.config.parseFormOptions(tabs)),
- {},
- );
- form.setValuesIn('forms', forms);
-
- onChange(tabs.properties);
- },
+ refresh,
}}
>
setVisible(true)}>
{workflow.executed ? lang('View user interface') : lang('Configure user interface')}
- {props.children}
+
+ {props.children}
+
>
);
}