Merge pull request #229 from webzard-io/fix/windlike-patch

fix(editor): make the form update correctly
This commit is contained in:
tanbowensg 2022-01-28 13:36:05 +08:00 committed by GitHub
commit 87e6289747
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 121 additions and 63 deletions

View File

@ -5,7 +5,7 @@ import { simple as simpleWalk } from 'acorn-walk';
import { flattenDeep, isArray, isObject } from 'lodash-es';
import { ComponentId, IFieldModel, ModuleId } from './IAppModel';
const regExp = new RegExp('.*{{.*}}.*');
const regExp = /.*{{.*}}.*/;
export class FieldModel implements IFieldModel {
isDynamic = false;
@ -32,21 +32,39 @@ export class FieldModel implements IFieldModel {
return this.value;
}
update(value: unknown) {
private updateValue(value: unknown, shouldExtendValues = true) {
if (isObject(value)) {
if (!isObject(this.value)) {
this.value = isArray(value) ? [] : {};
}
const isArrayValue = isArray(value);
const isOldValueObject = isObject(this.value);
for (const key in value) {
const val = (value as Record<string, unknown>)[key];
const _thisValue = this.value as Record<string, IFieldModel>;
if (!_thisValue[key]) {
_thisValue[key] = new FieldModel(val);
} else {
_thisValue[key].update(val);
}
}
this.value = (Object.keys(value) as Array<keyof typeof value>).reduce(
(result, key) => {
const oldValue: IFieldModel | null = isObject(this.value)
? this.value[key]
: null;
let newValue: FieldModel;
if (oldValue) {
(oldValue as FieldModel).updateValue(value[key], false);
newValue = oldValue;
} else {
newValue = new FieldModel(value[key]);
}
if (isArray(result)) {
result.push(newValue);
} else {
result[key] = newValue;
}
return result;
},
(isArrayValue
? []
: shouldExtendValues && isOldValueObject
? this.value
: {}) as Record<string, IFieldModel>
);
} else {
this.value = value;
}
@ -54,6 +72,10 @@ export class FieldModel implements IFieldModel {
this.parseReferences();
}
update(value: unknown) {
this.updateValue(value);
}
getProperty(key: string | number): FieldModel | undefined {
if (typeof this.value === 'object') {
return (this.value as any)[key];
@ -62,7 +84,7 @@ export class FieldModel implements IFieldModel {
}
getValue() {
return this.value
return this.value;
}
traverse(cb: (f: IFieldModel, key: string) => void) {
@ -102,7 +124,7 @@ export class FieldModel implements IFieldModel {
const str = exp.slice(node.start, node.end);
let path = str.replace(lastIdentifier, '');
if (path.startsWith('.')) {
path = path.slice(1, path.length)
path = path.slice(1, path.length);
}
this.refs[lastIdentifier].push(path);
break;

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useState, useEffect } from 'react';
import { flatten } from 'lodash-es';
import { observer } from 'mobx-react-lite';
import { FormControl, FormLabel, Input, Textarea, VStack } from '@chakra-ui/react';
@ -29,30 +29,50 @@ export const renderField = (properties: {
services: EditorServices;
}) => {
const { value, type, fullKey, selectedComponentId, index, services } = properties;
// eslint-disable-next-line react-hooks/rules-of-hooks
const [textareaValue, setTextareaValue] = useState(value as string);
const { eventBus, registry } = services;
// eslint-disable-next-line react-hooks/rules-of-hooks
useEffect(() => {
if (typeof value !== 'object') {
setTextareaValue(value as string);
}
}, [value]);
if (typeof value !== 'object') {
const ref = React.createRef<HTMLTextAreaElement>();
const onBlur = () => {
const operation = type
? genOperation(registry, 'modifyTraitProperty', {
componentId: selectedComponentId,
traitIndex: index,
properties: {
[fullKey]: ref.current?.value,
},
})
: genOperation(registry, 'modifyComponentProperty', {
componentId: selectedComponentId,
properties: {
[fullKey]: ref.current?.value,
},
});
const operation = type ? genOperation(
registry,
'modifyTraitProperty',
{
componentId: selectedComponentId,
traitIndex: index,
properties: {
[fullKey]: ref.current?.value,
},
}
) : genOperation(
registry,
'modifyComponentProperty',
{
componentId: selectedComponentId,
properties: {
[fullKey]: ref.current?.value,
},
}
);
eventBus.send('operation', operation);
};
const onChange = (event: any) => {
setTextareaValue(event.target.value);
};
return (
<FormControl key={`${selectedComponentId}-${fullKey}`}>
<FormLabel>{fullKey}</FormLabel>
<Textarea ref={ref} onBlur={onBlur} defaultValue={value as string} />
<Textarea ref={ref} onChange={onChange} onBlur={onBlur} value={textareaValue} />
</FormControl>
);
} else {

View File

@ -36,6 +36,13 @@ export const EventHandlerForm: React.FC<Props> = observer(props => {
const { components } = editorStore;
const [methods, setMethods] = useState<string[]>([]);
const formik = useFormik({
initialValues: handler,
onSubmit: values => {
onChange(values);
},
});
const updateMethods = useCallback(
(componentId: string) => {
if (componentId === GLOBAL_UTILS_ID) {
@ -57,6 +64,10 @@ export const EventHandlerForm: React.FC<Props> = observer(props => {
[components, registry]
);
useEffect(() => {
formik.setValues(handler);
}, [handler]);
useEffect(() => {
if (handler.componentId) {
updateMethods(handler.componentId);
@ -67,21 +78,14 @@ export const EventHandlerForm: React.FC<Props> = observer(props => {
updateMethods(e.target.value);
};
const formik = useFormik({
initialValues: handler,
onSubmit: values => {
onChange(values);
},
});
const typeField = (
<FormControl>
<FormLabel>Event Type</FormLabel>
<Select
name="type"
placeholder="Select Event Type"
onChange={formik.handleChange}
onBlur={() => formik.submitForm()}
onChange={formik.handleChange}
placeholder="Select Event Type"
value={formik.values.type}
>
{eventTypes.map(e => (
@ -97,12 +101,12 @@ export const EventHandlerForm: React.FC<Props> = observer(props => {
<FormLabel>Target Component</FormLabel>
<Select
name="componentId"
placeholder="Select Target Component"
onBlur={() => formik.submitForm()}
onChange={e => {
onTargetComponentChange(e);
formik.handleChange(e);
}}
onBlur={() => formik.submitForm()}
placeholder="Select Target Component"
value={formik.values.componentId}
>
{[{ id: GLOBAL_UTILS_ID }].concat(components).map(c => (
@ -118,9 +122,9 @@ export const EventHandlerForm: React.FC<Props> = observer(props => {
<FormLabel>Method</FormLabel>
<Select
name="method.name"
placeholder="Select Method"
onChange={formik.handleChange}
onBlur={() => formik.submitForm()}
onChange={formik.handleChange}
placeholder="Select Method"
value={formik.values.method.name}
>
{methods.map(m => (
@ -136,7 +140,7 @@ export const EventHandlerForm: React.FC<Props> = observer(props => {
<FormControl>
<FormLabel>Parameters</FormLabel>
<KeyValueEditor
initValue={formik.values.method.parameters}
value={formik.values.method.parameters}
onChange={json => {
formik.setFieldValue('method.parameters', json);
formik.submitForm();
@ -150,8 +154,8 @@ export const EventHandlerForm: React.FC<Props> = observer(props => {
<FormLabel>Wait Type</FormLabel>
<Select
name="wait.type"
onChange={formik.handleChange}
onBlur={() => formik.submitForm()}
onChange={formik.handleChange}
value={formik.values.wait?.type}
>
<option value="delay">delay</option>
@ -166,8 +170,8 @@ export const EventHandlerForm: React.FC<Props> = observer(props => {
<FormLabel>Wait Time</FormLabel>
<Input
name="wait.time"
onChange={formik.handleChange}
onBlur={() => formik.submitForm()}
onChange={formik.handleChange}
value={formik.values.wait?.time}
/>
</FormControl>
@ -177,10 +181,10 @@ export const EventHandlerForm: React.FC<Props> = observer(props => {
<FormControl>
<FormLabel>Disabled</FormLabel>
<Switch
name="disabled"
isChecked={formik.values.disabled}
onChange={formik.handleChange}
name="disabled"
onBlur={() => formik.submitForm()}
onChange={formik.handleChange}
/>
</FormControl>
);
@ -197,15 +201,15 @@ export const EventHandlerForm: React.FC<Props> = observer(props => {
{disabledField}
</VStack>
<IconButton
position="absolute"
right="4"
top="4"
aria-label="remove event handler"
variant="ghost"
colorScheme="red"
size="xs"
icon={<CloseIcon />}
onClick={onRemove}
position="absolute"
right="4"
size="xs"
top="4"
variant="ghost"
/>
</Box>
);

View File

@ -93,7 +93,7 @@ export const FetchTraitForm: React.FC<Props> = props => {
<FormControl>
<FormLabel>Body</FormLabel>
<KeyValueEditor
initValue={formik.values.body}
value={formik.values.body}
onChange={json => {
formik.setFieldValue('body', json);
formik.submitForm();
@ -106,7 +106,7 @@ export const FetchTraitForm: React.FC<Props> = props => {
<FormControl>
<FormLabel>Headers</FormLabel>
<KeyValueEditor
initValue={formik.values.headers}
value={formik.values.headers}
onChange={json => {
formik.setFieldValue('headers', json);
formik.submitForm();

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { FieldProps } from './fields';
import {
NumberInput,
@ -14,6 +14,10 @@ const NumberField: React.FC<Props> = props => {
const { formData, onChange } = props;
const [value, setValue] = useState(String(formData));
useEffect(() => {
setValue(String(formData));
}, [formData]);
return (
<NumberInput
value={value}

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { FieldProps } from './fields';
import { Input, Select } from '@chakra-ui/react';
@ -8,6 +8,10 @@ const StringField: React.FC<Props> = props => {
const { schema, formData, onChange } = props;
const [value, setValue] = useState(formData);
useEffect(() => {
setValue(formData);
}, [formData]);
// enum
if (Array.isArray(schema.enum)) {
return (

View File

@ -52,7 +52,7 @@ export const ModuleMetaDataForm: React.FC<ModuleMetaDataFormProps> = observer(
<FormControl>
<FormLabel>Module StateMap</FormLabel>
<KeyValueEditor
initValue={formik.values.stateMap}
value={formik.values.stateMap}
onChange={json => {
formik.setFieldValue('stateMap', json);
formik.submitForm();

View File

@ -2,18 +2,22 @@ import { CloseIcon } from '@chakra-ui/icons';
import { Button, HStack, IconButton, Input, VStack } from '@chakra-ui/react';
import produce from 'immer';
import { fromPairs, toPairs } from 'lodash-es';
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
type Props = {
onChange: (json: Record<string, string>) => void;
initValue?: Record<string, string>;
value?: Record<string, string>;
};
export const KeyValueEditor: React.FC<Props> = props => {
const [rows, setRows] = useState<Array<[string, string]>>(() => {
return toPairs(props.initValue);
return toPairs(props.value);
});
useEffect(() => {
setRows(toPairs(props.value));
}, [props.value]);
const emitDataChange = (newRows: Array<[string, string]>) => {
const json = fromPairs(newRows);
props.onChange(json);