Selaa lähdekoodia

feat: validate the name field of the categorize operator for duplicate names and nulls #918 (#1471)

### What problem does this PR solve?

feat: validate the name field of the categorize operator for duplicate
names and nulls #918

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
tags/v0.9.0
balibabu 1 vuosi sitten
vanhempi
commit
9c023b6d8c
No account linked to committer's email address

+ 2
- 0
web/src/locales/en.ts Näytä tiedosto

blank: 'Blank', blank: 'Blank',
createFromNothing: 'Create from nothing', createFromNothing: 'Create from nothing',
addItem: 'Add Item', addItem: 'Add Item',
nameRequiredMsg: 'Name is required',
nameRepeatedMsg: 'The name cannot be repeated',
}, },
footer: { footer: {
profile: 'All rights reserved @ React', profile: 'All rights reserved @ React',

+ 2
- 0
web/src/locales/zh-traditional.ts Näytä tiedosto

blank: '空', blank: '空',
createFromNothing: '從無到有', createFromNothing: '從無到有',
addItem: '新增', addItem: '新增',
nameRequiredMsg: '名稱不能為空',
nameRepeatedMsg: '名稱不能重複',
}, },
footer: { footer: {
profile: '“保留所有權利 @ react”', profile: '“保留所有權利 @ react”',

+ 2
- 0
web/src/locales/zh.ts Näytä tiedosto

blank: '空', blank: '空',
createFromNothing: '从无到有', createFromNothing: '从无到有',
addItem: '新增', addItem: '新增',
nameRequiredMsg: '名称不能为空',
nameRepeatedMsg: '名称不能重复',
}, },
footer: { footer: {
profile: 'All rights reserved @ React', profile: 'All rights reserved @ React',

+ 0
- 1
web/src/pages/flow/canvas/node/categorize-node.tsx Näytä tiedosto

), ),
indexesInUse, indexesInUse,
); );
console.info('newPositionMap:', newPositionMap);


const nextPostionMap = { const nextPostionMap = {
...pick(state, intersectionKeys), ...pick(state, intersectionKeys),

+ 98
- 12
web/src/pages/flow/categorize-form/dynamic-categorize.tsx Näytä tiedosto

import { useTranslate } from '@/hooks/commonHooks'; import { useTranslate } from '@/hooks/commonHooks';
import { CloseOutlined } from '@ant-design/icons'; import { CloseOutlined } from '@ant-design/icons';
import { Button, Card, Form, Input, Select } from 'antd';
import { Button, Card, Form, FormListFieldData, Input, Select } from 'antd';
import { FormInstance } from 'antd/lib';
import { humanId } from 'human-id'; import { humanId } from 'human-id';
import trim from 'lodash/trim';
import {
ChangeEventHandler,
FocusEventHandler,
useCallback,
useEffect,
useState,
} from 'react';
import { useUpdateNodeInternals } from 'reactflow'; import { useUpdateNodeInternals } from 'reactflow';
import { Operator } from '../constant'; import { Operator } from '../constant';
import { useBuildFormSelectOptions } from '../form-hooks'; import { useBuildFormSelectOptions } from '../form-hooks';
import { ICategorizeItem } from '../interface';


interface IProps { interface IProps {
nodeId?: string; nodeId?: string;
} }


interface INameInputProps {
value?: string;
onChange?: (value: string) => void;
otherNames?: string[];
validate(errors: string[]): void;
}

const getOtherFieldValues = (
form: FormInstance,
field: FormListFieldData,
latestField: string,
) =>
(form.getFieldValue(['items']) ?? [])
.map((x: any) => x[latestField])
.filter(
(x: string) =>
x !== form.getFieldValue(['items', field.name, latestField]),
);

const NameInput = ({
value,
onChange,
otherNames,
validate,
}: INameInputProps) => {
const [name, setName] = useState<string | undefined>();
const { t } = useTranslate('flow');

const handleNameChange: ChangeEventHandler<HTMLInputElement> = useCallback(
(e) => {
const val = e.target.value;
// trigger validation
if (otherNames?.some((x) => x === val)) {
validate([t('nameRepeatedMsg')]);
} else if (trim(val) === '') {
validate([t('nameRequiredMsg')]);
} else {
validate([]);
}
setName(val);
},
[otherNames, validate, t],
);

const handleNameBlur: FocusEventHandler<HTMLInputElement> = useCallback(
(e) => {
const val = e.target.value;
if (otherNames?.every((x) => x !== val) && trim(val) !== '') {
onChange?.(val);
}
},
[onChange, otherNames],
);

useEffect(() => {
setName(value);
}, [value]);

return (
<Input
value={name}
onChange={handleNameChange}
onBlur={handleNameBlur}
></Input>
);
};

const DynamicCategorize = ({ nodeId }: IProps) => { const DynamicCategorize = ({ nodeId }: IProps) => {
const updateNodeInternals = useUpdateNodeInternals(); const updateNodeInternals = useUpdateNodeInternals();
const form = Form.useFormInstance(); const form = Form.useFormInstance();
} }
> >
<Form.Item <Form.Item
label={t('name')} // TODO: repeatability check
label={t('name')}
name={[field.name, 'name']} name={[field.name, 'name']}
rules={[{ required: true, message: t('nameMessage') }]}
validateTrigger={['onChange', 'onBlur']}
rules={[
{
required: true,
whitespace: true,
message: t('nameMessage'),
},
]}
> >
<Input />
<NameInput
otherNames={getOtherFieldValues(form, field, 'name')}
validate={(errors: string[]) =>
form.setFields([
{
name: ['items', field.name, 'name'],
errors,
},
])
}
></NameInput>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t('description')} label={t('description')}
<Select <Select
allowClear allowClear
options={buildCategorizeToOptions( options={buildCategorizeToOptions(
(form.getFieldValue(['items']) ?? [])
.map((x: ICategorizeItem) => x.to)
.filter(
(x: string) =>
x !==
form.getFieldValue(['items', field.name, 'to']),
),
getOtherFieldValues(form, field, 'to'),
)} )}
/> />
</Form.Item> </Form.Item>

+ 0
- 2
web/src/pages/flow/categorize-form/hooks.ts Näytä tiedosto



const handleValuesChange = useCallback( const handleValuesChange = useCallback(
(changedValues: any, values: any) => { (changedValues: any, values: any) => {
console.info(changedValues, values);
onValuesChange?.(changedValues, { onValuesChange?.(changedValues, {
...omit(values, 'items'), ...omit(values, 'items'),
category_description: buildCategorizeObjectFromList(values.items), category_description: buildCategorizeObjectFromList(values.items),
const items = buildCategorizeListFromObject( const items = buildCategorizeListFromObject(
get(node, 'data.form.category_description', {}), get(node, 'data.form.category_description', {}),
); );
console.info('effect:', items);
form?.setFieldsValue({ form?.setFieldsValue({
items, items,
}); });

+ 7
- 2
web/src/pages/flow/form-hooks.ts Näytä tiedosto



const ExcludedNodesMap = { const ExcludedNodesMap = {
// exclude some nodes downstream of the classification node // exclude some nodes downstream of the classification node
[Operator.Categorize]: [Operator.Categorize, Operator.Answer, Operator.Begin],
[Operator.Relevant]: [Operator.Begin],
[Operator.Categorize]: [
Operator.Categorize,
Operator.Answer,
Operator.Begin,
Operator.Relevant,
],
[Operator.Relevant]: [Operator.Begin, Operator.Answer, Operator.Relevant],
[Operator.Generate]: [Operator.Begin], [Operator.Generate]: [Operator.Begin],
}; };



Loading…
Peruuta
Tallenna