// Copyright (C) 2020 Intel Corporation // // SPDX-License-Identifier: MIT import React from 'react'; import { Row, Col, Tag, Icon, Modal, Button, notification, } from 'antd'; import Text from 'antd/lib/typography/Text'; import Title from 'antd/lib/typography/Title'; import moment from 'moment'; import getCore from 'cvat-core'; import patterns from 'utils/validation-patterns'; import { getReposData, syncRepos } from 'utils/git-utils'; import UserSelector from './user-selector'; import LabelsEditorComponent from '../labels-editor/labels-editor'; const core = getCore(); interface Props { previewImage: string; taskInstance: any; installedGit: boolean; // change to git repos url registeredUsers: any[]; onTaskUpdate: (taskInstance: any) => void; } interface State { name: string; bugTracker: string; repository: string; repositoryStatus: string; } export default class DetailsComponent extends React.PureComponent { private mounted: boolean; private previewImageElement: HTMLImageElement; private previewWrapperRef: React.RefObject; constructor(props: Props) { super(props); const { taskInstance } = props; this.mounted = false; this.previewImageElement = new Image(); this.previewWrapperRef = React.createRef(); this.state = { name: taskInstance.name, bugTracker: taskInstance.bugTracker, repository: '', repositoryStatus: '', }; } public componentDidMount(): void { const { taskInstance, previewImage } = this.props; const { previewImageElement, previewWrapperRef } = this; this.mounted = true; previewImageElement.onload = () => { const { height, width } = previewImageElement; if (width > height) { previewImageElement.style.width = '100%'; } else { previewImageElement.style.height = '100%'; } }; previewImageElement.src = previewImage; previewImageElement.alt = 'Preview'; if (previewWrapperRef.current) { previewWrapperRef.current.appendChild(previewImageElement); } getReposData(taskInstance.id) .then((data): void => { if (data !== null && this.mounted) { if (data.status.error) { notification.error({ message: 'Could not receive repository status', description: data.status.error, }); } else { this.setState({ repositoryStatus: data.status.value, }); } this.setState({ repository: data.url, }); } }).catch((error): void => { if (this.mounted) { notification.error({ message: 'Could not receive repository status', description: error.toString(), }); } }); } public componentDidUpdate(prevProps: Props): void { const { taskInstance } = this.props; if (prevProps !== this.props) { this.setState({ name: taskInstance.name, bugTracker: taskInstance.bugTracker, }); } } public componentWillUnmount(): void { this.mounted = false; } private renderTaskName(): JSX.Element { const { name } = this.state; const { taskInstance, onTaskUpdate, } = this.props; return ( { this.setState({ name: value, }); taskInstance.name = value; onTaskUpdate(taskInstance); }, }} className='cvat-text-color' > {name} ); } private renderPreview(): JSX.Element { const { previewWrapperRef } = this; // Add image on mount after get its width and height to fit it into wrapper return (
); } private renderParameters(): JSX.Element { const { taskInstance } = this.props; const { overlap } = taskInstance; const { segmentSize } = taskInstance; const { imageQuality } = taskInstance; const zOrder = taskInstance.zOrder.toString(); return ( <> Overlap size
{overlap} Segment size
{segmentSize}
Image quality
{imageQuality} Z-order
{zOrder}
); } private renderUsers(): JSX.Element { const { taskInstance, registeredUsers, onTaskUpdate, } = this.props; const owner = taskInstance.owner ? taskInstance.owner.username : null; const assignee = taskInstance.assignee ? taskInstance.assignee.username : null; const created = moment(taskInstance.createdDate).format('MMMM Do YYYY'); const assigneeSelect = ( { let [userInstance] = registeredUsers .filter((user: any) => user.username === value); if (userInstance === undefined) { userInstance = null; } taskInstance.assignee = userInstance; onTaskUpdate(taskInstance); } } /> ); return ( { owner && ( {`Created by ${owner} on ${created}`} )} Assigned to { assigneeSelect } ); } private renderDatasetRepository(): JSX.Element | boolean { const { taskInstance } = this.props; const { repository, repositoryStatus, } = this.state; return ( !!repository && ( Dataset Repository
{repository} {repositoryStatus === 'sync' && ( Synchronized )} {repositoryStatus === 'merged' && ( Merged )} {repositoryStatus === 'syncing' && ( Syncing )} {repositoryStatus === '!sync' && ( { this.setState({ repositoryStatus: 'syncing', }); syncRepos(taskInstance.id).then((): void => { if (this.mounted) { this.setState({ repositoryStatus: 'sync', }); } }).catch((): void => { if (this.mounted) { this.setState({ repositoryStatus: '!sync', }); } }); }} > Synchronize )}
) ); } private renderBugTracker(): JSX.Element { const { taskInstance, onTaskUpdate, } = this.props; const { bugTracker } = this.state; let shown = false; const onChangeValue = (value: string): void => { if (value && !patterns.validateURL.pattern.test(value)) { if (!shown) { Modal.error({ title: `Could not update the task ${taskInstance.id}`, content: 'Issue tracker is expected to be URL', onOk: (() => { shown = false; }), }); shown = true; } } else { this.setState({ bugTracker: value, }); taskInstance.bugTracker = value; onTaskUpdate(taskInstance); } }; if (bugTracker) { return ( Issue Tracker
{bugTracker}
); } return ( Issue Tracker
Not specified
); } private renderLabelsEditor(): JSX.Element { const { taskInstance, onTaskUpdate, } = this.props; return ( label.toJSON(), )} onSubmit={(labels: any[]): void => { taskInstance.labels = labels .map((labelData): any => new core.classes.Label(labelData)); onTaskUpdate(taskInstance); }} /> ); } public render(): JSX.Element { return (
{ this.renderTaskName() } { this.renderPreview() } { this.renderParameters() } { this.renderUsers() } { this.renderBugTracker() } { this.renderDatasetRepository() } { this.renderLabelsEditor() }
); } }