Part of forms was updated

main
Boris Sekachev 5 years ago
parent 55f4d95e67
commit 4a0cf6b0f8

@ -4,8 +4,10 @@
import './styles.scss';
import React from 'react';
import Menu, { ClickParam } from 'antd/lib/menu';
import Menu from 'antd/lib/menu';
import Modal from 'antd/lib/modal';
// eslint-disable-next-line import/no-extraneous-dependencies
import { MenuInfo } from 'rc-menu/lib/interface';
import DumpSubmenu from './dump-submenu';
import LoadSubmenu from './load-submenu';
@ -22,7 +24,7 @@ interface Props {
exportActivities: string[] | null;
inferenceIsActive: boolean;
onClickMenu: (params: ClickParam, file?: File) => void;
onClickMenu: (params: MenuInfo, file?: File) => void;
}
export enum Actions {
@ -48,8 +50,8 @@ export default function ActionsMenuComponent(props: Props): JSX.Element {
loadActivity,
} = props;
let latestParams: ClickParam | null = null;
function onClickMenuWrapper(params: ClickParam | null, file?: File): void {
let latestParams: MenuInfo | null = null;
function onClickMenuWrapper(params: MenuInfo | null, file?: File): void {
const copyParams = params || latestParams;
if (!copyParams) {
return;
@ -67,7 +69,7 @@ export default function ActionsMenuComponent(props: Props): JSX.Element {
onClickMenu(copyParams, file);
},
okButtonProps: {
type: 'danger',
danger: true,
},
okText: 'Update',
});
@ -83,7 +85,7 @@ export default function ActionsMenuComponent(props: Props): JSX.Element {
onClickMenu(copyParams);
},
okButtonProps: {
type: 'danger',
danger: true,
},
okText: 'Delete',
});

@ -7,7 +7,7 @@ import { AnyAction } from 'redux';
import { connect } from 'react-redux';
import Text from 'antd/lib/typography/Text';
import Radio, { RadioChangeEvent } from 'antd/lib/radio';
import Slider, { SliderValue } from 'antd/lib/slider';
import Slider from 'antd/lib/slider';
import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox';
import Collapse from 'antd/lib/collapse';
@ -42,8 +42,8 @@ interface StateToProps {
interface DispatchToProps {
collapseAppearance(): void;
changeShapesColorBy(event: RadioChangeEvent): void;
changeShapesOpacity(event: SliderValue): void;
changeSelectedShapesOpacity(event: SliderValue): void;
changeShapesOpacity(value: number): void;
changeSelectedShapesOpacity(value: number): void;
changeShapesOutlinedBorders(outlined: boolean, color: string): void;
changeShowBitmap(event: CheckboxChangeEvent): void;
changeShowProjections(event: CheckboxChangeEvent): void;
@ -107,11 +107,11 @@ function mapDispatchToProps(dispatch: Dispatch<AnyAction>): DispatchToProps {
changeShapesColorBy(event: RadioChangeEvent): void {
dispatch(changeShapesColorByAction(event.target.value));
},
changeShapesOpacity(value: SliderValue): void {
dispatch(changeShapesOpacityAction(value as number));
changeShapesOpacity(value: number): void {
dispatch(changeShapesOpacityAction(value));
},
changeSelectedShapesOpacity(value: SliderValue): void {
dispatch(changeSelectedShapesOpacityAction(value as number));
changeSelectedShapesOpacity(value: number): void {
dispatch(changeSelectedShapesOpacityAction(value));
},
changeShapesOutlinedBorders(outlined: boolean, color: string): void {
dispatch(changeShapesOutlinedBordersAction(outlined, color));

@ -4,7 +4,9 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Menu, { ClickParam } from 'antd/lib/menu';
import Menu from 'antd/lib/menu';
// eslint-disable-next-line import/no-extraneous-dependencies
import { MenuInfo } from 'rc-menu/lib/interface';
import ObjectItemContainer from 'containers/annotation-page/standard-workspace/objects-side-bar/object-item';
import { Workspace } from 'reducers/interfaces';
@ -27,7 +29,7 @@ interface ReviewContextMenuProps {
top: number;
left: number;
latestComments: string[];
onClick: (param: ClickParam) => void;
onClick: (param: MenuInfo) => void;
}
enum ReviewContextMenuKeys {
@ -95,7 +97,7 @@ export default function CanvasContextMenu(props: Props): JSX.Element | null {
top={top}
left={left}
latestComments={latestComments}
onClick={(param: ClickParam) => {
onClick={(param: MenuInfo) => {
const [state] = objectStates.filter(
(_state: any): boolean => _state.clientID === contextMenuClientID,
);

@ -129,9 +129,9 @@ function DrawShapePopoverComponent(props: Props): JSX.Element {
</Col>
<Col span={10}>
<InputNumber
onChange={(value: number | undefined) => {
if (typeof value === 'number') {
onChangePoints(Math.floor(clamp(value, minimumPoints, Number.MAX_SAFE_INTEGER)));
onChange={(value: number | undefined | string) => {
if (typeof value !== 'undefined') {
onChangePoints(Math.floor(clamp(+value, minimumPoints, Number.MAX_SAFE_INTEGER)));
} else if (!value) {
onChangePoints(undefined);
}

@ -531,10 +531,10 @@ export class ToolsControlComponent extends React.PureComponent<Props, State> {
min={1}
precision={0}
max={jobInstance.stopFrame - frame}
onChange={(value: number | undefined): void => {
onChange={(value: number | undefined | string): void => {
if (typeof value !== 'undefined') {
this.setState({
trackingFrames: value,
trackingFrames: +value,
});
}
}}

@ -134,9 +134,9 @@ function ItemAttributeComponent(props: Props): JSX.Element {
<InputNumber
disabled={readonly}
size='small'
onChange={(value: number | undefined): void => {
if (typeof value === 'number') {
changeAttribute(attrID, `${clamp(value, min, max)}`);
onChange={(value: number | undefined | string): void => {
if (typeof value !== 'undefined') {
changeAttribute(attrID, `${clamp(+value, min, max)}`);
}
}}
value={+attrValue}

@ -52,10 +52,10 @@ export default function PropagateConfirmComponent(props: Props): JSX.Element {
size='small'
min={minPropagateFrames}
value={propagateFrames}
onChange={(value: number | undefined) => {
if (typeof value === 'number') {
onChange={(value: number | undefined | string) => {
if (typeof value !== 'undefined') {
changePropagateFrames(
Math.floor(clamp(value, minPropagateFrames, Number.MAX_SAFE_INTEGER)),
Math.floor(clamp(+value, minPropagateFrames, Number.MAX_SAFE_INTEGER)),
);
}
}}
@ -67,9 +67,9 @@ export default function PropagateConfirmComponent(props: Props): JSX.Element {
value={propagateUpToFrame}
min={frameNumber + 1}
max={stopFrame}
onChange={(value: number | undefined) => {
if (typeof value === 'number') {
changeUpToFrame(Math.floor(clamp(value, frameNumber + 1, stopFrame)));
onChange={(value: number | undefined | string) => {
if (typeof value !== 'undefined') {
changeUpToFrame(Math.floor(clamp(+value, frameNumber + 1, stopFrame)));
}
}}
/>

@ -3,8 +3,10 @@
// SPDX-License-Identifier: MIT
import React from 'react';
import Menu, { ClickParam } from 'antd/lib/menu';
import Menu from 'antd/lib/menu';
import Modal from 'antd/lib/modal';
// eslint-disable-next-line import/no-extraneous-dependencies
import { MenuInfo } from 'rc-menu/lib/interface';
import DumpSubmenu from 'components/actions-menu/dump-submenu';
import LoadSubmenu from 'components/actions-menu/load-submenu';
@ -19,7 +21,7 @@ interface Props {
exportActivities: string[] | null;
isReviewer: boolean;
jobInstance: any;
onClickMenu(params: ClickParam, file?: File): void;
onClickMenu(params: MenuInfo, file?: File): void;
setForceExitAnnotationFlag(forceExit: boolean): void;
saveAnnotations(jobInstance: any, afterSave?: () => void): void;
}
@ -54,15 +56,15 @@ export default function AnnotationMenuComponent(props: Props): JSX.Element {
const jobStatus = jobInstance.status;
const taskID = jobInstance.task.id;
let latestParams: ClickParam | null = null;
function onClickMenuWrapper(params: ClickParam | null, file?: File): void {
let latestParams: MenuInfo | null = null;
function onClickMenuWrapper(params: MenuInfo | null, file?: File): void {
const copyParams = params || latestParams;
if (!copyParams) {
return;
}
latestParams = params;
function checkUnsavedChanges(_copyParams: ClickParam): void {
function checkUnsavedChanges(_copyParams: MenuInfo): void {
if (jobInstance.annotations.hasUnsavedChanges()) {
Modal.confirm({
title: 'The job has unsaved annotations',
@ -100,7 +102,7 @@ export default function AnnotationMenuComponent(props: Props): JSX.Element {
onClickMenu(copyParams, file);
},
okButtonProps: {
type: 'danger',
danger: true,
},
okText: 'Update',
});
@ -118,7 +120,7 @@ export default function AnnotationMenuComponent(props: Props): JSX.Element {
onClickMenu(copyParams);
},
okButtonProps: {
type: 'danger',
danger: true,
},
okText: 'Delete',
});

@ -6,9 +6,10 @@ import React, { useState, useEffect } from 'react';
import { Row, Col } from 'antd/lib/grid';
import { LinkOutlined } from '@ant-design/icons';
import Slider, { SliderValue } from 'antd/lib/slider';
import Slider from 'antd/lib/slider';
import Tooltip from 'antd/lib/tooltip';
import InputNumber from 'antd/lib/input-number';
import Input from 'antd/lib/input';
import Text from 'antd/lib/typography/Text';
import { clamp } from 'utils/math';
@ -19,8 +20,8 @@ interface Props {
frameNumber: number;
frameFilename: string;
focusFrameInputShortcut: string;
inputFrameRef: React.RefObject<InputNumber>;
onSliderChange(value: SliderValue): void;
inputFrameRef: React.RefObject<Input>;
onSliderChange(value: number): void;
onInputChange(value: number): void;
onURLIconClick(): void;
}
@ -76,12 +77,13 @@ function PlayerNavigation(props: Props): JSX.Element {
<Col>
<Tooltip title={`Press ${focusFrameInputShortcut} to focus here`} mouseLeaveDelay={0}>
<InputNumber
ref={inputFrameRef}
className='cvat-player-frame-selector'
type='number'
value={frameInputValue}
onChange={(value: number | undefined) => {
if (typeof value === 'number') {
setFrameInputValue(Math.floor(clamp(value, startFrame, stopFrame)));
onChange={(value: number | undefined | string) => {
if (typeof (value) !== 'undefined') {
setFrameInputValue(Math.floor(clamp(+value, startFrame, stopFrame)));
}
}}
onBlur={() => {
@ -90,7 +92,6 @@ function PlayerNavigation(props: Props): JSX.Element {
onPressEnter={() => {
onInputChange(frameInputValue);
}}
ref={inputFrameRef}
/>
</Tooltip>
</Col>

@ -5,8 +5,7 @@
import React from 'react';
import { Row, Col } from 'antd/lib/grid';
import InputNumber from 'antd/lib/input-number';
import { SliderValue } from 'antd/lib/slider';
import Input from 'antd/lib/input';
import { Workspace } from 'reducers/interfaces';
import LeftGroup from './left-group';
@ -20,7 +19,7 @@ interface Props {
savingStatuses: string[];
frameNumber: number;
frameFilename: string;
inputFrameRef: React.RefObject<InputNumber>;
inputFrameRef: React.RefObject<Input>;
startFrame: number;
stopFrame: number;
undoAction?: string;
@ -49,7 +48,7 @@ interface Props {
onLastFrame(): void;
setPrevButtonType(type: 'regular' | 'filtered' | 'empty'): void;
setNextButtonType(type: 'regular' | 'filtered' | 'empty'): void;
onSliderChange(value: SliderValue): void;
onSliderChange(value: number): void;
onInputChange(value: number): void;
onURLIconClick(): void;
onUndoClick(): void;

@ -3,12 +3,12 @@
// SPDX-License-Identifier: MIT
import React from 'react';
import Form, { FormComponentProps } from '@ant-design/compatible/lib/form/Form';
import Form from 'antd/lib/form';
import { LockOutlined } from '@ant-design/icons';
import Button from 'antd/lib/button';
import Input from 'antd/lib/input';
import patterns from 'utils/validation-patterns';
import { validateConfirmation, validatePassword } from 'components/register-page/register-form';
export interface ChangePasswordData {
oldPassword: string;
@ -16,159 +16,79 @@ export interface ChangePasswordData {
newPassword2: string;
}
type ChangePasswordFormProps = {
interface Props {
fetching: boolean;
onSubmit(loginData: ChangePasswordData): void;
} & FormComponentProps;
class ChangePasswordFormComponent extends React.PureComponent<ChangePasswordFormProps> {
private validateConfirmation = (_: any, value: string, callback: Function): void => {
const { form } = this.props;
if (value && value !== form.getFieldValue('newPassword1')) {
callback('Two passwords that you enter is inconsistent!');
} else {
callback();
}
};
private validatePassword = (_: any, value: string, callback: Function): void => {
const { form } = this.props;
if (!patterns.validatePasswordLength.pattern.test(value)) {
callback(patterns.validatePasswordLength.message);
}
if (!patterns.passwordContainsNumericCharacters.pattern.test(value)) {
callback(patterns.passwordContainsNumericCharacters.message);
}
if (!patterns.passwordContainsUpperCaseCharacter.pattern.test(value)) {
callback(patterns.passwordContainsUpperCaseCharacter.message);
}
if (!patterns.passwordContainsLowerCaseCharacter.pattern.test(value)) {
callback(patterns.passwordContainsLowerCaseCharacter.message);
}
if (value) {
form.validateFields(['newPassword2'], { force: true });
}
callback();
};
private handleSubmit = (e: React.FormEvent): void => {
e.preventDefault();
const { form, onSubmit } = this.props;
form.validateFields((error, values): void => {
if (!error) {
const validatedFields = {
...values,
confirmations: [],
};
onSubmit(validatedFields);
}
});
};
private renderOldPasswordField(): JSX.Element {
const { form } = this.props;
}
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('oldPassword', {
rules: [
{
required: true,
message: 'Please input your current password!',
},
],
})(
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Current password'
/>,
)}
function ChangePasswordFormComponent({ fetching, onSubmit }: Props): JSX.Element {
return (
<Form onFinish={onSubmit} className='change-password-form'>
<Form.Item
hasFeedback
name='oldPassword'
rules={[
{
required: true,
message: 'Please input your current password!',
},
]}
>
<Input.Password
autoComplete='current-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Current password'
/>
</Form.Item>
);
}
private renderNewPasswordField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('newPassword1', {
rules: [
{
required: true,
message: 'Please input new password!',
},
{
validator: this.validatePassword,
},
],
})(
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='New password'
/>,
)}
<Form.Item
hasFeedback
name='newPassword1'
rules={[
{
required: true,
message: 'Please input new password!',
}, validatePassword,
]}
>
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='New password'
/>
</Form.Item>
);
}
private renderNewPasswordConfirmationField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('newPassword2', {
rules: [
{
required: true,
message: 'Please confirm your new password!',
},
{
validator: this.validateConfirmation,
},
],
})(
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Confirm new password'
/>,
)}
<Form.Item
hasFeedback
name='newPassword2'
dependencies={['newPassword1']}
rules={[
{
required: true,
message: 'Please confirm your new password!',
}, validateConfirmation('newPassword1'),
]}
>
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Confirm new password'
/>
</Form.Item>
);
}
public render(): JSX.Element {
const { fetching } = this.props;
return (
<Form onSubmit={this.handleSubmit} className='change-password-form'>
{this.renderOldPasswordField()}
{this.renderNewPasswordField()}
{this.renderNewPasswordConfirmationField()}
<Form.Item>
<Button
type='primary'
htmlType='submit'
className='change-password-form-button'
loading={fetching}
disabled={fetching}
>
Submit
</Button>
</Form.Item>
</Form>
);
}
<Form.Item>
<Button
type='primary'
htmlType='submit'
className='change-password-form-button'
loading={fetching}
disabled={fetching}
>
Submit
</Button>
</Form.Item>
</Form>
);
}
export default Form.create<ChangePasswordFormProps>()(ChangePasswordFormComponent);
export default React.memo(ChangePasswordFormComponent);

@ -149,6 +149,7 @@ export default class FileManager extends React.PureComponent<Props, State> {
className='cvat-share-tree'
checkable
showLine
height={256}
checkStrictly={false}
expandedKeys={expandedKeys}
checkedKeys={files.share}

@ -5,10 +5,7 @@
@import '../../base.scss';
.cvat-share-tree {
height: fit-content;
min-height: 10em;
max-height: 20em;
overflow: auto;
height: 32 * $grid-unit-size;
}
.cvat-empty-share-tree {

@ -89,9 +89,9 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element {
min={minFrameStep}
max={maxFrameStep}
value={frameStep}
onChange={(value: number | undefined): void => {
if (typeof value === 'number') {
onChangeFrameStep(Math.floor(clamp(value, minFrameStep, maxFrameStep)));
onChange={(value: number | undefined | string): void => {
if (typeof value !== 'undefined') {
onChangeFrameStep(Math.floor(clamp(+value, minFrameStep, maxFrameStep)));
}
}}
/>
@ -174,9 +174,9 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element {
max={maxGridSize}
value={gridSize}
disabled={!grid}
onChange={(value: number | undefined): void => {
if (typeof value === 'number') {
onChangeGridSize(Math.floor(clamp(value, minGridSize, maxGridSize)));
onChange={(value: number | undefined | string): void => {
if (typeof value !== 'undefined') {
onChangeGridSize(Math.floor(clamp(+value, minGridSize, maxGridSize)));
}
}}
/>

@ -70,10 +70,10 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element {
max={maxAutoSaveInterval}
step={1}
value={Math.round(autoSaveInterval / (60 * 1000))}
onChange={(value: number | undefined): void => {
if (typeof value === 'number') {
onChange={(value: number | undefined | string): void => {
if (typeof value !== 'undefined') {
onChangeAutoSaveInterval(
Math.floor(clamp(value, minAutoSaveInterval, maxAutoSaveInterval)) * 60 * 1000,
Math.floor(clamp(+value, minAutoSaveInterval, maxAutoSaveInterval)) * 60 * 1000,
);
}
}}
@ -112,7 +112,8 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element {
<Col>
<Text type='secondary'>
{' '}
Show text for an object on the canvas not only when the object is activated{' '}
Show text for an object on the canvas not only when the object is activated
{' '}
</Text>
</Col>
</Row>
@ -131,7 +132,8 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element {
<Col>
<Text type='secondary'>
{' '}
Enable automatic bordering for polygons and polylines during drawing/editing{' '}
Enable automatic bordering for polygons and polylines during drawing/editing
{' '}
</Text>
</Col>
</Row>
@ -142,9 +144,9 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element {
min={minAAMMargin}
max={maxAAMMargin}
value={aamZoomMargin}
onChange={(value: number | undefined): void => {
if (typeof value === 'number') {
onChangeAAMZoomMargin(Math.floor(clamp(value, minAAMMargin, maxAAMMargin)));
onChange={(value: number | undefined | string): void => {
if (typeof value !== 'undefined') {
onChangeAAMZoomMargin(Math.floor(clamp(+value, minAAMMargin, maxAAMMargin)));
}
}}
/>

@ -3,9 +3,11 @@
// SPDX-License-Identifier: MIT
import React from 'react';
import Select, { OptionProps, SelectProps } from 'antd/lib/select';
import Select, { SelectProps } from 'antd/lib/select';
// eslint-disable-next-line import/no-extraneous-dependencies
import { OptionData, OptionGroupData } from 'rc-select/lib/interface';
interface Props extends SelectProps {
interface Props extends SelectProps<string> {
labels: any[];
value: any | number | null;
onChange: (label: any) => void;
@ -26,10 +28,12 @@ export default function LabelSelector(props: Props): JSX.Element {
{...rest}
{...dinamicProps}
showSearch
filterOption={(input: string, option: React.ReactElement<OptionProps>) => {
const { children } = option.props;
if (typeof children === 'string') {
return children.toLowerCase().includes(input.toLowerCase());
filterOption={(input: string, option?: OptionData | OptionGroupData) => {
if (option) {
const { children } = option.props;
if (typeof children === 'string') {
return children.toLowerCase().includes(input.toLowerCase());
}
}
return false;

@ -467,8 +467,8 @@ class LabelForm extends React.PureComponent<Props, {}> {
<Col offset={1}>
<Tooltip title='Do not save the label and return' mouseLeaveDelay={0}>
<Button
danger
style={{ width: '150px' }}
type='danger'
onClick={(): void => {
onSubmit(null);
}}

@ -101,8 +101,8 @@ class RawViewer extends React.PureComponent<Props> {
<Col offset={1}>
<Tooltip title='Do not save the label and return' mouseLeaveDelay={0}>
<Button
danger
style={{ width: '150px' }}
type='danger'
onClick={(): void => {
form.resetFields();
}}

@ -3,7 +3,7 @@
// SPDX-License-Identifier: MIT
import React from 'react';
import Form, { FormComponentProps } from '@ant-design/compatible/lib/form/Form';
import Form from 'antd/lib/form';
import Button from 'antd/lib/button';
import Input from 'antd/lib/input';
import { UserOutlined, LockOutlined } from '@ant-design/icons';
@ -13,93 +13,63 @@ export interface LoginData {
password: string;
}
type LoginFormProps = {
interface Props {
fetching: boolean;
onSubmit(loginData: LoginData): void;
} & FormComponentProps;
class LoginFormComponent extends React.PureComponent<LoginFormProps> {
private handleSubmit = (e: React.FormEvent): void => {
e.preventDefault();
const { form, onSubmit } = this.props;
form.validateFields((error, values): void => {
if (!error) {
onSubmit(values);
}
});
};
private renderUsernameField(): JSX.Element {
const { form } = this.props;
const { getFieldDecorator } = form;
}
return (
<Form.Item hasFeedback>
{getFieldDecorator('username', {
rules: [
{
required: true,
message: 'Please specify a username',
},
],
})(
<Input
autoComplete='username'
prefix={<UserOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Username'
/>,
)}
function LoginFormComponent(props: Props): JSX.Element {
const { fetching, onSubmit } = props;
return (
<Form onFinish={onSubmit} className='login-form'>
<Form.Item
hasFeedback
name='username'
rules={[
{
required: true,
message: 'Please specify a username',
},
]}
>
<Input
autoComplete='username'
prefix={<UserOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Username'
/>
</Form.Item>
);
}
private renderPasswordField(): JSX.Element {
const { form } = this.props;
const { getFieldDecorator } = form;
return (
<Form.Item hasFeedback>
{getFieldDecorator('password', {
rules: [
{
required: true,
message: 'Please specify a password',
},
],
})(
<Input
autoComplete='current-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Password'
type='password'
/>,
)}
<Form.Item
hasFeedback
name='password'
rules={[
{
required: true,
message: 'Please specify a password',
},
]}
>
<Input
autoComplete='current-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Password'
type='password'
/>
</Form.Item>
);
}
public render(): JSX.Element {
const { fetching } = this.props;
return (
<Form onSubmit={this.handleSubmit} className='login-form'>
{this.renderUsernameField()}
{this.renderPasswordField()}
<Form.Item>
<Button
type='primary'
loading={fetching}
disabled={fetching}
htmlType='submit'
className='login-form-button'
>
Sign in
</Button>
</Form.Item>
</Form>
);
}
<Form.Item>
<Button
type='primary'
loading={fetching}
disabled={fetching}
htmlType='submit'
className='login-form-button'
>
Sign in
</Button>
</Form.Item>
</Form>
);
}
export default Form.create<LoginFormProps>()(LoginFormComponent);
export default React.memo(LoginFormComponent);

@ -6,7 +6,7 @@ import './styles.scss';
import React, { useState } from 'react';
import { Row, Col } from 'antd/lib/grid';
import { CloseCircleOutlined, QuestionCircleOutlined } from '@ant-design/icons';
import Select, { OptionProps } from 'antd/lib/select';
import Select from 'antd/lib/select';
import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox';
import Tooltip from 'antd/lib/tooltip';
import Tag from 'antd/lib/tag';
@ -14,9 +14,12 @@ import Text from 'antd/lib/typography/Text';
import InputNumber from 'antd/lib/input-number';
import Button from 'antd/lib/button';
import notification from 'antd/lib/notification';
// eslint-disable-next-line import/no-extraneous-dependencies
import { OptionData, OptionGroupData } from 'rc-select/lib/interface';
import { Model, StringObject } from 'reducers/interfaces';
import { clamp } from 'utils/math';
import consts from 'consts';
interface Props {
@ -95,10 +98,12 @@ function DetectorRunner(props: Props): JSX.Element {
onChange={onChange}
style={{ width: '100%' }}
showSearch
filterOption={(input: string, option: React.ReactElement<OptionProps>) => {
const { children } = option.props;
if (typeof children === 'string') {
return children.toLowerCase().includes(input.toLowerCase());
filterOption={(input: string, option?: OptionData | OptionGroupData) => {
if (option) {
const { children } = option.props;
if (typeof children === 'string') {
return children.toLowerCase().includes(input.toLowerCase());
}
}
return false;
@ -106,7 +111,7 @@ function DetectorRunner(props: Props): JSX.Element {
>
{labels.map(
(label: string): JSX.Element => (
<Select.Option key={label}>{label}</Select.Option>
<Select.Option value={label} key={label}>{label}</Select.Option>
),
)}
</Select>
@ -138,7 +143,7 @@ function DetectorRunner(props: Props): JSX.Element {
>
{models.map(
(_model: Model): JSX.Element => (
<Select.Option key={_model.id}>{_model.name}</Select.Option>
<Select.Option value={_model.id} key={_model.id}>{_model.name}</Select.Option>
),
)}
</Select>
@ -176,13 +181,19 @@ function DetectorRunner(props: Props): JSX.Element {
<>
<Row type='flex' justify='start' align='middle'>
<Col span={10}>
{renderSelector(match.model || '', 'Model labels', modelLabels, (modelLabel: string) =>
updateMatch(modelLabel, null),
{renderSelector(
match.model || '',
'Model labels',
modelLabels,
(modelLabel: string) => updateMatch(modelLabel, null),
)}
</Col>
<Col span={10} offset={1}>
{renderSelector(match.task || '', 'Task labels', taskLabels, (taskLabel: string) =>
updateMatch(null, taskLabel),
{renderSelector(
match.task || '',
'Task labels',
taskLabels,
(taskLabel: string) => updateMatch(null, taskLabel),
)}
</Col>
<Col span={1} offset={1}>
@ -219,9 +230,9 @@ function DetectorRunner(props: Props): JSX.Element {
step={0.01}
max={1}
value={threshold}
onChange={(value: number | undefined) => {
if (typeof value === 'number') {
setThreshold(value);
onChange={(value: number | undefined | string) => {
if (typeof value !== 'undefined') {
setThreshold(clamp(+value, 0.01, 1));
}
}}
/>
@ -238,9 +249,9 @@ function DetectorRunner(props: Props): JSX.Element {
placeholder='Threshold'
min={1}
value={distance}
onChange={(value: number | undefined) => {
if (typeof value === 'number') {
setDistance(value);
onChange={(value: number | undefined | string) => {
if (typeof value !== 'undefined') {
setDistance(+value);
}
}}
/>
@ -258,12 +269,10 @@ function DetectorRunner(props: Props): JSX.Element {
runInference(
task,
model,
model.type === 'detector'
? { mapping, cleanup }
: {
threshold,
max_distance: distance,
},
model.type === 'detector' ? { mapping, cleanup } : {
threshold,
max_distance: distance,
},
);
}}
>

@ -26,7 +26,7 @@ export default function ProjectActionsMenuComponent(props: Props): JSX.Element {
dispatch(deleteProjectAsync(projectInstance));
},
okButtonProps: {
type: 'danger',
danger: true,
},
okText: 'Delete',
});

@ -3,8 +3,8 @@
// SPDX-License-Identifier: MIT
import React from 'react';
import Form, { FormComponentProps } from '@ant-design/compatible/lib/form/Form';
import { UserAddOutlined, MailOutlined, LockOutlined } from '@ant-design/icons';
import Form, { RuleRender, RuleObject } from 'antd/lib/form';
import Button from 'antd/lib/button';
import Input from 'antd/lib/input';
import Checkbox from 'antd/lib/checkbox';
@ -29,312 +29,240 @@ export interface RegisterData {
confirmations: UserConfirmation[];
}
type RegisterFormProps = {
interface Props {
fetching: boolean;
userAgreements: UserAgreement[];
onSubmit(registerData: RegisterData): void;
} & FormComponentProps;
}
class RegisterFormComponent extends React.PureComponent<RegisterFormProps> {
private validateConfirmation = (rule: any, value: any, callback: any): void => {
const { form } = this.props;
if (value && value !== form.getFieldValue('password1')) {
callback('Two passwords that you enter is inconsistent!');
} else {
callback();
}
};
function validateUsername(_: RuleObject, value: string): Promise<void> {
if (!patterns.validateUsernameLength.pattern.test(value)) {
return Promise.reject(new Error(patterns.validateUsernameLength.message));
}
if (!patterns.validateUsernameCharacters.pattern.test(value)) {
return Promise.reject(new Error(patterns.validateUsernameCharacters.message));
}
return Promise.resolve();
}
private validatePassword = (_: any, value: any, callback: any): void => {
const { form } = this.props;
export const validatePassword: RuleRender = (): RuleObject => ({
validator(_: RuleObject, value: string): Promise<void> {
if (!patterns.validatePasswordLength.pattern.test(value)) {
callback(patterns.validatePasswordLength.message);
return Promise.reject(new Error(patterns.validatePasswordLength.message));
}
if (!patterns.passwordContainsNumericCharacters.pattern.test(value)) {
callback(patterns.passwordContainsNumericCharacters.message);
return Promise.reject(new Error(patterns.passwordContainsNumericCharacters.message));
}
if (!patterns.passwordContainsUpperCaseCharacter.pattern.test(value)) {
callback(patterns.passwordContainsUpperCaseCharacter.message);
return Promise.reject(new Error(patterns.passwordContainsUpperCaseCharacter.message));
}
if (!patterns.passwordContainsLowerCaseCharacter.pattern.test(value)) {
callback(patterns.passwordContainsLowerCaseCharacter.message);
return Promise.reject(new Error(patterns.passwordContainsLowerCaseCharacter.message));
}
if (value) {
form.validateFields(['password2'], { force: true });
}
callback();
};
private validateUsername = (_: any, value: any, callback: any): void => {
if (!patterns.validateUsernameLength.pattern.test(value)) {
callback(patterns.validateUsernameLength.message);
}
return Promise.resolve();
},
});
if (!patterns.validateUsernameCharacters.pattern.test(value)) {
callback(patterns.validateUsernameCharacters.message);
export const validateConfirmation: ((firstFieldName: string) => RuleRender) = (
firstFieldName: string,
): RuleRender => ({ getFieldValue }): RuleObject => ({
validator(_: RuleObject, value: string): Promise<void> {
if (value && value !== getFieldValue(firstFieldName)) {
return Promise.reject(new Error('Two passwords that you enter is inconsistent!'));
}
callback();
};
private validateAgrement = (agreement: any, value: any, callback: any): void => {
const { userAgreements } = this.props;
let isValid = true;
for (const userAgreement of userAgreements) {
if (agreement.field === userAgreement.name && userAgreement.required && !value) {
isValid = false;
callback(`You must accept the ${userAgreement.displayText} to continue!`);
break;
}
return Promise.resolve();
},
});
const validateAgreement: ((userAgreements: UserAgreement[]) => RuleRender) = (
userAgreements: UserAgreement[],
): RuleRender => () => ({
validator(rule: any, value: boolean): Promise<void> {
const [, name] = rule.field.split(':');
const [agreement] = userAgreements
.filter((userAgreement: UserAgreement): boolean => userAgreement.name === name);
if (agreement.required && !value) {
return Promise.reject(new Error(`You must accept ${agreement.displayText} to continue!`));
}
if (isValid) {
callback();
}
};
private handleSubmit = (e: React.FormEvent): void => {
e.preventDefault();
const { form, onSubmit, userAgreements } = this.props;
form.validateFields((error, values): void => {
if (!error) {
const validatedFields = {
...values,
confirmations: [],
};
for (const userAgreement of userAgreements) {
validatedFields.confirmations.push({
name: userAgreement.name,
value: validatedFields[userAgreement.name],
});
delete validatedFields[userAgreement.name];
}
onSubmit(validatedFields);
}
});
};
private renderFirstNameField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('firstName', {
rules: [
{
required: true,
message: 'Please specify a first name',
pattern: patterns.validateName.pattern,
},
],
})(
<Input
prefix={<UserAddOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='First name'
/>,
)}
</Form.Item>
);
}
private renderLastNameField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('lastName', {
rules: [
{
required: true,
message: 'Please specify a last name',
pattern: patterns.validateName.pattern,
},
],
})(
<Input
prefix={<UserAddOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Last name'
/>,
)}
return Promise.resolve();
},
});
function RegisterFormComponent(props: Props): JSX.Element {
const { fetching, userAgreements, onSubmit } = props;
return (
<Form
onFinish={(values: Record<string, string | boolean>) => {
const agreements = Object.keys(values)
.filter((key: string):boolean => key.startsWith('agreement:'));
const confirmations = agreements
.map((key: string): UserConfirmation => ({ name: key.split(':')[1], value: (values[key] as boolean) }));
const rest = Object.entries(values)
.filter((entry: (string | boolean)[]) => !agreements.includes(entry[0] as string));
onSubmit({
...(Object.fromEntries(rest) as any as RegisterData),
confirmations,
});
}}
className='register-form'
>
<Row gutter={8}>
<Col span={12}>
<Form.Item
hasFeedback
name='firstName'
rules={[
{
required: true,
message: 'Please specify a first name',
pattern: patterns.validateName.pattern,
},
]}
>
<Input
prefix={<UserAddOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='First name'
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
hasFeedback
name='lastName'
rules={[
{
required: true,
message: 'Please specify a last name',
pattern: patterns.validateName.pattern,
},
]}
>
<Input
prefix={<UserAddOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Last name'
/>
</Form.Item>
</Col>
</Row>
<Form.Item
hasFeedback
name='username'
rules={[
{
required: true,
message: 'Please specify a username',
},
{
validator: validateUsername,
},
]}
>
<Input
prefix={<UserAddOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Username'
/>
</Form.Item>
);
}
private renderUsernameField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('username', {
rules: [
{
required: true,
message: 'Please specify a username',
},
{
validator: this.validateUsername,
},
],
})(
<Input
prefix={<UserAddOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Username'
/>,
)}
<Form.Item
hasFeedback
name='email'
rules={[
{
type: 'email',
message: 'The input is not valid E-mail!',
},
{
required: true,
message: 'Please specify an email address',
},
]}
>
<Input
autoComplete='email'
prefix={<MailOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Email address'
/>
</Form.Item>
);
}
private renderEmailField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('email', {
rules: [
{
type: 'email',
message: 'The input is not valid E-mail!',
},
{
required: true,
message: 'Please specify an email address',
},
],
})(
<Input
autoComplete='email'
prefix={<MailOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Email address'
/>,
)}
<Form.Item
hasFeedback
name='password1'
rules={[
{
required: true,
message: 'Please input your password!',
}, validatePassword,
]}
>
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Password'
/>
</Form.Item>
);
}
private renderPasswordField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('password1', {
rules: [
{
required: true,
message: 'Please input your password!',
},
{
validator: this.validatePassword,
},
],
})(
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Password'
/>,
)}
<Form.Item
hasFeedback
name='password2'
dependencies={['password1']}
rules={[
{
required: true,
message: 'Please confirm your password!',
}, validateConfirmation('password1'),
]}
>
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Confirm password'
/>
</Form.Item>
);
}
private renderPasswordConfirmationField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('password2', {
rules: [
{userAgreements.map((userAgreement: UserAgreement): JSX.Element => (
<Form.Item
name={`agreement:${userAgreement.name}`}
key={userAgreement.name}
initialValue={false}
valuePropName='checked'
rules={[
{
required: true,
message: 'Please confirm your password!',
},
{
validator: this.validateConfirmation,
},
],
})(
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Confirm password'
/>,
)}
</Form.Item>
);
}
private renderUserAgreements(): JSX.Element[] {
const { form, userAgreements } = this.props;
const getUserAgreementsElements = (): JSX.Element[] => {
const agreementsList: JSX.Element[] = [];
for (const userAgreement of userAgreements) {
agreementsList.push(
<Form.Item key={userAgreement.name}>
{form.getFieldDecorator(userAgreement.name, {
initialValue: false,
valuePropName: 'checked',
rules: [
{
required: true,
message: 'You must accept to continue!',
},
{
validator: this.validateAgrement,
},
],
})(
<Checkbox>
I read and accept the
<a rel='noopener noreferrer' target='_blank' href={userAgreement.url}>
{` ${userAgreement.displayText}`}
</a>
</Checkbox>,
)}
</Form.Item>,
);
}
return agreementsList;
};
return getUserAgreementsElements();
}
public render(): JSX.Element {
const { fetching } = this.props;
return (
<Form onSubmit={this.handleSubmit} className='login-form'>
<Row gutter={8}>
<Col span={12}>{this.renderFirstNameField()}</Col>
<Col span={12}>{this.renderLastNameField()}</Col>
</Row>
{this.renderUsernameField()}
{this.renderEmailField()}
{this.renderPasswordField()}
{this.renderPasswordConfirmationField()}
{this.renderUserAgreements()}
<Form.Item>
<Button
type='primary'
htmlType='submit'
className='register-form-button'
loading={fetching}
disabled={fetching}
>
Submit
</Button>
message: 'You must accept to continue!',
}, validateAgreement(userAgreements),
]}
>
<Checkbox>
I read and accept the
<a rel='noopener noreferrer' target='_blank' href={userAgreement.url}>
{` ${userAgreement.displayText}`}
</a>
</Checkbox>
</Form.Item>
</Form>
);
}
))}
<Form.Item>
<Button
type='primary'
htmlType='submit'
className='register-form-button'
loading={fetching}
disabled={fetching}
>
Submit
</Button>
</Form.Item>
</Form>
);
}
export default Form.create<RegisterFormProps>()(RegisterFormComponent);
export default React.memo(RegisterFormComponent);

@ -3,14 +3,13 @@
// SPDX-License-Identifier: MIT
import React from 'react';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import Form, { FormComponentProps } from '@ant-design/compatible/lib/form/Form';
import { useLocation } from 'react-router-dom';
import Form from 'antd/lib/form';
import Button from 'antd/lib/button';
import { LockOutlined } from '@ant-design/icons';
import Input from 'antd/lib/input';
import patterns from 'utils/validation-patterns';
import { validateConfirmation, validatePassword } from 'components/register-page/register-form';
export interface ResetPasswordConfirmData {
newPassword1: string;
@ -19,140 +18,73 @@ export interface ResetPasswordConfirmData {
token: string;
}
type ResetPasswordConfirmFormProps = {
interface Props {
fetching: boolean;
onSubmit(resetPasswordConfirmData: ResetPasswordConfirmData): void;
} & FormComponentProps & RouteComponentProps;
class ResetPasswordConfirmFormComponent extends React.PureComponent<ResetPasswordConfirmFormProps> {
private validateConfirmation = (_: any, value: string, callback: Function): void => {
const { form } = this.props;
if (value && value !== form.getFieldValue('newPassword1')) {
callback('Passwords do not match!');
} else {
callback();
}
};
private validatePassword = (_: any, value: string, callback: Function): void => {
const { form } = this.props;
if (!patterns.validatePasswordLength.pattern.test(value)) {
callback(patterns.validatePasswordLength.message);
}
if (!patterns.passwordContainsNumericCharacters.pattern.test(value)) {
callback(patterns.passwordContainsNumericCharacters.message);
}
if (!patterns.passwordContainsUpperCaseCharacter.pattern.test(value)) {
callback(patterns.passwordContainsUpperCaseCharacter.message);
}
if (!patterns.passwordContainsLowerCaseCharacter.pattern.test(value)) {
callback(patterns.passwordContainsLowerCaseCharacter.message);
}
if (value) {
form.validateFields(['newPassword2'], { force: true });
}
callback();
};
private handleSubmit = (e: React.FormEvent): void => {
e.preventDefault();
const { form, onSubmit, location } = this.props;
const params = new URLSearchParams(location.search);
const uid = params.get('uid');
const token = params.get('token');
form.validateFields((error, values): void => {
if (!error) {
const validatedFields = {
...values,
uid,
token,
};
onSubmit(validatedFields);
}
});
};
private renderNewPasswordField(): JSX.Element {
const { form } = this.props;
}
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('newPassword1', {
rules: [
{
required: true,
message: 'Please input new password!',
},
{
validator: this.validatePassword,
},
],
})(
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='New password'
/>,
)}
function ResetPasswordConfirmFormComponent({ fetching, onSubmit }: Props): JSX.Element {
const location = useLocation();
return (
<Form
onFinish={(values: Record<string, string>): void => {
const params = new URLSearchParams(location.search);
const uid = params.get('uid');
const token = params.get('token');
if (uid && token) {
onSubmit(({ ...values, uid, token } as ResetPasswordConfirmData));
}
}}
className='cvat-reset-password-confirm-form'
>
<Form.Item
hasFeedback
name='newPassword1'
rules={[
{
required: true,
message: 'Please input new password!',
}, validatePassword,
]}
>
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='New password'
/>
</Form.Item>
);
}
private renderNewPasswordConfirmationField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('newPassword2', {
rules: [
{
required: true,
message: 'Please confirm your new password!',
},
{
validator: this.validateConfirmation,
},
],
})(
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Confirm new password'
/>,
)}
<Form.Item
hasFeedback
name='newPassword2'
dependencies={['newPassword1']}
rules={[
{
required: true,
message: 'Please confirm your new password!',
}, validateConfirmation('newPassword1'),
]}
>
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Confirm new password'
/>
</Form.Item>
);
}
public render(): JSX.Element {
const { fetching } = this.props;
return (
<Form onSubmit={this.handleSubmit} className='cvat-reset-password-confirm-form'>
{this.renderNewPasswordField()}
{this.renderNewPasswordConfirmationField()}
<Form.Item>
<Button
type='primary'
htmlType='submit'
className='cvat-reset-password-confirm-form-button'
loading={fetching}
disabled={fetching}
>
Change password
</Button>
</Form.Item>
</Form>
);
}
<Form.Item>
<Button
type='primary'
htmlType='submit'
className='cvat-reset-password-confirm-form-button'
loading={fetching}
disabled={fetching}
>
Change password
</Button>
</Form.Item>
</Form>
);
}
export default withRouter(Form.create<ResetPasswordConfirmFormProps>()(ResetPasswordConfirmFormComponent));
export default React.memo(ResetPasswordConfirmFormComponent);

@ -3,7 +3,7 @@
// SPDX-License-Identifier: MIT
import React from 'react';
import Form, { FormComponentProps } from '@ant-design/compatible/lib/form/Form';
import Form from 'antd/lib/form';
import Button from 'antd/lib/button';
import { MailOutlined } from '@ant-design/icons';
import Input from 'antd/lib/input';
@ -12,70 +12,48 @@ export interface ResetPasswordData {
email: string;
}
type ResetPasswordFormProps = {
interface Props {
fetching: boolean;
onSubmit(resetPasswordData: ResetPasswordData): void;
} & FormComponentProps;
class ResetPasswordFormComponent extends React.PureComponent<ResetPasswordFormProps> {
private handleSubmit = (e: React.FormEvent): void => {
e.preventDefault();
const { form, onSubmit } = this.props;
form.validateFields((error, values): void => {
if (!error) {
onSubmit(values);
}
});
};
private renderEmailField(): JSX.Element {
const { form } = this.props;
}
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('email', {
rules: [
{
type: 'email',
message: 'The input is not valid E-mail!',
},
{
required: true,
message: 'Please specify an email address',
},
],
})(
<Input
autoComplete='email'
prefix={<MailOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Email address'
/>,
)}
function ResetPasswordFormComponent({ fetching, onSubmit }: Props): JSX.Element {
return (
<Form onFinish={onSubmit} className='cvat-reset-password-form'>
<Form.Item
hasFeedback
name='email'
rules={[
{
type: 'email',
message: 'The input is not valid E-mail!',
},
{
required: true,
message: 'Please specify an email address',
},
]}
>
<Input
autoComplete='email'
prefix={<MailOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Email address'
/>
</Form.Item>
);
}
public render(): JSX.Element {
const { fetching } = this.props;
return (
<Form onSubmit={this.handleSubmit} className='cvat-reset-password-form'>
{this.renderEmailField()}
<Form.Item>
<Button
type='primary'
loading={fetching}
disabled={fetching}
htmlType='submit'
className='cvat-reset-password-form-button'
>
Reset password
</Button>
</Form.Item>
</Form>
);
}
<Form.Item>
<Button
type='primary'
loading={fetching}
disabled={fetching}
htmlType='submit'
className='cvat-reset-password-form-button'
>
Reset password
</Button>
</Form.Item>
</Form>
);
}
export default Form.create<ResetPasswordFormProps>()(ResetPasswordFormComponent);
export default React.memo(ResetPasswordFormComponent);

@ -47,7 +47,9 @@ export default function AutomaticAnnotationProgress(props: Props): JSX.Element |
Modal.confirm({
title: 'You are going to cancel automatic annotation?',
content: 'Reached progress will be lost. Continue?',
okType: 'danger',
okButtonProps: {
danger: true,
},
onOk() {
cancelAutoAnnotation();
},

@ -10,7 +10,8 @@ import { CombinedState } from 'reducers/interfaces';
import { modelsActions } from 'actions/models-actions';
import { dumpAnnotationsAsync, loadAnnotationsAsync, exportDatasetAsync, deleteTaskAsync } from 'actions/tasks-actions';
import { ClickParam } from 'antd/lib/menu';
// eslint-disable-next-line import/no-extraneous-dependencies
import { MenuInfo } from 'rc-menu/lib/interface';
interface OwnProps {
taskInstance: any;
@ -89,7 +90,7 @@ function ActionsMenuContainer(props: OwnProps & StateToProps & DispatchToProps):
openRunModelWindow,
} = props;
function onClickMenu(params: ClickParam, file?: File): void {
function onClickMenu(params: MenuInfo, file?: File): void {
if (params.keyPath.length > 1) {
const [additionalKey, action] = params.keyPath;
if (action === Actions.DUMP_TASK_ANNO) {

@ -5,7 +5,8 @@
import React from 'react';
import { withRouter, RouteComponentProps } from 'react-router';
import { connect } from 'react-redux';
import { ClickParam } from 'antd/lib/menu/index';
// eslint-disable-next-line import/no-extraneous-dependencies
import { MenuInfo } from 'rc-menu/lib/interface';
import { CombinedState, TaskStatus } from 'reducers/interfaces';
import AnnotationMenuComponent, { Actions } from 'components/annotation-page/top-bar/annotation-menu';
@ -120,7 +121,7 @@ function AnnotationMenuContainer(props: Props): JSX.Element {
updateJob,
} = props;
const onClickMenu = (params: ClickParam, file?: File): void => {
const onClickMenu = (params: MenuInfo, file?: File): void => {
if (params.keyPath.length > 1) {
const [additionalKey, action] = params.keyPath;
if (action === Actions.DUMP_TASK_ANNO) {

@ -8,8 +8,7 @@ import { connect } from 'react-redux';
import { withRouter } from 'react-router';
import { RouteComponentProps } from 'react-router-dom';
import { GlobalHotKeys, ExtendedKeyMapOptions } from 'react-hotkeys';
import InputNumber from 'antd/lib/input-number';
import { SliderValue } from 'antd/lib/slider';
import Input from 'antd/lib/input';
import {
changeFrameAsync,
@ -154,15 +153,13 @@ interface State {
type Props = StateToProps & DispatchToProps & RouteComponentProps;
class AnnotationTopBarContainer extends React.PureComponent<Props, State> {
private inputFrameRef: React.RefObject<InputNumber>;
private inputFrameRef: React.RefObject<Input>;
private autoSaveInterval: number | undefined;
private unblock: any;
constructor(props: Props) {
super(props);
this.inputFrameRef = React.createRef<InputNumber>();
this.inputFrameRef = React.createRef<Input>();
this.state = {
prevButtonType: 'regular',
nextButtonType: 'regular',
@ -408,7 +405,7 @@ class AnnotationTopBarContainer extends React.PureComponent<Props, State> {
onSaveAnnotation(jobInstance);
};
private onChangePlayerSliderValue = (value: SliderValue): void => {
private onChangePlayerSliderValue = (value: number): void => {
const { playing, onSwitchPlay } = this.props;
if (playing) {
onSwitchPlay(false);

Loading…
Cancel
Save