From 9f9638289f605b66e86e165bb783af677a3cb27f Mon Sep 17 00:00:00 2001 From: SkalskiP Date: Thu, 20 Oct 2022 15:13:28 +0200 Subject: [PATCH] initial version of improved user noification --- src/logic/import/yolo/YOLOErrors.ts | 16 ++++----- src/logic/import/yolo/YOLOUtils.ts | 35 +++++++++++-------- .../ImportLabelPopup/ImportLabelPopup.tsx | 13 +++++-- .../LoadLabelNamesPopup.tsx | 20 +++++++++-- .../LoadYOLOv5ModelPopup.tsx | 8 +++-- 5 files changed, 63 insertions(+), 29 deletions(-) diff --git a/src/logic/import/yolo/YOLOErrors.ts b/src/logic/import/yolo/YOLOErrors.ts index e9a541e3..8475ebc0 100644 --- a/src/logic/import/yolo/YOLOErrors.ts +++ b/src/logic/import/yolo/YOLOErrors.ts @@ -1,34 +1,34 @@ export class YOLOAnnotationsLoadingError extends Error { constructor(message) { super(message); - this.name = "YOLOAnnotationsLoadingError"; + this.name = 'YOLOAnnotationsLoadingError'; } } export class YOLOLabelsReadingError extends YOLOAnnotationsLoadingError { constructor() { - super("Unexpected error occurred during reading label names from labels.txt file"); - this.name = "YOLOLabelsLoadingError"; + super('Unexpected error occurred during reading label names from labels.txt file'); + this.name = 'YOLOLabelsLoadingError'; } } export class NoLabelNamesFileProvidedError extends YOLOAnnotationsLoadingError { constructor() { - super("For YOLO labels to be loaded correctly, labels.txt file is required"); - this.name = "NoLabelNamesFileProvidedError"; + super('For YOLO labels to be loaded correctly, labels.txt file is required'); + this.name = 'NoLabelNamesFileProvidedError'; } } export class LabelNamesNotUniqueError extends YOLOAnnotationsLoadingError { constructor() { - super("Label names listed in labels.txt file should be unique"); - this.name = "LabelNamesNotUniqueError"; + super('Label names listed in labels.txt file should be unique'); + this.name = 'LabelNamesNotUniqueError'; } } export class AnnotationsParsingError extends YOLOAnnotationsLoadingError { constructor(imageName: string) { super(`Unexpected error occurred during parsing of ${imageName} annotations file`); - this.name = "AnnotationsParsingError"; + this.name = 'AnnotationsParsingError'; } } \ No newline at end of file diff --git a/src/logic/import/yolo/YOLOUtils.ts b/src/logic/import/yolo/YOLOUtils.ts index 3e28794c..7d540f37 100644 --- a/src/logic/import/yolo/YOLOUtils.ts +++ b/src/logic/import/yolo/YOLOUtils.ts @@ -1,15 +1,15 @@ -import {LabelName, LabelRect} from "../../../store/labels/types"; -import {LabelUtil} from "../../../utils/LabelUtil"; -import {AnnotationsParsingError, LabelNamesNotUniqueError} from "./YOLOErrors"; -import {ISize} from "../../../interfaces/ISize"; -import {uniq} from "lodash"; +import {LabelName, LabelRect} from '../../../store/labels/types'; +import {LabelUtil} from '../../../utils/LabelUtil'; +import {AnnotationsParsingError, LabelNamesNotUniqueError} from './YOLOErrors'; +import {ISize} from '../../../interfaces/ISize'; +import {uniq} from 'lodash'; export class YOLOUtils { public static parseLabelsNamesFromString(content: string): LabelName[] { const labelNames: string[] = content .split(/[\r\n]/) .filter(Boolean) - .map((name: string) => name.replace(/\s/g, "")) + .map((name: string) => name.replace(/\s/g, '')) if (uniq(labelNames).length !== labelNames.length) { throw new LabelNamesNotUniqueError() @@ -19,14 +19,21 @@ export class YOLOUtils { .map((name: string) => LabelUtil.createLabelName(name)) } - public static loadLabelsList(fileData: File, onSuccess: (labels: LabelName[]) => any, onFailure: () => any) { + public static loadLabelsList( + fileData: File, + onSuccess: (labels: LabelName[]) => void, + onFailure: (error: Error) => void + ) { const reader = new FileReader(); - reader.onloadend = function (evt: any) { - const content: string = evt.target.result; - const labelNames = YOLOUtils.parseLabelsNamesFromString(content); - onSuccess(labelNames); + reader.onloadend = (evt: ProgressEvent) => { + try { + const content: string = evt.target.result as string; + const labelNames = YOLOUtils.parseLabelsNamesFromString(content); + onSuccess(labelNames); + } catch (error) { + onFailure(error as Error) + } }; - reader.onerror = () => onFailure(); reader.readAsText(fileData); } @@ -50,7 +57,7 @@ export class YOLOUtils { imageSize: ISize, imageName: string ): LabelRect { - const components = rawAnnotation.split(" "); + const components = rawAnnotation.split(' '); if (!YOLOUtils.validateYOLOAnnotationComponents(components, labelNames.length)) { throw new AnnotationsParsingError(imageName); } @@ -88,4 +95,4 @@ export class YOLOUtils { validateCoordinateValue(components[4]) ].every(Boolean) } -} \ No newline at end of file +} diff --git a/src/views/PopupView/ImportLabelPopup/ImportLabelPopup.tsx b/src/views/PopupView/ImportLabelPopup/ImportLabelPopup.tsx index 4fe10ee1..8fb22309 100644 --- a/src/views/PopupView/ImportLabelPopup/ImportLabelPopup.tsx +++ b/src/views/PopupView/ImportLabelPopup/ImportLabelPopup.tsx @@ -18,6 +18,7 @@ import { NotificationUtil } from '../../../utils/NotificationUtil'; import { NotificationsDataMap } from '../../../data/info/NotificationsData'; import { DocumentParsingError } from '../../../logic/import/voc/VOCImporter'; import { Notification } from '../../../data/enums/Notification'; +import {LabelNamesNotUniqueError} from '../../../logic/import/yolo/YOLOErrors'; interface IProps { activeLabelType: LabelType, @@ -44,7 +45,15 @@ const ImportLabelPopup: React.FC = ( const [loadedImageData, setLoadedImageData] = useState([]); const [annotationsLoadedError, setAnnotationsLoadedError] = useState(null); - + const resolveNotification = (error: Error): Notification => { + if (error instanceof DocumentParsingError) { + return Notification.ANNOTATION_FILE_PARSE_ERROR + } + if (error instanceof LabelNamesNotUniqueError) { + return Notification.NON_UNIQUE_LABEL_NAMES_ERROR + } + return Notification.ANNOTATION_IMPORT_ASSERTION_ERROR + } const onLabelTypeChange = (type: LabelType) => { setLabelType(type); @@ -64,7 +73,7 @@ const ImportLabelPopup: React.FC = ( setLoadedLabelNames([]); setLoadedImageData([]); setAnnotationsLoadedError(error); - const notification = error instanceof DocumentParsingError ? Notification.ANNOTATION_FILE_PARSE_ERROR : Notification.ANNOTATION_IMPORT_ASSERTION_ERROR; + const notification = resolveNotification(error) submitNewNotification(NotificationUtil.createErrorNotification(NotificationsDataMap[notification])); }; diff --git a/src/views/PopupView/LoadLabelNamesPopup/LoadLabelNamesPopup.tsx b/src/views/PopupView/LoadLabelNamesPopup/LoadLabelNamesPopup.tsx index 855e8cb5..7cedbe8d 100644 --- a/src/views/PopupView/LoadLabelNamesPopup/LoadLabelNamesPopup.tsx +++ b/src/views/PopupView/LoadLabelNamesPopup/LoadLabelNamesPopup.tsx @@ -9,13 +9,22 @@ import { updateActivePopupType } from '../../../store/general/actionCreators'; import { useDropzone } from 'react-dropzone'; import { LabelName } from '../../../store/labels/types'; import { YOLOUtils } from '../../../logic/import/yolo/YOLOUtils'; +import {LabelNamesNotUniqueError} from '../../../logic/import/yolo/YOLOErrors'; +import {NotificationUtil} from '../../../utils/NotificationUtil'; +import {NotificationsDataMap} from '../../../data/info/NotificationsData'; +import {Notification} from '../../../data/enums/Notification'; +import {submitNewNotification} from '../../../store/notifications/actionCreators'; +import {INotification} from '../../../store/notifications/types'; interface IProps { updateActivePopupTypeAction: (activePopupType: PopupWindowType) => any; updateLabelNamesAction: (labels: LabelName[]) => any; + submitNewNotificationAction: (notification: INotification) => any; } -const LoadLabelNamesPopup: React.FC = ({ updateActivePopupTypeAction, updateLabelNamesAction }) => { +const LoadLabelNamesPopup: React.FC = ( + { updateActivePopupTypeAction, updateLabelNamesAction, submitNewNotificationAction } +) => { const [labelsList, setLabelsList] = useState([]); const [invalidFileLoadedStatus, setInvalidFileLoadedStatus] = useState(false); @@ -24,8 +33,12 @@ const LoadLabelNamesPopup: React.FC = ({ updateActivePopupTypeAction, up setInvalidFileLoadedStatus(false); }; - const onFailure = () => { + const onFailure = (error: Error) => { setInvalidFileLoadedStatus(true); + if (error instanceof LabelNamesNotUniqueError) { + submitNewNotificationAction(NotificationUtil + .createErrorNotification(NotificationsDataMap[Notification.NON_UNIQUE_LABEL_NAMES_ERROR])); + } }; const { acceptedFiles, getRootProps, getInputProps } = useDropzone({ @@ -122,7 +135,8 @@ const LoadLabelNamesPopup: React.FC = ({ updateActivePopupTypeAction, up const mapDispatchToProps = { updateActivePopupTypeAction: updateActivePopupType, - updateLabelNamesAction: updateLabelNames + updateLabelNamesAction: updateLabelNames, + submitNewNotificationAction: submitNewNotification }; const mapStateToProps = (state: AppState) => ({}); diff --git a/src/views/PopupView/LoadYOLOv5ModelPopup/LoadYOLOv5ModelPopup.tsx b/src/views/PopupView/LoadYOLOv5ModelPopup/LoadYOLOv5ModelPopup.tsx index 63f7556c..34ebd7c1 100644 --- a/src/views/PopupView/LoadYOLOv5ModelPopup/LoadYOLOv5ModelPopup.tsx +++ b/src/views/PopupView/LoadYOLOv5ModelPopup/LoadYOLOv5ModelPopup.tsx @@ -25,6 +25,7 @@ import {ClipLoader} from 'react-spinners'; import {useDropzone} from 'react-dropzone'; import {YOLOUtils} from '../../../logic/import/yolo/YOLOUtils'; import {LabelName} from '../../../store/labels/types'; +import {LabelNamesNotUniqueError} from '../../../logic/import/yolo/YOLOErrors'; enum ModelSource { DOWNLOAD = 'DOWNLOAD', @@ -87,8 +88,11 @@ const LoadYOLOv5ModelPopup: React.FC = ({ updateActivePopupTypeAction, s setClassNames(labels) setModeFiles([...jsonFiles, ...binFiles]) } - const onFailure = () => { - return null; + const onFailure = (error) => { + if (error instanceof LabelNamesNotUniqueError) { + submitNewNotificationAction(NotificationUtil + .createErrorNotification(NotificationsDataMap[Notification.NON_UNIQUE_LABEL_NAMES_ERROR])); + } } YOLOUtils.loadLabelsList(txtFiles[0], onSuccess, onFailure) }