@flowgram.ai/form-materials 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js +420 -96
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +52 -7
- package/dist/index.d.ts +52 -7
- package/dist/index.js +422 -99
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/src/components/condition-row/config.json +5 -0
- package/src/components/condition-row/constants.ts +123 -0
- package/src/components/condition-row/hooks/useOp.tsx +45 -0
- package/src/components/condition-row/hooks/useRule.ts +26 -0
- package/src/components/condition-row/index.tsx +71 -0
- package/src/components/condition-row/styles.tsx +25 -0
- package/src/components/condition-row/types.ts +37 -0
- package/src/components/dynamic-value-input/index.tsx +11 -3
- package/src/components/index.ts +1 -0
- package/src/components/json-schema-editor/components/blur-input.tsx +22 -0
- package/src/components/json-schema-editor/index.tsx +4 -3
- package/src/components/variable-selector/index.tsx +1 -1
- package/src/effects/auto-rename-ref/config.json +5 -0
- package/src/effects/auto-rename-ref/index.ts +104 -0
- package/src/effects/index.ts +1 -0
- package/src/utils/json-schema/index.ts +13 -6
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { IRules, Op, OpConfigs } from './types';
|
|
2
|
+
|
|
3
|
+
export const rules: IRules = {
|
|
4
|
+
string: {
|
|
5
|
+
[Op.EQ]: 'string',
|
|
6
|
+
[Op.NEQ]: 'string',
|
|
7
|
+
[Op.CONTAINS]: 'string',
|
|
8
|
+
[Op.NOT_CONTAINS]: 'string',
|
|
9
|
+
[Op.IN]: 'array',
|
|
10
|
+
[Op.NIN]: 'array',
|
|
11
|
+
[Op.IS_EMPTY]: 'string',
|
|
12
|
+
[Op.IS_NOT_EMPTY]: 'string',
|
|
13
|
+
},
|
|
14
|
+
number: {
|
|
15
|
+
[Op.EQ]: 'number',
|
|
16
|
+
[Op.NEQ]: 'number',
|
|
17
|
+
[Op.GT]: 'number',
|
|
18
|
+
[Op.GTE]: 'number',
|
|
19
|
+
[Op.LT]: 'number',
|
|
20
|
+
[Op.LTE]: 'number',
|
|
21
|
+
[Op.IN]: 'array',
|
|
22
|
+
[Op.NIN]: 'array',
|
|
23
|
+
[Op.IS_EMPTY]: null,
|
|
24
|
+
[Op.IS_NOT_EMPTY]: null,
|
|
25
|
+
},
|
|
26
|
+
integer: {
|
|
27
|
+
[Op.EQ]: 'number',
|
|
28
|
+
[Op.NEQ]: 'number',
|
|
29
|
+
[Op.GT]: 'number',
|
|
30
|
+
[Op.GTE]: 'number',
|
|
31
|
+
[Op.LT]: 'number',
|
|
32
|
+
[Op.LTE]: 'number',
|
|
33
|
+
[Op.IN]: 'array',
|
|
34
|
+
[Op.NIN]: 'array',
|
|
35
|
+
[Op.IS_EMPTY]: null,
|
|
36
|
+
[Op.IS_NOT_EMPTY]: null,
|
|
37
|
+
},
|
|
38
|
+
boolean: {
|
|
39
|
+
[Op.EQ]: 'boolean',
|
|
40
|
+
[Op.NEQ]: 'boolean',
|
|
41
|
+
[Op.IS_TRUE]: null,
|
|
42
|
+
[Op.IS_FALSE]: null,
|
|
43
|
+
[Op.IN]: 'array',
|
|
44
|
+
[Op.NIN]: 'array',
|
|
45
|
+
[Op.IS_EMPTY]: null,
|
|
46
|
+
[Op.IS_NOT_EMPTY]: null,
|
|
47
|
+
},
|
|
48
|
+
object: {
|
|
49
|
+
[Op.IS_EMPTY]: null,
|
|
50
|
+
[Op.IS_NOT_EMPTY]: null,
|
|
51
|
+
},
|
|
52
|
+
array: {
|
|
53
|
+
[Op.IS_EMPTY]: null,
|
|
54
|
+
[Op.IS_NOT_EMPTY]: null,
|
|
55
|
+
},
|
|
56
|
+
map: {
|
|
57
|
+
[Op.IS_EMPTY]: null,
|
|
58
|
+
[Op.IS_NOT_EMPTY]: null,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const opConfigs: OpConfigs = {
|
|
63
|
+
[Op.EQ]: {
|
|
64
|
+
label: 'Equal',
|
|
65
|
+
abbreviation: '=',
|
|
66
|
+
},
|
|
67
|
+
[Op.NEQ]: {
|
|
68
|
+
label: 'Not Equal',
|
|
69
|
+
abbreviation: '≠',
|
|
70
|
+
},
|
|
71
|
+
[Op.GT]: {
|
|
72
|
+
label: 'Greater Than',
|
|
73
|
+
abbreviation: '>',
|
|
74
|
+
},
|
|
75
|
+
[Op.GTE]: {
|
|
76
|
+
label: 'Greater Than or Equal',
|
|
77
|
+
abbreviation: '>=',
|
|
78
|
+
},
|
|
79
|
+
[Op.LT]: {
|
|
80
|
+
label: 'Less Than',
|
|
81
|
+
abbreviation: '<',
|
|
82
|
+
},
|
|
83
|
+
[Op.LTE]: {
|
|
84
|
+
label: 'Less Than or Equal',
|
|
85
|
+
abbreviation: '<=',
|
|
86
|
+
},
|
|
87
|
+
[Op.IN]: {
|
|
88
|
+
label: 'In',
|
|
89
|
+
abbreviation: '∈',
|
|
90
|
+
},
|
|
91
|
+
[Op.NIN]: {
|
|
92
|
+
label: 'Not In',
|
|
93
|
+
abbreviation: '∉',
|
|
94
|
+
},
|
|
95
|
+
[Op.CONTAINS]: {
|
|
96
|
+
label: 'Contains',
|
|
97
|
+
abbreviation: '⊇',
|
|
98
|
+
},
|
|
99
|
+
[Op.NOT_CONTAINS]: {
|
|
100
|
+
label: 'Not Contains',
|
|
101
|
+
abbreviation: '⊉',
|
|
102
|
+
},
|
|
103
|
+
[Op.IS_EMPTY]: {
|
|
104
|
+
label: 'Is Empty',
|
|
105
|
+
abbreviation: '=',
|
|
106
|
+
rightDisplay: 'Empty',
|
|
107
|
+
},
|
|
108
|
+
[Op.IS_NOT_EMPTY]: {
|
|
109
|
+
label: 'Is Not Empty',
|
|
110
|
+
abbreviation: '≠',
|
|
111
|
+
rightDisplay: 'Empty',
|
|
112
|
+
},
|
|
113
|
+
[Op.IS_TRUE]: {
|
|
114
|
+
label: 'Is True',
|
|
115
|
+
abbreviation: '=',
|
|
116
|
+
rightDisplay: 'True',
|
|
117
|
+
},
|
|
118
|
+
[Op.IS_FALSE]: {
|
|
119
|
+
label: 'Is False',
|
|
120
|
+
abbreviation: '=',
|
|
121
|
+
rightDisplay: 'False',
|
|
122
|
+
},
|
|
123
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Button, Select } from '@douyinfe/semi-ui';
|
|
4
|
+
import { IconChevronDownStroked } from '@douyinfe/semi-icons';
|
|
5
|
+
|
|
6
|
+
import { IRule, Op } from '../types';
|
|
7
|
+
import { opConfigs } from '../constants';
|
|
8
|
+
|
|
9
|
+
interface HookParams {
|
|
10
|
+
rule?: IRule;
|
|
11
|
+
op?: Op;
|
|
12
|
+
onChange: (op: Op) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function useOp({ rule, op, onChange }: HookParams) {
|
|
16
|
+
const options = useMemo(
|
|
17
|
+
() =>
|
|
18
|
+
Object.keys(rule || {}).map((_op) => ({
|
|
19
|
+
...(opConfigs[_op as Op] || {}),
|
|
20
|
+
value: _op,
|
|
21
|
+
})),
|
|
22
|
+
[rule]
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const opConfig = useMemo(() => opConfigs[op as Op], [op]);
|
|
26
|
+
|
|
27
|
+
const renderOpSelect = () => (
|
|
28
|
+
<Select
|
|
29
|
+
style={{ height: 22 }}
|
|
30
|
+
size="small"
|
|
31
|
+
value={op}
|
|
32
|
+
optionList={options}
|
|
33
|
+
onChange={(v) => {
|
|
34
|
+
onChange(v as Op);
|
|
35
|
+
}}
|
|
36
|
+
triggerRender={({ value }) => (
|
|
37
|
+
<Button size="small" disabled={!rule}>
|
|
38
|
+
{opConfig?.abbreviation || <IconChevronDownStroked size="small" />}
|
|
39
|
+
</Button>
|
|
40
|
+
)}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return { renderOpSelect, opConfig };
|
|
45
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { useScopeAvailable } from '@flowgram.ai/editor';
|
|
4
|
+
|
|
5
|
+
import { rules } from '../constants';
|
|
6
|
+
import { JsonSchemaUtils } from '../../../utils';
|
|
7
|
+
import { IFlowRefValue, JsonSchemaBasicType } from '../../../typings';
|
|
8
|
+
|
|
9
|
+
export function useRule(left?: IFlowRefValue) {
|
|
10
|
+
const available = useScopeAvailable();
|
|
11
|
+
|
|
12
|
+
const variable = useMemo(() => {
|
|
13
|
+
if (!left) return undefined;
|
|
14
|
+
return available.getByKeyPath(left.content);
|
|
15
|
+
}, [available, left]);
|
|
16
|
+
|
|
17
|
+
const rule = useMemo(() => {
|
|
18
|
+
if (!variable) return undefined;
|
|
19
|
+
|
|
20
|
+
const schema = JsonSchemaUtils.astToSchema(variable.type, { drilldown: false });
|
|
21
|
+
|
|
22
|
+
return rules[schema?.type as JsonSchemaBasicType];
|
|
23
|
+
}, [variable?.type]);
|
|
24
|
+
|
|
25
|
+
return { rule };
|
|
26
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Input } from '@douyinfe/semi-ui';
|
|
4
|
+
|
|
5
|
+
import { ConditionRowValueType, Op } from './types';
|
|
6
|
+
import { UIContainer, UILeft, UIOperator, UIRight, UIValues } from './styles';
|
|
7
|
+
import { useRule } from './hooks/useRule';
|
|
8
|
+
import { useOp } from './hooks/useOp';
|
|
9
|
+
import { VariableSelector } from '../variable-selector';
|
|
10
|
+
import { DynamicValueInput } from '../dynamic-value-input';
|
|
11
|
+
import { JsonSchemaBasicType } from '../../typings';
|
|
12
|
+
|
|
13
|
+
interface PropTypes {
|
|
14
|
+
value?: ConditionRowValueType;
|
|
15
|
+
onChange: (value?: ConditionRowValueType) => void;
|
|
16
|
+
style?: React.CSSProperties;
|
|
17
|
+
readonly?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function ConditionRow({ style, value, onChange, readonly }: PropTypes) {
|
|
21
|
+
const { left, operator, right } = value || {};
|
|
22
|
+
const { rule } = useRule(left);
|
|
23
|
+
const { renderOpSelect, opConfig } = useOp({
|
|
24
|
+
rule,
|
|
25
|
+
op: operator,
|
|
26
|
+
onChange: (v) => onChange({ ...value, operator: v }),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const targetSchema = useMemo(() => {
|
|
30
|
+
const targetType: JsonSchemaBasicType | null = rule?.[operator as Op] || null;
|
|
31
|
+
return targetType ? { type: targetType, extra: { weak: true } } : null;
|
|
32
|
+
}, [rule, opConfig]);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<UIContainer style={style}>
|
|
36
|
+
<UIOperator>{renderOpSelect()}</UIOperator>
|
|
37
|
+
<UIValues>
|
|
38
|
+
<UILeft>
|
|
39
|
+
<VariableSelector
|
|
40
|
+
readonly={readonly}
|
|
41
|
+
style={{ width: '100%' }}
|
|
42
|
+
value={left?.content}
|
|
43
|
+
onChange={(v) =>
|
|
44
|
+
onChange({
|
|
45
|
+
...value,
|
|
46
|
+
left: {
|
|
47
|
+
type: 'ref',
|
|
48
|
+
content: v,
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
/>
|
|
53
|
+
</UILeft>
|
|
54
|
+
<UIRight>
|
|
55
|
+
{targetSchema ? (
|
|
56
|
+
<DynamicValueInput
|
|
57
|
+
readonly={readonly || !rule}
|
|
58
|
+
value={right}
|
|
59
|
+
schema={targetSchema}
|
|
60
|
+
onChange={(v) => onChange({ ...value, right: v })}
|
|
61
|
+
/>
|
|
62
|
+
) : (
|
|
63
|
+
<Input size="small" disabled value={opConfig?.rightDisplay || 'Empty'} />
|
|
64
|
+
)}
|
|
65
|
+
</UIRight>
|
|
66
|
+
</UIValues>
|
|
67
|
+
</UIContainer>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { ConditionRowValueType };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
|
|
3
|
+
export const UIContainer = styled.div`
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
gap: 4px;
|
|
7
|
+
`;
|
|
8
|
+
|
|
9
|
+
export const UIOperator = styled.div``;
|
|
10
|
+
|
|
11
|
+
export const UILeft = styled.div`
|
|
12
|
+
width: 100%;
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
export const UIRight = styled.div`
|
|
16
|
+
width: 100%;
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
export const UIValues = styled.div`
|
|
20
|
+
flex-grow: 1;
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
align-items: center;
|
|
24
|
+
gap: 4px;
|
|
25
|
+
`;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { IFlowConstantRefValue, IFlowRefValue, JsonSchemaBasicType } from '../../typings';
|
|
2
|
+
|
|
3
|
+
export enum Op {
|
|
4
|
+
EQ = 'eq',
|
|
5
|
+
NEQ = 'neq',
|
|
6
|
+
GT = 'gt',
|
|
7
|
+
GTE = 'gte',
|
|
8
|
+
LT = 'lt',
|
|
9
|
+
LTE = 'lte',
|
|
10
|
+
IN = 'in',
|
|
11
|
+
NIN = 'nin',
|
|
12
|
+
CONTAINS = 'contains',
|
|
13
|
+
NOT_CONTAINS = 'not_contains',
|
|
14
|
+
IS_EMPTY = 'is_empty',
|
|
15
|
+
IS_NOT_EMPTY = 'is_not_empty',
|
|
16
|
+
IS_TRUE = 'is_true',
|
|
17
|
+
IS_FALSE = 'is_false',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface OpConfig {
|
|
21
|
+
label: string;
|
|
22
|
+
abbreviation: string;
|
|
23
|
+
// When right is not a value, display this text
|
|
24
|
+
rightDisplay?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type OpConfigs = Record<Op, OpConfig>;
|
|
28
|
+
|
|
29
|
+
export type IRule = Partial<Record<Op, JsonSchemaBasicType | null>>;
|
|
30
|
+
|
|
31
|
+
export type IRules = Record<JsonSchemaBasicType, IRule>;
|
|
32
|
+
|
|
33
|
+
export interface ConditionRowValueType {
|
|
34
|
+
left?: IFlowRefValue;
|
|
35
|
+
operator?: Op;
|
|
36
|
+
right?: IFlowConstantRefValue;
|
|
37
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
2
|
|
|
3
3
|
import { IconButton } from '@douyinfe/semi-ui';
|
|
4
4
|
import { IconSetting } from '@douyinfe/semi-icons';
|
|
@@ -31,6 +31,14 @@ export function DynamicValueInput({
|
|
|
31
31
|
schema,
|
|
32
32
|
constantProps,
|
|
33
33
|
}: PropsType) {
|
|
34
|
+
// When is number type, include integer as well
|
|
35
|
+
const includeSchema = useMemo(() => {
|
|
36
|
+
if (schema?.type === 'number') {
|
|
37
|
+
return [schema, { type: 'integer' }];
|
|
38
|
+
}
|
|
39
|
+
return schema;
|
|
40
|
+
}, [schema]);
|
|
41
|
+
|
|
34
42
|
const renderMain = () => {
|
|
35
43
|
if (value?.type === 'ref') {
|
|
36
44
|
// Display Variable Or Delete
|
|
@@ -38,7 +46,7 @@ export function DynamicValueInput({
|
|
|
38
46
|
<VariableSelector
|
|
39
47
|
value={value?.content}
|
|
40
48
|
onChange={(_v) => onChange(_v ? { type: 'ref', content: _v } : undefined)}
|
|
41
|
-
includeSchema={
|
|
49
|
+
includeSchema={includeSchema}
|
|
42
50
|
readonly={readonly}
|
|
43
51
|
/>
|
|
44
52
|
);
|
|
@@ -60,7 +68,7 @@ export function DynamicValueInput({
|
|
|
60
68
|
style={{ width: '100%' }}
|
|
61
69
|
value={value?.type === 'ref' ? value?.content : undefined}
|
|
62
70
|
onChange={(_v) => onChange({ type: 'ref', content: _v })}
|
|
63
|
-
includeSchema={
|
|
71
|
+
includeSchema={includeSchema}
|
|
64
72
|
readonly={readonly}
|
|
65
73
|
triggerRender={() => (
|
|
66
74
|
<IconButton disabled={readonly} size="small" icon={<IconSetting size="small" />} />
|
package/src/components/index.ts
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import Input, { InputProps } from '@douyinfe/semi-ui/lib/es/input';
|
|
4
|
+
|
|
5
|
+
export function BlurInput(props: InputProps) {
|
|
6
|
+
const [value, setValue] = useState('');
|
|
7
|
+
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
setValue(props.value as string);
|
|
10
|
+
}, [props.value]);
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<Input
|
|
14
|
+
{...props}
|
|
15
|
+
value={value}
|
|
16
|
+
onChange={(value) => {
|
|
17
|
+
setValue(value);
|
|
18
|
+
}}
|
|
19
|
+
onBlur={(e) => props.onChange?.(value, e)}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useMemo, useState } from 'react';
|
|
2
2
|
|
|
3
|
-
import { Button, Checkbox, IconButton
|
|
3
|
+
import { Button, Checkbox, IconButton } from '@douyinfe/semi-ui';
|
|
4
4
|
import {
|
|
5
5
|
IconExpand,
|
|
6
6
|
IconShrink,
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
import { UIName } from './styles';
|
|
32
32
|
import { UIRow } from './styles';
|
|
33
33
|
import { usePropertiesEdit } from './hooks';
|
|
34
|
+
import { BlurInput } from './components/blur-input';
|
|
34
35
|
|
|
35
36
|
export function JsonSchemaEditor(props: {
|
|
36
37
|
value?: IJsonSchema;
|
|
@@ -109,7 +110,7 @@ function PropertyEdit(props: {
|
|
|
109
110
|
<UIPropertyMain $expand={expand}>
|
|
110
111
|
<UIRow>
|
|
111
112
|
<UIName>
|
|
112
|
-
<
|
|
113
|
+
<BlurInput
|
|
113
114
|
placeholder={config?.placeholder ?? 'Input Variable Name'}
|
|
114
115
|
size="small"
|
|
115
116
|
value={name}
|
|
@@ -162,7 +163,7 @@ function PropertyEdit(props: {
|
|
|
162
163
|
{expand && (
|
|
163
164
|
<UIExpandDetail>
|
|
164
165
|
<UILabel>{config?.descTitle ?? 'Description'}</UILabel>
|
|
165
|
-
<
|
|
166
|
+
<BlurInput
|
|
166
167
|
size="small"
|
|
167
168
|
value={description}
|
|
168
169
|
onChange={(value) => onChange('description', value)}
|
|
@@ -100,7 +100,7 @@ export const VariableSelector = ({
|
|
|
100
100
|
);
|
|
101
101
|
}}
|
|
102
102
|
showClear={false}
|
|
103
|
-
arrowIcon={
|
|
103
|
+
arrowIcon={<IconChevronDownStroked size="small" />}
|
|
104
104
|
triggerRender={triggerRender}
|
|
105
105
|
placeholder={config?.placeholder ?? 'Select Variable...'}
|
|
106
106
|
/>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { isArray, isObject } from 'lodash';
|
|
2
|
+
import {
|
|
3
|
+
DataEvent,
|
|
4
|
+
Effect,
|
|
5
|
+
EffectOptions,
|
|
6
|
+
VariableFieldKeyRenameService,
|
|
7
|
+
} from '@flowgram.ai/editor';
|
|
8
|
+
|
|
9
|
+
import { IFlowRefValue } from '../../typings';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Auto rename ref when form item's key is renamed
|
|
13
|
+
*
|
|
14
|
+
* Example:
|
|
15
|
+
*
|
|
16
|
+
* formMeta: {
|
|
17
|
+
* effects: {
|
|
18
|
+
* "inputsValues": autoRenameRefEffect,
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
export const autoRenameRefEffect: EffectOptions[] = [
|
|
23
|
+
{
|
|
24
|
+
event: DataEvent.onValueInit,
|
|
25
|
+
effect: ((params) => {
|
|
26
|
+
const { context, form, name } = params;
|
|
27
|
+
|
|
28
|
+
const renameService = context.node.getService(VariableFieldKeyRenameService);
|
|
29
|
+
|
|
30
|
+
const disposable = renameService.onRename(({ before, after }) => {
|
|
31
|
+
const beforeKeyPath = [
|
|
32
|
+
...before.parentFields.map((_field) => _field.key).reverse(),
|
|
33
|
+
before.key,
|
|
34
|
+
];
|
|
35
|
+
const afterKeyPath = [
|
|
36
|
+
...after.parentFields.map((_field) => _field.key).reverse(),
|
|
37
|
+
after.key,
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
// traverse rename refs inside form item 'name'
|
|
41
|
+
traverseRef(name, form.getValueIn(name), (_drilldownName, _v) => {
|
|
42
|
+
if (isRefMatch(_v, beforeKeyPath)) {
|
|
43
|
+
_v.content = [...afterKeyPath, ...(_v.content || [])?.slice(beforeKeyPath.length)];
|
|
44
|
+
form.setValueIn(_drilldownName, _v);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return () => {
|
|
50
|
+
disposable.dispose();
|
|
51
|
+
};
|
|
52
|
+
}) as Effect,
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* If ref value's keyPath is the under as targetKeyPath
|
|
58
|
+
* @param value
|
|
59
|
+
* @param targetKeyPath
|
|
60
|
+
* @returns
|
|
61
|
+
*/
|
|
62
|
+
function isRefMatch(value: IFlowRefValue, targetKeyPath: string[]) {
|
|
63
|
+
return targetKeyPath.every((_key, index) => _key === value.content?.[index]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* If value is ref
|
|
68
|
+
* @param value
|
|
69
|
+
* @returns
|
|
70
|
+
*/
|
|
71
|
+
function isRef(value: any): value is IFlowRefValue {
|
|
72
|
+
return (
|
|
73
|
+
value?.type === 'ref' && Array.isArray(value?.content) && typeof value?.content[0] === 'string'
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Traverse value to find ref
|
|
79
|
+
* @param value
|
|
80
|
+
* @param options
|
|
81
|
+
* @returns
|
|
82
|
+
*/
|
|
83
|
+
function traverseRef(name: string, value: any, cb: (name: string, _v: IFlowRefValue) => void) {
|
|
84
|
+
if (isObject(value)) {
|
|
85
|
+
if (isRef(value)) {
|
|
86
|
+
cb(name, value);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
Object.entries(value).forEach(([_key, _value]) => {
|
|
91
|
+
traverseRef(`${name}.${_key}`, _value, cb);
|
|
92
|
+
});
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (isArray(value)) {
|
|
97
|
+
value.forEach((_value, idx) => {
|
|
98
|
+
traverseRef(`${name}[${idx}]`, _value, cb);
|
|
99
|
+
});
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return;
|
|
104
|
+
}
|
package/src/effects/index.ts
CHANGED
|
@@ -74,7 +74,12 @@ export namespace JsonSchemaUtils {
|
|
|
74
74
|
* @param typeAST
|
|
75
75
|
* @returns
|
|
76
76
|
*/
|
|
77
|
-
export function astToSchema(
|
|
77
|
+
export function astToSchema(
|
|
78
|
+
typeAST: ASTNode,
|
|
79
|
+
options?: { drilldown?: boolean }
|
|
80
|
+
): IJsonSchema | undefined {
|
|
81
|
+
const { drilldown = true } = options || {};
|
|
82
|
+
|
|
78
83
|
if (ASTMatch.isString(typeAST)) {
|
|
79
84
|
return {
|
|
80
85
|
type: 'string',
|
|
@@ -102,23 +107,25 @@ export namespace JsonSchemaUtils {
|
|
|
102
107
|
if (ASTMatch.isObject(typeAST)) {
|
|
103
108
|
return {
|
|
104
109
|
type: 'object',
|
|
105
|
-
properties:
|
|
106
|
-
Object.
|
|
107
|
-
|
|
110
|
+
properties: drilldown
|
|
111
|
+
? Object.fromEntries(
|
|
112
|
+
Object.entries(typeAST.properties).map(([key, value]) => [key, astToSchema(value)!])
|
|
113
|
+
)
|
|
114
|
+
: {},
|
|
108
115
|
};
|
|
109
116
|
}
|
|
110
117
|
|
|
111
118
|
if (ASTMatch.isArray(typeAST)) {
|
|
112
119
|
return {
|
|
113
120
|
type: 'array',
|
|
114
|
-
items: astToSchema(typeAST.items),
|
|
121
|
+
items: drilldown ? astToSchema(typeAST.items) : undefined,
|
|
115
122
|
};
|
|
116
123
|
}
|
|
117
124
|
|
|
118
125
|
if (ASTMatch.isMap(typeAST)) {
|
|
119
126
|
return {
|
|
120
127
|
type: 'map',
|
|
121
|
-
items: astToSchema(typeAST.valueType),
|
|
128
|
+
items: drilldown ? astToSchema(typeAST.valueType) : undefined,
|
|
122
129
|
};
|
|
123
130
|
}
|
|
124
131
|
|