Project form, raw label form

main
Boris Sekachev 5 years ago
parent 87f360aa13
commit ae14894796

@ -18,7 +18,7 @@ $completed-progress-color: #61c200;
$inprogress-progress-color: #1890ff; $inprogress-progress-color: #1890ff;
$pending-progress-color: #c1c1c1; $pending-progress-color: #c1c1c1;
$border-color-1: #c3c3c3; $border-color-1: #c3c3c3;
$border-color-2: #d9d9d9; $border-color-2: rgb(240, 240, 240);
$border-color-3: #242424; $border-color-3: #242424;
$border-color-hover: #40a9ff; $border-color-hover: #40a9ff;
$background-color-1: white; $background-color-1: white;

@ -3,13 +3,13 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import React, { import React, {
useState, useRef, useEffect, Component, useState, useRef, useEffect, RefObject,
} from 'react'; } from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import { Col, Row } from 'antd/lib/grid'; import { Col, Row } from 'antd/lib/grid';
import Text from 'antd/lib/typography/Text'; import Text from 'antd/lib/typography/Text';
import Form, { FormComponentProps, WrappedFormUtils } from '@ant-design/compatible/lib/form/Form'; import Form, { FormInstance } from 'antd/lib/form';
import Button from 'antd/lib/button'; import Button from 'antd/lib/button';
import Input from 'antd/lib/input'; import Input from 'antd/lib/input';
import notification from 'antd/lib/notification'; import notification from 'antd/lib/notification';
@ -19,44 +19,35 @@ import { CombinedState } from 'reducers/interfaces';
import LabelsEditor from 'components/labels-editor/labels-editor'; import LabelsEditor from 'components/labels-editor/labels-editor';
import { createProjectAsync } from 'actions/projects-actions'; import { createProjectAsync } from 'actions/projects-actions';
type FormRefType = Component<FormComponentProps<any>, any, any> & WrappedFormUtils; function NameConfigurationForm({ formRef }: { formRef: RefObject<FormInstance> }): JSX.Element {
const ProjectNameEditor = Form.create<FormComponentProps>()(
(props: FormComponentProps): JSX.Element => {
const { form } = props;
const { getFieldDecorator } = form;
return ( return (
<Form onSubmit={(e): void => e.preventDefault()}> <Form layout='vertical' ref={formRef}>
<Form.Item hasFeedback label={<span>Name</span>}> <Form.Item
{getFieldDecorator('name', { name='name'
rules: [ hasFeedback
label='Name'
rules={[
{ {
required: true, required: true,
message: 'Please, specify a name', message: 'Please, specify a name',
}, },
], ]}
})(<Input />)} >
<Input />
</Form.Item> </Form.Item>
</Form> </Form>
); );
}, }
);
const AdvanvedConfigurationForm = Form.create<FormComponentProps>()(
(props: FormComponentProps): JSX.Element => {
const { form } = props;
const { getFieldDecorator } = form;
function AdvanvedConfigurationForm({ formRef }: { formRef: RefObject<FormInstance> }): JSX.Element {
return ( return (
<Form onSubmit={(e): void => e.preventDefault()}> <Form layout='vertical' ref={formRef}>
<Form.Item <Form.Item
label={<span>Issue tracker</span>} name='bug_tracker'
label='Issue tracker'
extra='Attach issue tracker where the project is described' extra='Attach issue tracker where the project is described'
hasFeedback hasFeedback
> rules={[
{getFieldDecorator('bug_tracker', {
rules: [
{ {
validator: (_, value, callback): void => { validator: (_, value, callback): void => {
if (value && !patterns.validateURL.pattern.test(value)) { if (value && !patterns.validateURL.pattern.test(value)) {
@ -66,19 +57,19 @@ const AdvanvedConfigurationForm = Form.create<FormComponentProps>()(
} }
}, },
}, },
], ]}
})(<Input />)} >
<Input />
</Form.Item> </Form.Item>
</Form> </Form>
); );
}, }
);
export default function CreateProjectContent(): JSX.Element { export default function CreateProjectContent(): JSX.Element {
const [projectLabels, setProjectLabels] = useState<any[]>([]); const [projectLabels, setProjectLabels] = useState<any[]>([]);
const shouldShowNotification = useRef(false); const shouldShowNotification = useRef(false);
const nameFormRef = useRef<FormRefType>(null); const nameFormRef = useRef<FormInstance>(null);
const advancedFormRef = useRef<FormRefType>(null); const advancedFormRef = useRef<FormInstance>(null);
const dispatch = useDispatch(); const dispatch = useDispatch();
const history = useHistory(); const history = useHistory();
@ -102,29 +93,20 @@ export default function CreateProjectContent(): JSX.Element {
shouldShowNotification.current = true; shouldShowNotification.current = true;
}, [newProjectId]); }, [newProjectId]);
const onSumbit = (): void => { const onSumbit = async (): Promise<void> => {
interface Project { interface Project {
[key: string]: any; [key: string]: any;
} }
const projectData: Project = {}; const projectData: Project = {};
if (nameFormRef.current !== null) { if (nameFormRef.current && advancedFormRef.current) {
nameFormRef.current.validateFields((error, value) => { const basicValues = await nameFormRef.current.validateFields();
if (!error) { const advancedValues = await advancedFormRef.current.validateFields();
projectData.name = value.name; projectData.name = basicValues.name;
} for (const [field, value] of Object.entries(advancedValues)) {
});
}
if (advancedFormRef.current !== null) {
advancedFormRef.current.validateFields((error, values) => {
if (!error) {
for (const [field, value] of Object.entries(values)) {
projectData[field] = value; projectData[field] = value;
} }
} }
});
}
projectData.labels = projectLabels; projectData.labels = projectLabels;
@ -136,7 +118,7 @@ export default function CreateProjectContent(): JSX.Element {
return ( return (
<Row type='flex' justify='start' align='middle' className='cvat-create-project-content'> <Row type='flex' justify='start' align='middle' className='cvat-create-project-content'>
<Col span={24}> <Col span={24}>
<ProjectNameEditor ref={nameFormRef} /> <NameConfigurationForm formRef={nameFormRef} />
</Col> </Col>
<Col span={24}> <Col span={24}>
<Text className='cvat-text-color'>Labels:</Text> <Text className='cvat-text-color'>Labels:</Text>
@ -148,7 +130,7 @@ export default function CreateProjectContent(): JSX.Element {
/> />
</Col> </Col>
<Col span={24}> <Col span={24}>
<AdvanvedConfigurationForm ref={advancedFormRef} /> <AdvanvedConfigurationForm formRef={advancedFormRef} />
</Col> </Col>
<Col span={24}> <Col span={24}>
<Button type='primary' onClick={onSumbit}> <Button type='primary' onClick={onSumbit}>

@ -2,52 +2,56 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import React from 'react'; import React, { RefObject } from 'react';
import { Row, Col } from 'antd/lib/grid'; import { Row, Col } from 'antd/lib/grid';
import Input from 'antd/lib/input'; import Input from 'antd/lib/input';
import Button from 'antd/lib/button'; import Button from 'antd/lib/button';
import Tooltip from 'antd/lib/tooltip'; import Tooltip from 'antd/lib/tooltip';
import Form, { FormComponentProps } from '@ant-design/compatible/lib/form/Form'; import Form, { FormInstance, RuleObject } from 'antd/lib/form';
import { Store } from 'antd/lib/form/interface';
import { Label, Attribute, validateParsedLabel, idGenerator } from './common'; import { Label, Attribute, validateParsedLabel, idGenerator } from './common';
type Props = FormComponentProps & { function validateLabels(_: RuleObject, value: string): Promise<void> {
labels: Label[];
onSubmit: (labels: Label[]) => void;
};
class RawViewer extends React.PureComponent<Props> {
private validateLabels = (_: any, value: string, callback: any): void => {
try { try {
const parsed = JSON.parse(value); const parsed = JSON.parse(value);
if (!Array.isArray(parsed)) { if (!Array.isArray(parsed)) {
callback('Field is expected to be a JSON array'); return Promise.reject(new Error('Field is expected to be a JSON array'));
} }
const labelNames = parsed.map((label: Label) => label.name); const labelNames = parsed.map((label: Label) => label.name);
if (new Set(labelNames).size !== labelNames.length) { if (new Set(labelNames).size !== labelNames.length) {
callback('Label names must be unique for the task'); return Promise.reject(new Error('Label names must be unique for the task'));
} }
for (const label of parsed) { for (const label of parsed) {
try { try {
validateParsedLabel(label); validateParsedLabel(label);
} catch (error) { } catch (error) {
callback(error.toString()); return Promise.reject(error);
} }
} }
} catch (error) { } catch (error) {
callback(error.toString()); return Promise.reject(error);
} }
callback(); return Promise.resolve();
}; }
interface Props {
labels: Label[];
onSubmit: (labels: Label[]) => void;
}
export default class RawViewer extends React.PureComponent<Props> {
private formRef: RefObject<FormInstance>;
private handleSubmit = (e: React.FormEvent): void => { public constructor(props: Props) {
const { form, onSubmit } = this.props; super(props);
this.formRef = React.createRef<FormInstance>();
}
e.preventDefault(); private handleSubmit = (values: Store): void => {
form.validateFields((error, values): void => { const { onSubmit } = this.props;
if (!error) {
const parsed = JSON.parse(values.labels); const parsed = JSON.parse(values.labels);
for (const label of parsed) { for (const label of parsed) {
label.id = label.id || idGenerator(); label.id = label.id || idGenerator();
@ -56,8 +60,6 @@ class RawViewer extends React.PureComponent<Props> {
} }
} }
onSubmit(parsed); onSubmit(parsed);
}
});
}; };
public render(): JSX.Element { public render(): JSX.Element {
@ -76,19 +78,14 @@ class RawViewer extends React.PureComponent<Props> {
); );
const textLabels = JSON.stringify(convertedLabels, null, 2); const textLabels = JSON.stringify(convertedLabels, null, 2);
const { form } = this.props;
return ( return (
<Form onSubmit={this.handleSubmit}> <Form layout='vertical' onFinish={this.handleSubmit} ref={this.formRef}>
<Form.Item> <Form.Item
{form.getFieldDecorator('labels', { name='labels'
initialValue: textLabels, initialValue={textLabels}
rules: [ rules={[{ validator: validateLabels }]}
{ >
validator: this.validateLabels, <Input.TextArea rows={5} className='cvat-raw-labels-viewer' />
},
],
})(<Input.TextArea rows={5} className='cvat-raw-labels-viewer' />)}
</Form.Item> </Form.Item>
<Row type='flex' justify='start' align='middle'> <Row type='flex' justify='start' align='middle'>
<Col> <Col>
@ -104,7 +101,9 @@ class RawViewer extends React.PureComponent<Props> {
danger danger
style={{ width: '150px' }} style={{ width: '150px' }}
onClick={(): void => { onClick={(): void => {
form.resetFields(); if (this.formRef.current) {
this.formRef.current.resetFields();
}
}} }}
> >
Reset Reset
@ -116,5 +115,3 @@ class RawViewer extends React.PureComponent<Props> {
); );
} }
} }
export default Form.create<Props>()(RawViewer);

Loading…
Cancel
Save