Label form

main
Boris Sekachev 5 years ago
parent ae14894796
commit a60fd76f0d

@ -2,7 +2,7 @@
// //
// 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 Icon, { CloseCircleOutlined, PlusOutlined } from '@ant-design/icons'; import Icon, { CloseCircleOutlined, PlusOutlined } from '@ant-design/icons';
import Input from 'antd/lib/input'; import Input from 'antd/lib/input';
@ -10,11 +10,11 @@ import Button from 'antd/lib/button';
import Checkbox from 'antd/lib/checkbox'; import Checkbox from 'antd/lib/checkbox';
import Tooltip from 'antd/lib/tooltip'; import Tooltip from 'antd/lib/tooltip';
import Select from 'antd/lib/select'; import Select from 'antd/lib/select';
import Form, { FormComponentProps } from '@ant-design/compatible/lib/form/Form'; import Form, { FormInstance } from 'antd/lib/form';
import Text from 'antd/lib/typography/Text';
import Badge from 'antd/lib/badge'; import Badge from 'antd/lib/badge';
import ColorPicker from 'components/annotation-page/standard-workspace/objects-side-bar/color-picker'; import { Store } from 'antd/lib/form/interface';
import ColorPicker from 'components/annotation-page/standard-workspace/objects-side-bar/color-picker';
import { ColorizeIcon } from 'icons'; import { ColorizeIcon } from 'icons';
import patterns from 'utils/validation-patterns'; import patterns from 'utils/validation-patterns';
import consts from 'consts'; import consts from 'consts';
@ -30,91 +30,84 @@ export enum AttributeType {
NUMBER = 'NUMBER', NUMBER = 'NUMBER',
} }
type Props = FormComponentProps & { interface Props {
label: Label | null; label: Label | null;
labelNames?: string[]; labelNames?: string[];
onSubmit: (label: Label | null) => void; onSubmit: (label: Label | null) => void;
}; }
class LabelForm extends React.PureComponent<Props, {}> { export default class LabelForm extends React.Component<Props> {
private continueAfterSubmit: boolean; private continueAfterSubmit: boolean;
private formRef: RefObject<FormInstance>;
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
this.continueAfterSubmit = false; this.continueAfterSubmit = false;
this.formRef = React.createRef<FormInstance>();
} }
private handleSubmit = (e: React.FormEvent): void => { private handleSubmit = (values: Store): void => {
const { form, label, onSubmit } = this.props; const { label, onSubmit } = this.props;
e.preventDefault();
form.validateFields((error, formValues): void => {
if (!error) {
onSubmit({ onSubmit({
name: formValues.labelName, name: values.labelName,
id: label ? label.id : idGenerator(), id: label ? label.id : idGenerator(),
color: formValues.labelColor, color: values.labelColor,
attributes: formValues.keys.map( attributes: values.attributes.map((attribute: Store) => {
(key: number, index: number): Attribute => { let attrValues: any = attribute.values;
let attrValues = formValues.values[key]; if (attribute.input_type === AttributeType.NUMBER) {
if (!Array.isArray(attrValues)) {
if (formValues.type[key] === AttributeType.NUMBER) {
attrValues = attrValues.split(';'); attrValues = attrValues.split(';');
} else { } else {
attrValues = [attrValues]; attrValues = [attrValues];
} }
}
attrValues = attrValues.map((value: string) => value.trim()); attrValues = attrValues.map((value: string) => value.trim());
return { return {
name: formValues.attrName[key], ...attribute,
input_type: formValues.type[key],
mutable: formValues.mutable[key],
id: label && index < label.attributes.length ? label.attributes[index].id : key,
values: attrValues, values: attrValues,
input_type: attribute.type,
}; };
}, }),
),
}); });
form.resetFields(); if (this.formRef.current) {
this.formRef.current.resetFields();
}
if (!this.continueAfterSubmit) { if (!this.continueAfterSubmit) {
onSubmit(null); onSubmit(null);
} }
}
});
}; };
private addAttribute = (): void => { private addAttribute = (): void => {
const { form } = this.props; if (this.formRef.current) {
const keys = form.getFieldValue('keys'); const attributes = this.formRef.current.getFieldValue('attributes');
const nextKeys = keys.concat(idGenerator()); this.formRef.current.setFieldsValue({ attributes: [...attributes, { id: idGenerator() }] });
form.setFieldsValue({ }
keys: nextKeys,
});
}; };
private removeAttribute = (key: number): void => { private removeAttribute = (key: number): void => {
const { form } = this.props; if (this.formRef.current) {
const keys = form.getFieldValue('keys'); const attributes = this.formRef.current.getFieldValue('attributes');
form.setFieldsValue({ this.formRef.current.setFieldsValue({
keys: keys.filter((_key: number) => _key !== key), attributes: attributes.filter((_: any, id: number) => id !== key),
}); });
}
}; };
private renderAttributeNameInput(key: number, attr: Attribute | null): JSX.Element { /* eslint-disable class-methods-use-this */
private renderAttributeNameInput(fieldInstance: any, attr: Attribute | null): JSX.Element {
const { key } = fieldInstance;
const locked = attr ? attr.id >= 0 : false; const locked = attr ? attr.id >= 0 : false;
const value = attr ? attr.name : ''; const value = attr ? attr.name : '';
const { form } = this.props;
return ( return (
<Col span={5}> <Form.Item
<Form.Item hasFeedback> hasFeedback
{form.getFieldDecorator(`attrName[${key}]`, { name={[key, 'name']}
initialValue: value, fieldKey={[fieldInstance.fieldKey, 'name']}
rules: [ initialValue={value}
rules={[
{ {
required: true, required: true,
message: 'Please specify a name', message: 'Please specify a name',
@ -123,43 +116,37 @@ class LabelForm extends React.PureComponent<Props, {}> {
pattern: patterns.validateAttributeName.pattern, pattern: patterns.validateAttributeName.pattern,
message: patterns.validateAttributeName.message, message: patterns.validateAttributeName.message,
}, },
], ]}
})(<Input className='cvat-attribute-name-input' disabled={locked} placeholder='Name' />)} >
<Input className='cvat-attribute-name-input' disabled={locked} placeholder='Name' />
</Form.Item> </Form.Item>
</Col>
); );
} }
private renderAttributeTypeInput(key: number, attr: Attribute | null): JSX.Element { private renderAttributeTypeInput(fieldInstance: any, attr: Attribute | null): JSX.Element {
const { key } = fieldInstance;
const locked = attr ? attr.id >= 0 : false; const locked = attr ? attr.id >= 0 : false;
const type = attr ? attr.input_type.toUpperCase() : AttributeType.SELECT; const type = attr ? attr.input_type.toUpperCase() : AttributeType.SELECT;
const { form } = this.props;
return ( return (
<Col span={4}>
<Form.Item>
<Tooltip title='An HTML element representing the attribute' mouseLeaveDelay={0}> <Tooltip title='An HTML element representing the attribute' mouseLeaveDelay={0}>
{form.getFieldDecorator(`type[${key}]`, { <Form.Item name={[key, 'type']} fieldKey={[fieldInstance.fieldKey, 'type']} initialValue={type}>
initialValue: type,
})(
<Select className='cvat-attribute-type-input' disabled={locked}> <Select className='cvat-attribute-type-input' disabled={locked}>
<Select.Option value={AttributeType.SELECT}>Select</Select.Option> <Select.Option value={AttributeType.SELECT}>Select</Select.Option>
<Select.Option value={AttributeType.RADIO}>Radio</Select.Option> <Select.Option value={AttributeType.RADIO}>Radio</Select.Option>
<Select.Option value={AttributeType.CHECKBOX}>Checkbox</Select.Option> <Select.Option value={AttributeType.CHECKBOX}>Checkbox</Select.Option>
<Select.Option value={AttributeType.TEXT}>Text</Select.Option> <Select.Option value={AttributeType.TEXT}>Text</Select.Option>
<Select.Option value={AttributeType.NUMBER}>Number</Select.Option> <Select.Option value={AttributeType.NUMBER}>Number</Select.Option>
</Select>, </Select>
)}
</Tooltip>
</Form.Item> </Form.Item>
</Col> </Tooltip>
); );
} }
private renderAttributeValuesInput(key: number, attr: Attribute | null): JSX.Element { private renderAttributeValuesInput(fieldInstance: any, attr: Attribute | null): JSX.Element {
const { key } = fieldInstance;
const locked = attr ? attr.id >= 0 : false; const locked = attr ? attr.id >= 0 : false;
const existedValues = attr ? attr.values : []; const existedValues = attr ? attr.values : [];
const { form } = this.props;
const validator = (_: any, values: string[], callback: any): void => { const validator = (_: any, values: string[], callback: any): void => {
if (locked && existedValues) { if (locked && existedValues) {
@ -179,10 +166,11 @@ class LabelForm extends React.PureComponent<Props, {}> {
return ( return (
<Tooltip title='Press enter to add a new value' mouseLeaveDelay={0}> <Tooltip title='Press enter to add a new value' mouseLeaveDelay={0}>
<Form.Item> <Form.Item
{form.getFieldDecorator(`values[${key}]`, { name={[key, 'values']}
initialValue: existedValues, fieldKey={[fieldInstance.fieldKey, 'values']}
rules: [ initialValue={existedValues}
rules={[
{ {
required: true, required: true,
message: 'Please specify values', message: 'Please specify values',
@ -190,44 +178,39 @@ class LabelForm extends React.PureComponent<Props, {}> {
{ {
validator, validator,
}, },
], ]}
})( >
<Select <Select
className='cvat-attribute-values-input' className='cvat-attribute-values-input'
mode='tags' mode='tags'
dropdownMenuStyle={{ display: 'none' }}
placeholder='Attribute values' placeholder='Attribute values'
/>, dropdownStyle={{ display: 'none' }}
)} />
</Form.Item> </Form.Item>
</Tooltip> </Tooltip>
); );
} }
private renderBooleanValueInput(key: number, attr: Attribute | null): JSX.Element { private renderBooleanValueInput(fieldInstance: any, attr: Attribute | null): JSX.Element {
const { key } = fieldInstance;
const value = attr ? attr.values[0] : 'false'; const value = attr ? attr.values[0] : 'false';
const { form } = this.props;
return ( return (
<Tooltip title='Specify a default value' mouseLeaveDelay={0}> <Tooltip title='Specify a default value' mouseLeaveDelay={0}>
<Form.Item> <Form.Item name={[key, 'values']} fieldKey={[fieldInstance.fieldKey, 'values']} initialValue={value}>
{form.getFieldDecorator(`values[${key}]`, {
initialValue: value,
})(
<Select className='cvat-attribute-values-input'> <Select className='cvat-attribute-values-input'>
<Select.Option value='false'> False </Select.Option> <Select.Option value='false'> False </Select.Option>
<Select.Option value='true'> True </Select.Option> <Select.Option value='true'> True </Select.Option>
</Select>, </Select>
)}
</Form.Item> </Form.Item>
</Tooltip> </Tooltip>
); );
} }
private renderNumberRangeInput(key: number, attr: Attribute | null): JSX.Element { private renderNumberRangeInput(fieldInstance: any, attr: Attribute | null): JSX.Element {
const { key } = fieldInstance;
const locked = attr ? attr.id >= 0 : false; const locked = attr ? attr.id >= 0 : false;
const value = attr ? attr.values.join(';') : ''; const value = attr ? attr.values.join(';') : '';
const { form } = this.props;
const validator = (_: any, strNumbers: string, callback: any): void => { const validator = (_: any, strNumbers: string, callback: any): void => {
const numbers = strNumbers.split(';').map((number): number => Number.parseFloat(number)); const numbers = strNumbers.split(';').map((number): number => Number.parseFloat(number));
@ -259,10 +242,11 @@ class LabelForm extends React.PureComponent<Props, {}> {
}; };
return ( return (
<Form.Item> <Form.Item
{form.getFieldDecorator(`values[${key}]`, { name={[key, 'values']}
initialValue: value, fieldKey={[fieldInstance.fieldKey, 'values']}
rules: [ initialValue={value}
rules={[
{ {
required: true, required: true,
message: 'Please set a range', message: 'Please set a range',
@ -270,54 +254,45 @@ class LabelForm extends React.PureComponent<Props, {}> {
{ {
validator, validator,
}, },
], ]}
})(<Input className='cvat-attribute-values-input' disabled={locked} placeholder='min;max;step' />)} >
<Input className='cvat-attribute-values-input' disabled={locked} placeholder='min;max;step' />
</Form.Item> </Form.Item>
); );
} }
private renderDefaultValueInput(key: number, attr: Attribute | null): JSX.Element { private renderDefaultValueInput(fieldInstance: any, attr: Attribute | null): JSX.Element {
const { key } = fieldInstance;
const value = attr ? attr.values[0] : ''; const value = attr ? attr.values[0] : '';
const { form } = this.props;
return ( return (
<Form.Item> <Form.Item name={[key, 'values']} fieldKey={[fieldInstance.fieldKey, 'values']} initialValue={value}>
{form.getFieldDecorator(`values[${key}]`, { <Input className='cvat-attribute-values-input' placeholder='Default value' />
initialValue: value,
})(<Input className='cvat-attribute-values-input' placeholder='Default value' />)}
</Form.Item> </Form.Item>
); );
} }
private renderMutableAttributeInput(key: number, attr: Attribute | null): JSX.Element { private renderMutableAttributeInput(fieldInstance: any, attr: Attribute | null): JSX.Element {
const { key } = fieldInstance;
const locked = attr ? attr.id >= 0 : false; const locked = attr ? attr.id >= 0 : false;
const value = attr ? attr.mutable : false; const value = attr ? attr.mutable : false;
const { form } = this.props;
return ( return (
<Form.Item>
<Tooltip title='Can this attribute be changed frame to frame?' mouseLeaveDelay={0}> <Tooltip title='Can this attribute be changed frame to frame?' mouseLeaveDelay={0}>
{form.getFieldDecorator(`mutable[${key}]`, { <Form.Item name={[key, 'mutable']} fieldKey={[fieldInstance.fieldKey, 'mutable']} initialValue={value} valuePropName='checked'>
initialValue: value, <Checkbox className='cvat-attribute-mutable-checkbox' disabled={locked}>Mutable</Checkbox>
valuePropName: 'checked',
})(
<Checkbox className='cvat-attribute-mutable-checkbox' disabled={locked}>
{' '}
Mutable
{' '}
</Checkbox>,
)}
</Tooltip>
</Form.Item> </Form.Item>
</Tooltip>
); );
} }
private renderDeleteAttributeButton(key: number, attr: Attribute | null): JSX.Element { private renderDeleteAttributeButton(fieldInstance: any, attr: Attribute | null): JSX.Element {
const { key } = fieldInstance;
const locked = attr ? attr.id >= 0 : false; const locked = attr ? attr.id >= 0 : false;
return ( return (
<Form.Item>
<Tooltip title='Delete the attribute' mouseLeaveDelay={0}> <Tooltip title='Delete the attribute' mouseLeaveDelay={0}>
<Form.Item>
<Button <Button
type='link' type='link'
className='cvat-delete-attribute-button' className='cvat-delete-attribute-button'
@ -328,61 +303,70 @@ class LabelForm extends React.PureComponent<Props, {}> {
> >
<CloseCircleOutlined /> <CloseCircleOutlined />
</Button> </Button>
</Tooltip>
</Form.Item> </Form.Item>
</Tooltip>
); );
} }
private renderAttribute = (key: number): JSX.Element => { private renderAttribute = (fieldInstance: any): JSX.Element => {
const { label, form } = this.props; const { label } = this.props;
const attr = label ? label.attributes.filter((_attr: any): boolean => _attr.id === key)[0] : null; const { key } = fieldInstance;
const fieldValue = this.formRef.current?.getFieldValue('attributes')[key];
const attr = label ? label.attributes.filter((_attr: any): boolean => _attr.id === fieldValue.id)[0] : null;
return ( return (
<Form.Item key={key}> <Form.Item
noStyle
key={key}
shouldUpdate
>
{() => ((
<Row <Row
type='flex'
justify='space-between' justify='space-between'
align='middle' align='middle'
cvat-attribute-id={key} cvat-attribute-id={key}
className='cvat-attribute-inputs-wrapper' className='cvat-attribute-inputs-wrapper'
> >
{this.renderAttributeNameInput(key, attr)} <Col span={5}>{this.renderAttributeNameInput(fieldInstance, attr)}</Col>
{this.renderAttributeTypeInput(key, attr)} <Col span={4}>{this.renderAttributeTypeInput(fieldInstance, attr)}</Col>
<Col span={6}> <Col span={6}>
{((): JSX.Element => { {((): JSX.Element => {
const type = form.getFieldValue(`type[${key}]`); const currentFieldValue = this.formRef.current?.getFieldValue('attributes')[key];
const type = currentFieldValue.type || AttributeType.SELECT;
let element = null; let element = null;
if ([AttributeType.SELECT, AttributeType.RADIO].includes(type)) { if ([AttributeType.SELECT, AttributeType.RADIO].includes(type)) {
element = this.renderAttributeValuesInput(key, attr); element = this.renderAttributeValuesInput(fieldInstance, attr);
} else if (type === AttributeType.CHECKBOX) { } else if (type === AttributeType.CHECKBOX) {
element = this.renderBooleanValueInput(key, attr); element = this.renderBooleanValueInput(fieldInstance, attr);
} else if (type === AttributeType.NUMBER) { } else if (type === AttributeType.NUMBER) {
element = this.renderNumberRangeInput(key, attr); element = this.renderNumberRangeInput(fieldInstance, attr);
} else { } else {
element = this.renderDefaultValueInput(key, attr); element = this.renderDefaultValueInput(fieldInstance, attr);
} }
return element; return element;
})()} })()}
</Col> </Col>
<Col span={5}>{this.renderMutableAttributeInput(key, attr)}</Col> <Col span={5}>{this.renderMutableAttributeInput(fieldInstance, attr)}</Col>
<Col span={2}>{this.renderDeleteAttributeButton(key, attr)}</Col> <Col span={2}>{this.renderDeleteAttributeButton(fieldInstance, attr)}</Col>
</Row> </Row>
))}
</Form.Item> </Form.Item>
); );
}; };
private renderLabelNameInput(): JSX.Element { private renderLabelNameInput(): JSX.Element {
const { label, form, labelNames } = this.props; const { label, labelNames } = this.props;
const value = label ? label.name : ''; const value = label ? label.name : '';
const locked = label ? label.id >= 0 : false; const locked = label ? label.id >= 0 : false;
return ( return (
<Col span={10}> <Form.Item
<Form.Item hasFeedback> hasFeedback
{form.getFieldDecorator('labelName', { name='labelName'
initialValue: value, initialValue={value}
rules: [ rules={
[
{ {
required: true, required: true,
message: 'Please specify a name', message: 'Please specify a name',
@ -398,29 +382,27 @@ class LabelForm extends React.PureComponent<Props, {}> {
} }
}, },
}, },
], ]
})(<Input disabled={locked} placeholder='Label name' />)} }
>
<Input disabled={locked} placeholder='Label name' />
</Form.Item> </Form.Item>
</Col>
); );
} }
private renderNewAttributeButton(): JSX.Element { private renderNewAttributeButton(): JSX.Element {
return ( return (
<Col span={6}>
<Form.Item> <Form.Item>
<Button type='ghost' onClick={this.addAttribute} className='cvat-new-attribute-button'> <Button type='ghost' onClick={this.addAttribute} className='cvat-new-attribute-button'>
Add an attribute Add an attribute
<PlusOutlined /> <PlusOutlined />
</Button> </Button>
</Form.Item> </Form.Item>
</Col>
); );
} }
private renderDoneButton(): JSX.Element { private renderDoneButton(): JSX.Element {
return ( return (
<Col>
<Tooltip title='Save the label and return' mouseLeaveDelay={0}> <Tooltip title='Save the label and return' mouseLeaveDelay={0}>
<Button <Button
style={{ width: '150px' }} style={{ width: '150px' }}
@ -433,17 +415,14 @@ class LabelForm extends React.PureComponent<Props, {}> {
Done Done
</Button> </Button>
</Tooltip> </Tooltip>
</Col>
); );
} }
private renderContinueButton(): JSX.Element { private renderContinueButton(): JSX.Element | null {
const { label } = this.props; const { label } = this.props;
return label ? ( if (label) return null;
<div /> return (
) : (
<Col offset={1}>
<Tooltip title='Save the label and create one more' mouseLeaveDelay={0}> <Tooltip title='Save the label and create one more' mouseLeaveDelay={0}>
<Button <Button
style={{ width: '150px' }} style={{ width: '150px' }}
@ -456,7 +435,6 @@ class LabelForm extends React.PureComponent<Props, {}> {
Continue Continue
</Button> </Button>
</Tooltip> </Tooltip>
</Col>
); );
} }
@ -464,7 +442,6 @@ class LabelForm extends React.PureComponent<Props, {}> {
const { onSubmit } = this.props; const { onSubmit } = this.props;
return ( return (
<Col offset={1}>
<Tooltip title='Do not save the label and return' mouseLeaveDelay={0}> <Tooltip title='Do not save the label and return' mouseLeaveDelay={0}>
<Button <Button
danger danger
@ -476,71 +453,82 @@ class LabelForm extends React.PureComponent<Props, {}> {
Cancel Cancel
</Button> </Button>
</Tooltip> </Tooltip>
</Col>
); );
} }
private renderChangeColorButton(): JSX.Element { private renderChangeColorButton(): JSX.Element {
const { label, form } = this.props; const { label } = this.props;
return ( return (
<Col span={3}> <Form.Item name='labelColor' initialValue={label && label.color ? label.color : undefined}>
<Form.Item>
{form.getFieldDecorator('labelColor', {
initialValue: label && label.color ? label.color : undefined,
})(
<ColorPicker placement='bottom'> <ColorPicker placement='bottom'>
<Tooltip title='Change color of the label'> <Tooltip title='Change color of the label'>
<Button type='default' className='cvat-change-task-label-color-button'> <Button type='default' className='cvat-change-task-label-color-button'>
<Badge <Badge
className='cvat-change-task-label-color-badge' className='cvat-change-task-label-color-badge'
color={form.getFieldValue('labelColor') || consts.NEW_LABEL_COLOR} color={this.formRef.current?.getFieldValue('labelColor') || consts.NEW_LABEL_COLOR}
text={<Icon component={ColorizeIcon} />} text={<Icon component={ColorizeIcon} />}
/> />
</Button> </Button>
</Tooltip> </Tooltip>
</ColorPicker>, </ColorPicker>
)}
</Form.Item> </Form.Item>
</Col>
); );
} }
public render(): JSX.Element { private renderAttributes() {
const { label, form } = this.props; return (fieldInstances: any[]): JSX.Element[] => fieldInstances.map(this.renderAttribute);
}
form.getFieldDecorator('keys', { // eslint-disable-next-line react/sort-comp
initialValue: label ? label.attributes.map((attr: Attribute): number => attr.id) : [], public componentDidMount(): void {
const { label } = this.props;
if (this.formRef.current) {
this.formRef.current.setFieldsValue({
attributes: label ? label.attributes
.map((attribute: Attribute): Store => ({
...attribute,
type: attribute.input_type,
})) : [],
}); });
}
}
const keys = form.getFieldValue('keys'); public render(): JSX.Element {
const attributeItems = keys.map(this.renderAttribute);
return ( return (
<Form onSubmit={this.handleSubmit}> <Form onFinish={this.handleSubmit} layout='vertical' ref={this.formRef}>
<Row type='flex' justify='start' align='middle'> <Row justify='start' align='middle'>
<Col span={10}>
{this.renderLabelNameInput()} {this.renderLabelNameInput()}
</Col>
<Col span={1} /> <Col span={1} />
<Col span={3}>
{this.renderChangeColorButton()} {this.renderChangeColorButton()}
</Col>
<Col span={1} /> <Col span={1} />
<Col span={6}>
{this.renderNewAttributeButton()} {this.renderNewAttributeButton()}
</Col>
</Row> </Row>
{attributeItems.length > 0 && ( <Row justify='start' align='middle'>
<Row type='flex' justify='start' align='middle'> <Col span={24}>
<Col> <Form.List name='attributes'>
<Text>Attributes</Text> { this.renderAttributes() }
</Form.List>
</Col> </Col>
</Row> </Row>
)} <Row justify='start' align='middle'>
{attributeItems.reverse()} <Col>
<Row type='flex' justify='start' align='middle'>
{this.renderDoneButton()} {this.renderDoneButton()}
</Col>
<Col offset={1}>
{this.renderContinueButton()} {this.renderContinueButton()}
</Col>
<Col offset={1}>
{this.renderCancelButton()} {this.renderCancelButton()}
</Col>
</Row> </Row>
</Form> </Form>
); );
} }
} }
export default Form.create<Props>()(LabelForm);

@ -298,7 +298,7 @@ export default class DetailsComponent extends React.PureComponent<Props, State>
return ( return (
<Row> <Row>
<Col> <Col span={24}>
<LabelsEditorComponent <LabelsEditorComponent
labels={taskInstance.labels.map((label: any): string => label.toJSON())} labels={taskInstance.labels.map((label: any): string => label.toJSON())}
onSubmit={(labels: any[]): void => { onSubmit={(labels: any[]): void => {

Loading…
Cancel
Save