diff --git a/src/assets/sass/fabric-icons-inline.scss b/src/assets/sass/fabric-icons-inline.scss index 0aeaf6719..a43eb388c 100644 --- a/src/assets/sass/fabric-icons-inline.scss +++ b/src/assets/sass/fabric-icons-inline.scss @@ -3,7 +3,7 @@ */ @font-face { font-family: 'FabricMDL2Icons'; - src: url('data:application/octet-stream;base64,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') format('truetype'); + src: url('data:application/octet-stream;base64,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') format('truetype'); } .ms-Icon { @@ -21,6 +21,8 @@ @mixin ms-Icon--AddField { content: "\E4C7"; } @mixin ms-Icon--AddTo { content: "\ECC8"; } @mixin ms-Icon--AlertSolid { content: "\F331"; } +@mixin ms-Icon--AutoEnhanceOff { content: "\E78E"; } +@mixin ms-Icon--AutoEnhanceOn { content: "\E78D"; } @mixin ms-Icon--AzureAPIManagement { content: "\F37F"; } @mixin ms-Icon--BookAnswers { content: "\F8A4"; } @mixin ms-Icon--BranchMerge { content: "\F295"; } @@ -95,6 +97,8 @@ .ms-Icon--AddField:before { @include ms-Icon--AddField } .ms-Icon--AddTo:before { @include ms-Icon--AddTo } .ms-Icon--AlertSolid:before { @include ms-Icon--AlertSolid } +.ms-Icon--AutoEnhanceOff:before { @include ms-Icon--AutoEnhanceOff } +.ms-Icon--AutoEnhanceOn:before { @include ms-Icon--AutoEnhanceOn } .ms-Icon--AzureAPIManagement:before { @include ms-Icon--AzureAPIManagement } .ms-Icon--BookAnswers:before { @include ms-Icon--BookAnswers } .ms-Icon--BranchMerge:before { @include ms-Icon--BranchMerge } @@ -161,5 +165,4 @@ .ms-Icon--View:before { @include ms-Icon--View } .ms-Icon--WarningSolid:before { @include ms-Icon--WarningSolid } .ms-Icon--ZoomIn:before { @include ms-Icon--ZoomIn } -.ms-Icon--ZoomOut:before { @include ms-Icon--ZoomOut } - +.ms-Icon--ZoomOut:before { @include ms-Icon--ZoomOut } \ No newline at end of file diff --git a/src/common/localization/en-us.ts b/src/common/localization/en-us.ts index c734b8f10..abeb5f549 100644 --- a/src/common/localization/en-us.ts +++ b/src/common/localization/en-us.ts @@ -269,6 +269,12 @@ export const english: IAppStrings = { notCompatibleTagType: "Tag type is not compatible with this feature. If you want to change type of this tag, please remove or reassign all labels which using this tag in your project.", checkboxPerTagLimit: "Cannot assign more than one checkbox per tag", notCompatibleWithDrawnRegionTag: "Drawn regions and ${otherCatagory} values cannot both be assigned to the same document's tag", + replaceAllExitingLabels:"Are you sure you want to replace selected tag's labels?", + replaceAllExitingLabelsTitle:"Replace tag's labels", + }, + preText:{ + autoLabel:"Auto-labeled: ", + revised:"Revised: ", }, toolbar: { add: "Add new tag", @@ -473,6 +479,10 @@ export const english: IAppStrings = { continuing to next asset.", }, }, + warningMessage: { + PreventLeavingWhileRunningOCR: "An Layout operation is currently in progress, are you sure you want to leave?", + PreventLeavingRunningAutoLabeling: "Auto-labeling is currently in progress, are you sure you want to leave?", + } }, profile: { settings: "Profile Settings", diff --git a/src/common/localization/es-cl.ts b/src/common/localization/es-cl.ts index 4d56bc94f..5bb4257d6 100644 --- a/src/common/localization/es-cl.ts +++ b/src/common/localization/es-cl.ts @@ -268,6 +268,12 @@ export const spanish: IAppStrings = { notCompatibleTagType: "El tipo de etiqueta no es compatible con esta función. Si desea cambiar el tipo de esta etiqueta, elimine o reasigne todas las etiquetas que utilizan esta etiqueta en su proyecto.", checkboxPerTagLimit: "No se puede asignar más de una casilla de verificación por etiqueta", notCompatibleWithDrawnRegionTag: "Los valores de drawnRegion y $ {otherCatagory} no pueden asignarse a la misma etiqueta del documento", + replaceAllExitingLabels:"¿Está seguro de que desea reemplazar las etiquetas de la etiqueta seleccionada?", + replaceAllExitingLabelsTitle:"Reemplazar las etiquetas de la etiqueta", + }, + preText:{ + autoLabel:"Auto-etiquetado: ", + revised:"Revisado: ", }, toolbar: { add: "Agregar nueva etiqueta", @@ -474,6 +480,10 @@ export const spanish: IAppStrings = { Por favor, etiquete todas las regiones antes de continuar con el siguiente activo.", }, }, + warningMessage: { + PreventLeavingWhileRunningOCR: "Una operación de diseño está actualmente en curso, ¿está seguro de que desea salir?", + PreventLeavingRunningAutoLabeling: "El etiquetado automático está actualmente en curso, ¿está seguro de que desea irse?", + } }, profile: { settings: "Configuración de Perfíl", diff --git a/src/common/mockFactory.ts b/src/common/mockFactory.ts index fa4fb8a8f..c6a6c0ef5 100644 --- a/src/common/mockFactory.ts +++ b/src/common/mockFactory.ts @@ -319,6 +319,7 @@ export default class MockFactory { createContainer: jest.fn(), deleteContainer: jest.fn(), getAssets: jest.fn(), + getAsset: jest.fn(), isFileExists: jest.fn(), }; } @@ -343,6 +344,9 @@ export default class MockFactory { getAssets(folderPath?: string, folderName?: string): Promise { throw new Error("Method not implemented."); }, + getAsset(folderPath: string, assetName: string): Promise { + throw new Error("Method not implemented."); + } }; } @@ -480,6 +484,7 @@ export default class MockFactory { deleteAsset: jest.fn(() => Promise.resolve()), loadAssets: jest.fn(() => Promise.resolve()), loadAssetMetadata: jest.fn(() => Promise.resolve()), + refreshAsset: jest.fn(() => Promise.resolve()), saveAssetMetadata: jest.fn(() => Promise.resolve()), updateProjectTag: jest.fn(() => Promise.resolve()), deleteProjectTag: jest.fn(() => Promise.resolve()), diff --git a/src/common/strings.ts b/src/common/strings.ts index d88b45538..23fc0be06 100644 --- a/src/common/strings.ts +++ b/src/common/strings.ts @@ -285,6 +285,12 @@ export interface IAppStrings { notCompatibleTagType: string, checkboxPerTagLimit: string, notCompatibleWithDrawnRegionTag: string, + replaceAllExitingLabels:string, + replaceAllExitingLabelsTitle:string, + }, + preText:{ + autoLabel:string, + revised:string, } }; connections: { @@ -466,6 +472,10 @@ export interface IAppStrings { title: string, description: string, }, + }, + warningMessage: { + PreventLeavingWhileRunningOCR: string, + PreventLeavingRunningAutoLabeling: string, } }; profile: { diff --git a/src/config/fabric-icons.json b/src/config/fabric-icons.json index fcabd9259..126b5c1cb 100644 --- a/src/config/fabric-icons.json +++ b/src/config/fabric-icons.json @@ -22,6 +22,14 @@ "name": "AlertSolid", "unicode": "F331" }, + { + "name": "AutoEnhanceOff", + "unicode": "E78E" + }, + { + "name": "AutoEnhanceOn", + "unicode": "E78D" + }, { "name": "AzureAPIManagement", "unicode": "F37F" diff --git a/src/electron/providers/storage/localFileSystem.ts b/src/electron/providers/storage/localFileSystem.ts index 55da5fe96..d96be0267 100644 --- a/src/electron/providers/storage/localFileSystem.ts +++ b/src/electron/providers/storage/localFileSystem.ts @@ -198,6 +198,35 @@ export default class LocalFileSystem implements IStorageProvider { return result; } + public async getAsset(folderPath: string, assetName: string): Promise{ + const files = await this.listFiles(path.normalize(folderPath)); + if(files.findIndex(f=>f===assetName)!==-1){ + const fileParts = assetName.split(/[\\\/]/); + const fileName = fileParts[fileParts.length - 1]; + const asset = await AssetService.createAssetFromFilePath(assetName, folderPath + "/" + fileName, true); + if (this.isSupportedAssetType(asset.type)) { + const labelFileName = decodeURIComponent(`${assetName}${constants.labelFileExtension}`); + const ocrFileName = decodeURIComponent(`${assetName}${constants.ocrFileExtension}`); + if (files.find((str) => str === labelFileName)) { + asset.state = AssetState.Tagged; + const json = await this.readText(labelFileName); + const labelData = JSON.parse(json) as ILabelData; + if (labelData) { + asset.labelingState = labelData.labelingState || AssetLabelingState.ManuallyLabeled; + } + } else if (files.find((str) => str === ocrFileName)) { + asset.state = AssetState.Visited; + } else { + asset.state = AssetState.NotVisited; + } + + return asset; + } + } + else{ + return null; + } + } /** * Gets a list of file system items matching the specified predicate within the folderPath * @param {string} folderPath diff --git a/src/providers/storage/assetProviderFactory.test.ts b/src/providers/storage/assetProviderFactory.test.ts index 69ef20cf2..4444d2964 100644 --- a/src/providers/storage/assetProviderFactory.test.ts +++ b/src/providers/storage/assetProviderFactory.test.ts @@ -31,4 +31,7 @@ class TestAssetProvider implements IAssetProvider { public getAssets(folderPath?: string): Promise { throw new Error("Method not implemented."); } + public getAsset(folderPath: string, assetName: string): Promise{ + throw new Error("Method not implemented."); + } } diff --git a/src/providers/storage/assetProviderFactory.ts b/src/providers/storage/assetProviderFactory.ts index f4a1b0a54..c15ee98c0 100644 --- a/src/providers/storage/assetProviderFactory.ts +++ b/src/providers/storage/assetProviderFactory.ts @@ -13,6 +13,7 @@ import getHostProcess, { HostProcessType } from "../../common/hostProcess"; export interface IAssetProvider { initialize?(): Promise; getAssets(folderPath?: string, folderName?: string): Promise; + getAsset(folderPath: string, assetName: string): Promise; } /** diff --git a/src/providers/storage/azureBlobStorage.ts b/src/providers/storage/azureBlobStorage.ts index d4a3960ad..43060279a 100644 --- a/src/providers/storage/azureBlobStorage.ts +++ b/src/providers/storage/azureBlobStorage.ts @@ -231,6 +231,36 @@ export class AzureBlobStorage implements IStorageProvider { return result; } + public async getAsset(folderPath: string, assetName: string): Promise{ + const files: string[] = await this.listFiles(folderPath); + if(files.findIndex(f=>f===assetName)!==-1){ + const url = this.getUrl(assetName); + const asset = await AssetService.createAssetFromFilePath(url, this.getFileName(url)); + if (this.isSupportedAssetType(asset.type)) { + const labelFileName = decodeURIComponent(`${asset.name}${constants.labelFileExtension}`); + const ocrFileName = decodeURIComponent(`${asset.name}${constants.ocrFileExtension}`); + + if (files.find((str) => str === labelFileName)) { + asset.state = AssetState.Tagged; + const labelFileName = decodeURIComponent(`${asset.name}${constants.labelFileExtension}`); + const json = await this.readText(labelFileName, true); + const labelData = JSON.parse(json) as ILabelData; + if (labelData) { + asset.labelingState = labelData.labelingState || AssetLabelingState.ManuallyLabeled; + } + } else if (files.find((str) => str === ocrFileName)) { + asset.state = AssetState.Visited; + } else { + asset.state = AssetState.NotVisited; + } + return asset; + } + } + else{ + return null; + } + } + /** * * @param url - URL for Azure Blob diff --git a/src/providers/storage/localFileSystemProxy.ts b/src/providers/storage/localFileSystemProxy.ts index 1378c84c6..00e812cbb 100644 --- a/src/providers/storage/localFileSystemProxy.ts +++ b/src/providers/storage/localFileSystemProxy.ts @@ -153,4 +153,8 @@ export class LocalFileSystemProxy implements IStorageProvider, IAssetProvider { public getAssets(folderName?: string): Promise { return IpcRendererProxy.send(`${PROXY_NAME}:getAssets`, [this.options.folderPath, folderName]); } + + public getAsset(folderPath: string, assetName: string): Promise{ + return IpcRendererProxy.send(`${PROXY_NAME}:getAsset`, [this.options.folderPath, `${folderPath}/${assetName}`]); + } } diff --git a/src/providers/storage/storageProviderFactory.test.ts b/src/providers/storage/storageProviderFactory.test.ts index b3c0b497a..b0932dc05 100644 --- a/src/providers/storage/storageProviderFactory.test.ts +++ b/src/providers/storage/storageProviderFactory.test.ts @@ -63,4 +63,7 @@ class TestStorageProvider implements IStorageProvider { public getAssets(folderPath?: string): Promise { throw new Error("Method not implemented."); } + public getAsset(folderPath: string, assetName: string): Promise { + throw new Error("Method not implemented."); + } } diff --git a/src/react/components/common/tagInput/tagInput.scss b/src/react/components/common/tagInput/tagInput.scss index 7e709061b..cfb2e55bf 100644 --- a/src/react/components/common/tagInput/tagInput.scss +++ b/src/react/components/common/tagInput/tagInput.scss @@ -36,19 +36,6 @@ &-container{ overflow-x: visible; overflow-y: auto; - padding: 0 0 0 100px; - margin: 0 0 0 -100px; - &::before{ - content: " "; - display: inline-block; - position: absolute; - top: 44px; - width: 50px; - height: calc(100% - 44px); - left: -55px; - margin-right: 4px; - background: linear-gradient(to right, #00000000 10%,#00000080 80%); - } }; } diff --git a/src/react/components/common/tagInput/tagInput.tsx b/src/react/components/common/tagInput/tagInput.tsx index c769527ca..451c87df4 100644 --- a/src/react/components/common/tagInput/tagInput.tsx +++ b/src/react/components/common/tagInput/tagInput.tsx @@ -16,9 +16,10 @@ import React, {KeyboardEvent} from "react"; import {toast} from "react-toastify"; import {constants} from "../../../../common/constants"; import {interpolate, strings} from "../../../../common/strings"; -import {getDarkTheme} from "../../../../common/themes"; +import {getDarkTheme, getPrimaryRedTheme} from "../../../../common/themes"; import {getNextColor} from "../../../../common/utils"; import {FeatureCategory, FieldFormat, FieldType, ILabel, IRegion, ITag} from "../../../../models/applicationState"; +import Confirm from "../../common/confirm/confirm"; import {AlignPortal} from "../align/alignPortal"; import {ColorPicker} from "../colorPicker"; import "../condensedList/condensedList.scss"; @@ -143,7 +144,7 @@ export class TagInput extends React.Component { private tagItemRefs: Map = new Map(); private headerRef = React.createRef(); private inputRef = React.createRef(); - + private replaceConfirmRef = React.createRef(); public componentDidUpdate(prevProps: ITagInputProps) { if (prevProps.tags !== this.props.tags) { let selectedTag = this.state.selectedTag; @@ -248,6 +249,13 @@ export class TagInput extends React.Component { : } + ); } @@ -321,7 +329,7 @@ export class TagInput extends React.Component { return; } - const tags = [ ...this.state.tags, tag ]; + const tags = [...this.state.tags, tag]; this.setState({ tags, }, () => this.props.onChange(tags)); @@ -517,12 +525,14 @@ export class TagInput extends React.Component { const labelAssigned = this.labelAssigned(labels, name); if (labelAssigned && ((category === FeatureCategory.DrawnRegion) !== isTagLabelTypeDrawnRegion)) { - if (isTagLabelTypeDrawnRegion) { - toast.warn(interpolate(strings.tags.warnings.notCompatibleWithDrawnRegionTag, {otherCatagory: category})); + if(category===FeatureCategory.Checkbox&&isTagLabelTypeDrawnRegion){ + toast.warn(interpolate(strings.tags.warnings.notCompatibleWithDrawnRegionTag, {otherCatagory: FeatureCategory.Checkbox})); + }else if (isTagLabelTypeDrawnRegion) { + this.replaceConfirmRef.current.open(tag, props); } else if (tagCategory === FeatureCategory.Checkbox) { toast.warn(interpolate(strings.tags.warnings.notCompatibleWithDrawnRegionTag, {otherCatagory: FeatureCategory.Checkbox})); } else { - toast.warn(interpolate(strings.tags.warnings.notCompatibleWithDrawnRegionTag, {otherCatagory: FeatureCategory.Text})); + this.replaceConfirmRef.current.open(tag, props); } return; } else if (tagCategory === category || category === FeatureCategory.DrawnRegion || @@ -531,6 +541,10 @@ export class TagInput extends React.Component { toast.warn(strings.tags.warnings.checkboxPerTagLimit); return; } + if(tagCategory===FeatureCategory.Checkbox&&category!==FeatureCategory.Checkbox){ + toast.warn(strings.tags.warnings.notCompatibleTagType); + return; + } onTagClick(tag); deselect = false; } else { @@ -543,6 +557,18 @@ export class TagInput extends React.Component { }); } } + private onReplaceConfirm = (tag: ITag, props: ITagClickProps) => { + const {onTagClick} = this.props; + const {selectedTag, tagOperation: oldTagOperation} = this.state; + const selected = selectedTag && isNameEqual(selectedTag.name, tag.name); + const tagOperation = selected ? oldTagOperation : TagOperationMode.None; + const deselect = selected && oldTagOperation === TagOperationMode.None; + onTagClick(tag); + this.setState({ + selectedTag: deselect ? null : tag, + tagOperation, + }); + } focusTag(tag: string) { const tagItemRef = this.tagItemRefs.get(tag)?.getTagNameRef(); if (tagItemRef) { diff --git a/src/react/components/common/tagInput/tagInputItem.tsx b/src/react/components/common/tagInput/tagInputItem.tsx index b35ab7930..bb178f565 100644 --- a/src/react/components/common/tagInput/tagInputItem.tsx +++ b/src/react/components/common/tagInput/tagInputItem.tsx @@ -218,7 +218,7 @@ export default class TagInputItem extends React.Component
- {(confidence||revised)&& + {(confidence||revised) &&
{confidence &&
@@ -236,7 +236,7 @@ export default class TagInputItem extends React.Component }
diff --git a/src/react/components/pages/editorPage/canvas.tsx b/src/react/components/pages/editorPage/canvas.tsx index 5b4047b23..23961e1e2 100644 --- a/src/react/components/pages/editorPage/canvas.tsx +++ b/src/react/components/pages/editorPage/canvas.tsx @@ -39,7 +39,7 @@ import { AutoLabelingStatus, PredictService } from "../../../../services/predict import { AssetService } from "../../../../services/assetService"; import { interpolate, strings } from "../../../../common/strings"; import { toast } from "react-toastify"; -import {BatchSizeModal} from "./batchSizeModal"; +import { BatchSizeModal } from "./batchSizeModal"; pdfjsLib.GlobalWorkerOptions.workerSrc = constants.pdfjsWorkerSrc(pdfjsLib.version); @@ -52,6 +52,7 @@ export interface ICanvasProps extends React.Props { project: IProject; lockedTags: string[]; hoveredLabel: ILabel; + isRunningOCRs?: boolean; children?: ReactElement; setTableToView?: (tableToView: object, tableToViewId: string) => void; closeTableView?: (state: string) => void; @@ -187,12 +188,12 @@ export default class Canvas extends React.Component public componentDidUpdate = async (prevProps: Readonly, prevState: Readonly) => { // Handles asset changing if (this.props.selectedAsset.asset.name !== prevProps.selectedAsset.asset.name || - this.props.selectedAsset.asset.isRunningOCR !== prevProps.selectedAsset.asset.isRunningOCR || - this.props.selectedAsset.asset.labelingState !== prevProps.selectedAsset.asset.labelingState + this.props.selectedAsset.asset.isRunningOCR !== prevProps.selectedAsset.asset.isRunningOCR ) { this.selectedRegionIds = []; this.imageMap.removeAllFeatures(); this.imageMap.resetAllLayerVisibility(); + this.setState({ currentAsset: this.props.selectedAsset, ocr: null, @@ -212,9 +213,14 @@ export default class Canvas extends React.Component } else if (this.isLabelDataChanged(this.props, prevProps) || (prevProps.project && this.needUpdateAssetRegionsFromTags(prevProps.project.tags, this.props.project.tags))) { - const newRegions = this.convertLabelDataToRegions(this.props.selectedAsset.labelData); - this.updateAssetRegions(newRegions); - this.redrawAllFeatures(); + this.setState({ + currentAsset: this.props.selectedAsset + }, () => { + const newRegions = this.convertLabelDataToRegions(this.props.selectedAsset.labelData); + this.updateAssetRegions(newRegions); + this.redrawAllFeatures(); + }); + } if (this.props.hoveredLabel !== prevProps.hoveredLabel) { @@ -339,7 +345,7 @@ export default class Canvas extends React.Component Page {this.state.currentPage} of {this.state.numPages}

} - {this.state.ocrStatus !== OcrStatus.done && + {(this.props.isRunningOCRs || this.state.ocrStatus !== OcrStatus.done) &&
@@ -368,13 +374,12 @@ export default class Canvas extends React.Component + />
); } private runOcrForAllDocuments = () => { - this.setState({ ocrStatus: OcrStatus.runningOCR }) this.props.runOcrForAllDocs(true); } @@ -387,7 +392,14 @@ export default class Canvas extends React.Component const result = await predictService.getPrediction(assetPath); const assetService = new AssetService(this.props.project); const assetMetadata = assetService.getAssetPredictMetadata(asset, result); - await this.props.onAssetMetadataChanged(assetMetadata); + if(assetMetadata) { + await this.props.onAssetMetadataChanged(assetMetadata); + } + } catch(err){ + this.setState({ + isError: true, + errorMessage: `${err.message}, code ${err.code}` + }); } finally { this.setAutoLabelingStatus(AutoLabelingStatus.done); @@ -425,6 +437,25 @@ export default class Canvas extends React.Component if (this.showMultiPageFieldWarningIfNecessary(tag, selectedRegions)) { return; } + let regions: IRegion[] = []; + if (selectedRegions.length > 0) { + const labelsData = this.state.currentAsset.labelData; + if (labelsData) { + const relatedLabel = labelsData.labels.find((label) => label.label === tag); + if (relatedLabel && + (((relatedLabel.labelType === null || relatedLabel.labelType === undefined) && (selectedRegions[0].category === FeatureCategory.DrawnRegion)) + || (relatedLabel.labelType !== null && relatedLabel.labelType !== undefined && relatedLabel.labelType !== selectedRegions[0].category))) { + regions = this.convertLabelToRegion(relatedLabel) + regions.forEach((region) => { + region.tags = []; + const regionIndex = this.state.currentAsset.regions.findIndex(r => r.id === region.id); + if (regionIndex !== -1) { + this.state.currentAsset.regions.splice(regionIndex, 1, region); + } + }); + } + } + } const transformer: (tags: string[], tag: string) => string[] = CanvasHelpers.setSingleTag; const inputTag = this.props.project.tags.filter((t) => t.name === tag); @@ -432,8 +463,7 @@ export default class Canvas extends React.Component for (const selectedRegion of selectedRegions) { selectedRegion.tags = transformer(selectedRegion.tags, tag); } - - this.updateRegions(selectedRegions); + this.updateRegions([...selectedRegions, ...regions]); this.selectedRegionIds = []; if (this.props.onSelectedRegionsChanged) { @@ -664,10 +694,13 @@ export default class Canvas extends React.Component delete currentAsset.asset.labelingState; } + const isLabelChanged = this.compareLabelChanged(_.get(currentAsset, "labelData.labels", []) as ILabel[], _.get(this.state.currentAsset, "labelData.labels", []) as ILabel[]); this.setState({ currentAsset, }, () => { - this.props.onAssetMetadataChanged(currentAsset); + if (isLabelChanged) { + this.props.onAssetMetadataChanged(currentAsset); + } }); } @@ -699,7 +732,7 @@ export default class Canvas extends React.Component } private onRegionDoubleClick = (id: string) => { if (this.props.onRegionDoubleClick) { - const region = this.state.currentAsset.regions.find(region=>region.id === id); + const region = this.state.currentAsset.regions.find(region => region.id === id); this.props.onRegionDoubleClick(region); } } @@ -1377,6 +1410,20 @@ export default class Canvas extends React.Component return regions; } + private convertLabelToRegion = (label: ILabel): IRegion[] => { + const regions = []; + if (label.value) { + label.value.forEach((formRegion) => { + if (formRegion.boundingBoxes) { + formRegion.boundingBoxes.forEach((boundingBox, boundingBoxIndex) => { + const text = this.getBoundingBoxTextFromRegion(formRegion, boundingBoxIndex); + regions.push(this.createRegion(boundingBox, text, label.label, formRegion.page, label?.labelType)); + }); + } + }); + } + return regions; + } private convertRegionsToLabelData = (regions: IRegion[], assetName: string) => { const labels = (this.props.selectedAsset @@ -1390,14 +1437,17 @@ export default class Canvas extends React.Component const intersectionResult = _.intersection(selectedRegions, regions); if (intersectionResult.length === 0) { const relatedLabels = labels.find(label => selectedRegions.find(sr => sr.tags.find(t => t === label.label))); - const originLabel = this.props.selectedAsset!.labelData!.labels.find(a => a.label === relatedLabels.label); - if (relatedLabels&&originLabel&&relatedLabels.confidence) { - delete relatedLabels.confidence; - relatedLabels.revised = true; - relatedLabels.originValue = [...originLabel.value]; + if (relatedLabels && relatedLabels.confidence) { + const originLabel = this.props.selectedAsset!.labelData?.labels?.find(a => a.label === relatedLabels.label); + if (originLabel) { + delete relatedLabels.confidence; + relatedLabels.revised = true; + relatedLabels.originValue = [...originLabel.value]; } } + } } + regions.sort(this.compareRegionOrder); regions.forEach((region) => { const labelType = this.getLabelType(region.category); const boundingBox = region.id.split(",").map(parseFloat); @@ -1409,12 +1459,15 @@ export default class Canvas extends React.Component region.tags.forEach((tag) => { const label = labels.find(label => label.label === tag); if (label) { - const originLabel = this.props.selectedAsset!.labelData!.labels.find(a=>a.label === tag); - if (label.confidence && region.changed) { + const originLabel = this.props.selectedAsset!.labelData?.labels?.find(a => a.label === tag); + if (originLabel && label.confidence && region.changed) { delete label.confidence; label.revised = true; label.originValue = [...originLabel.value]; } + if (originLabel && region.changed && label.labelType !== labelType) { + label.labelType = labelType; + } label.value.push(formRegion); } else { let newLabel; @@ -1680,7 +1733,10 @@ export default class Canvas extends React.Component private isLabelDataChanged = (newProps: ICanvasProps, prevProps: ICanvasProps): boolean => { const newLabels = _.get(newProps, "selectedAsset.labelData.labels", []) as ILabel[]; const prevLabels = _.get(prevProps, "selectedAsset.labelData.labels", []) as ILabel[]; + return this.compareLabelChanged(newLabels, prevLabels); + } + private compareLabelChanged(newLabels: ILabel[], prevLabels: ILabel[]): boolean { if (newLabels.length !== prevLabels.length) { return true; } else if (newLabels.length > 0) { @@ -1809,7 +1865,7 @@ export default class Canvas extends React.Component const order2 = this.getRegionOrder(r2.id); if (order1.page === order2.page) { - return order1.order > order2.order ? 1 : -1; + return order1.order >= order2.order ? 1 : -1; } else if (order1.page > order2.page) { return 1; } else { @@ -2182,7 +2238,7 @@ export default class Canvas extends React.Component private handleToggleDrawRegionMode = () => { if (!this.state.drawRegionMode && this.props.project.apiVersion !== APIVersionPatches.patch3) { - toast.warn(interpolate(strings.editorPage.canvas.canvasCommandBar.warings.drawRegionUnsupportedAPIVersion, { apiVersion: (this.props.project.apiVersion || constants.appVersion ) }), {autoClose: 7000}); + toast.warn(interpolate(strings.editorPage.canvas.canvasCommandBar.warings.drawRegionUnsupportedAPIVersion, { apiVersion: (this.props.project.apiVersion || constants.appVersion) }), { autoClose: 7000 }); } this.setState({ drawRegionMode: !this.state.drawRegionMode diff --git a/src/react/components/pages/editorPage/canvasCommandBar.tsx b/src/react/components/pages/editorPage/canvasCommandBar.tsx index c46f03cc5..ae5991de8 100644 --- a/src/react/components/pages/editorPage/canvasCommandBar.tsx +++ b/src/react/components/pages/editorPage/canvasCommandBar.tsx @@ -91,7 +91,7 @@ export const CanvasCommandBar: React.FunctionComponent = key: "Label", text: strings.editorPage.canvas.canvasCommandBar.items.layers.subMenuItems.labels, canCheck: true, - iconProps: { iconName: "LabelComposite" }, + iconProps: { iconName: "Label" }, isChecked: props.layers["label"], onClick: () => props.handleLayerChange("label"), }, diff --git a/src/react/components/pages/editorPage/editorPage.tsx b/src/react/components/pages/editorPage/editorPage.tsx index f404f9c6e..9b36f24f6 100644 --- a/src/react/components/pages/editorPage/editorPage.tsx +++ b/src/react/components/pages/editorPage/editorPage.tsx @@ -280,6 +280,7 @@ export default class EditorPage extends React.Component + message={strings.editorPage.warningMessage.PreventLeavingRunningAutoLabeling} />
); } @@ -562,15 +563,13 @@ export default class EditorPage extends React.Component a.id === asset.id); if (assetIndex > -1) { assets[assetIndex] = { @@ -731,6 +729,7 @@ export default class EditorPage extends React.Component { - this.setState((state) => ({ - assets: state.assets.map((asset) => { - if (asset.id === newState.id) { - const updatedAsset = { ...asset, isRunningOCR: newState.isRunningOCR || false }; - if (newState.assetState !== undefined && asset.state === AssetState.NotVisited) { - updatedAsset.state = newState.assetState; - } - if (newState.labelingState) { - updatedAsset.labelingState = newState.labelingState; - } - if (newState.isRunningAutoLabeling !== undefined) { - updatedAsset.isRunningAutoLabeling = newState.isRunningAutoLabeling; - } - return updatedAsset; - } else { - return asset; + const assets = this.state.assets.map((asset) => { + if (asset.id === newState.id) { + const updatedAsset = { ...asset, isRunningOCR: newState.isRunningOCR || false }; + if (newState.assetState !== undefined && asset.state === AssetState.NotVisited) { + updatedAsset.state = newState.assetState; + } + if (newState.labelingState) { + updatedAsset.labelingState = newState.labelingState; + } + if (newState.isRunningAutoLabeling !== undefined) { + updatedAsset.isRunningAutoLabeling = newState.isRunningAutoLabeling; } - }) + return updatedAsset; + } else { + return asset; + } + }); + this.setState((state) => ({ + assets }), () => { - const asset = this.state.assets.find((asset) => asset.id === newState.id); - if (this.state.selectedAsset && newState.id === this.state.selectedAsset.asset.id) { - if (asset) { - this.setState({ - selectedAsset: { ...this.state.selectedAsset, asset: { ...asset } }, - }); + if (this.state.selectedAsset?.asset?.id === newState.id) { + const asset = this.state.assets.find((asset) => asset.id === newState.id); + if (this.state.selectedAsset && newState.id === this.state.selectedAsset.asset.id) { + if (asset) { + this.setState({ + selectedAsset: { ...this.state.selectedAsset, asset: { ...asset } }, + }); + } } } + }); } @@ -871,7 +876,7 @@ export default class EditorPage extends React.Component{ + private onLabelDoubleClicked = (label: ILabel) => { this.canvas.current.focusOnLabel(label); } @@ -971,10 +976,10 @@ export default class EditorPage extends React.Component { + assetMetadata.labelData?.labels?.forEach((label) => { updatedAssetLabels[label.label] = true; }); - this.state.selectedAsset.labelData.labels.forEach((label) => { + this.state.selectedAsset.labelData?.labels?.forEach((label) => { currentAssetLabels[label.label] = true; }); Object.keys(currentAssetLabels).forEach((label) => { diff --git a/src/react/components/pages/editorPage/editorSideBar.tsx b/src/react/components/pages/editorPage/editorSideBar.tsx index aaba4dde0..e952f14da 100644 --- a/src/react/components/pages/editorPage/editorSideBar.tsx +++ b/src/react/components/pages/editorPage/editorSideBar.tsx @@ -139,12 +139,32 @@ export default class EditorSideBar extends React.Component { return state ? `badge-tagged-${AssetLabelingState[state]}` : ""; }; + const getBadgeTaggedIcon=(labelingState:AssetLabelingState)=>{ + switch(labelingState){ + case AssetLabelingState.AutoLabeled: + return( + + ); + case AssetLabelingState.AutoLabeledAndAdjusted: + return( + + ); + case AssetLabelingState.Trained: + return( + + ); + default: + return( + + ) + } + } switch (asset.state) { case AssetState.Tagged: return ( - + {getBadgeTaggedIcon(asset.labelingState)} ); case AssetState.Visited: diff --git a/src/react/components/pages/predict/predictPage.tsx b/src/react/components/pages/predict/predictPage.tsx index 7d4b04e2b..bca93b51d 100644 --- a/src/react/components/pages/predict/predictPage.tsx +++ b/src/react/components/pages/predict/predictPage.tsx @@ -718,6 +718,8 @@ export default class PredictPage extends React.Component; deleteAsset(project: IProject, assetMetadata: IAssetMetadata): Promise; loadAssets(project: IProject): Promise; + refreshAsset(project: IProject, assetName: string):Promise; loadAssetMetadata(project: IProject, asset: IAsset): Promise; saveAssetMetadata(project: IProject, assetMetadata: IAssetMetadata): Promise; updateProjectTag(project: IProject, oldTag: ITag, newTag: ITag): Promise; @@ -230,6 +231,14 @@ function areAssetsEqual(assets: IAsset[], projectAssets: { [index: string]: IAss return JSON.stringify(assetsMap) === JSON.stringify(projectAssets); } +export function refreshAsset(project: IProject, assetName:string):(dispatch:Dispatch) => Promise { + return async (dispatch:Dispatch) =>{ + const assetService = new AssetService(project); + const asset = await assetService.getAsset( assetName); + dispatch(refreshAssetAction( asset)); + } +} + /** * Load metadata from asset within project * @param project - Project from which to load asset metadata @@ -313,9 +322,9 @@ export function deleteProjectTag(project: IProject, tagName) const assetUpdates = await assetService.deleteTag(tagName); // Save updated assets - await assetUpdates.forEachAsync(async (assetMetadata) => { + for (const assetMetadata of assetUpdates) { await saveAssetMetadata(project, assetMetadata)(dispatch); - }); + } const currentProject = getState().currentProject; const updatedProject = { @@ -386,7 +395,9 @@ export interface ILoadProjectAssetsAction extends IPayloadAction { type: ActionTypes.DELETE_PROJECT_ASSET_SUCCESS; } - +export interface IRefreshAssetAction extends IPayloadAction { + type: ActionTypes.REFRESH_ASSET_SUCCESS; +} /** * Load asset metadata action type */ @@ -445,6 +456,9 @@ export const loadProjectAssetsAction = */ export const deleteProjectAssetAction = createPayloadAction(ActionTypes.DELETE_PROJECT_ASSET_SUCCESS); + +export const refreshAssetAction = +createPayloadAction(ActionTypes.REFRESH_ASSET_SUCCESS); /** * Instance of Load Asset Metadata action */ diff --git a/src/redux/reducers/currentProjectReducer.ts b/src/redux/reducers/currentProjectReducer.ts index 3bfce0225..632e2a37f 100644 --- a/src/redux/reducers/currentProjectReducer.ts +++ b/src/redux/reducers/currentProjectReducer.ts @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { ActionTypes } from "../actions/actionTypes"; -import { IProject, ITag } from "../../models/applicationState"; -import { AnyAction } from "../actions/actionCreators"; +import {ActionTypes} from "../actions/actionTypes"; +import {IProject, ITag} from "../../models/applicationState"; +import {AnyAction} from "../actions/actionCreators"; // tslint:disable-next-line:no-var-requires const tagColors = require("../../react/components/common/tagColors.json"); @@ -24,9 +24,9 @@ export const reducer = (state: IProject = null, action: AnyAction): IProject => case ActionTypes.CLOSE_PROJECT_SUCCESS: return null; case ActionTypes.LOAD_PROJECT_SUCCESS: - return { ...action.payload }; + return {...action.payload}; case ActionTypes.ADD_ASSET_TO_PROJECT_SUCCESS: - return { ...state, lastVisitedAssetId: action.payload.id }; + return {...state, lastVisitedAssetId: action.payload.id}; case ActionTypes.LOAD_ASSET_METADATA_SUCCESS: if (!state) { return state; @@ -36,11 +36,18 @@ export const reducer = (state: IProject = null, action: AnyAction): IProject => ...state, lastVisitedAssetId: action.payload.asset.id, }; + + case ActionTypes.REFRESH_ASSET_SUCCESS: + return { + ...state, + assets:{...state.assets, [action.payload.id]: action.payload}, + }; + break; case ActionTypes.DELETE_PROJECT_ASSET_SUCCESS: case ActionTypes.LOAD_PROJECT_ASSETS_SUCCESS: let assets = {}; action.payload.forEach((asset) => { - assets = { ...assets, [asset.id]: { ...asset } }; + assets = {...assets, [asset.id]: {...asset}}; }); return { @@ -52,8 +59,8 @@ export const reducer = (state: IProject = null, action: AnyAction): IProject => return state; } - const updatedAssets = { ...state.assets } || {}; - updatedAssets[action.payload.asset.id] = { ...action.payload.asset }; + const updatedAssets = {...state.assets} || {}; + updatedAssets[action.payload.asset.id] = {...action.payload.asset}; const assetTags = new Set(); action.payload.regions.forEach((region) => region.tags.forEach((tag) => assetTags.add(tag))); @@ -88,11 +95,11 @@ export const reducer = (state: IProject = null, action: AnyAction): IProject => case ActionTypes.UPDATE_PROJECT_TAG_SUCCESS: case ActionTypes.UPDATE_PROJECT_TAGS_FROM_FILES_SUCCESS: case ActionTypes.UPDATE_TAG_LABEL_COUNTS_SUCCESS: + case ActionTypes.DELETE_PROJECT_TAG_SUCCESS: return { ...state, tags: action.payload.tags, }; - case ActionTypes.SAVE_CONNECTION_SUCCESS: if (!state) { return state; @@ -101,7 +108,7 @@ export const reducer = (state: IProject = null, action: AnyAction): IProject => return { ...state, sourceConnection: state.sourceConnection.id === action.payload.id - ? { ...action.payload } + ? {...action.payload} : state.sourceConnection, }; default: diff --git a/src/registerIcons.ts b/src/registerIcons.ts index 9c91c905d..892596640 100644 --- a/src/registerIcons.ts +++ b/src/registerIcons.ts @@ -9,77 +9,79 @@ export function registerIcons() { fontFamily: "FabricMDL2Icons", }, icons: { - AlertSolid: "\uF331", - CheckboxComposite: "\uE73A", - LabelComposite: "\uE932", - Insights: "\uE3AF", - MachineLearning: "\uE3B8", - TagGroup: "\uE3F6", - ChevronDown: "\uE70D", - ChevronUp: "\uE70E", - Edit: "\uE70F", - Add: "\uE710", - Settings: "\uE713", - Link: "\uE71B", - Search: "\uE721", - CheckMark: "\uE73E", - Up: "\uE74A", - Down: "\uE74B", - Delete: "\uE74D", - Cloud: "\uE753", - ChevronLeft: "\uE76B", - ChevronRight: "\uE76C", - Home: "\uE80F", - View: "\uE890", - Download: "\uE896", - Help: "\uE897", - Rename: "\uE8AC", - Copy: "\uE8C8", - Tag: "\uE8EC", - Info: "\uE946", - AddTo: "\uECC8", - OpenFolderHorizontal: "\uED25", - SortUp: "\uEE68", - SortDown: "\uEE69", - DocumentManagement: "\uEFFC", - Relationship: "\uF003", - TextDocument: "\uF029", - BranchMerge: "\uF295", - Plug: "\uF300", - PlugConnected: "\uF302", - Hide3: "\uF6AC", - WarningSolid: "\uF736", - ZoomIn: "\uE8A3", - ZoomOut: "\uE71F", - TextField: "\uEDC3", - StatusCircleCheckmark: "\uF13E", - CircleRing: "\uEA3A", - Filter: "\uE71C", - ClearFilter: "\uEF8F", - Table: "\uED86", - MapLayers: "\uE81E", - BookAnswers: "\uF8A4", - Cancel: "\uE711", - Refresh: "\uE72C", - Documentation: "\uEC17", - More: "\uE712", - ReceiptProcessing: "\uE496", - KeyPhraseExtraction: "\uE395", - Share: "\uE72D", - ChromeRestore: "\uE923", - ChromeMinimize: "\uE921", - System: "\uE770", - SquareShape: "\uF1A6", - Merge: "\uE7D5", - AddField: "\uE4C7", - RectangleShape: "\uF1A9", - Rotate90CounterClockwise: "\uF80E", - Rotate90Clockwise: "\uF80D", - AzureAPIManagement: "\uF37F", - GroupedList: "\uEF74", - GroupList: "\uF168", - FieldChanged: "\uF2C3", - FieldNotChanged: "\uF2C4" + 'Add': '\uE710', + 'AddField': '\uE4C7', + 'AddTo': '\uECC8', + 'AlertSolid': '\uF331', + 'AutoEnhanceOff': '\uE78E', + 'AutoEnhanceOn': '\uE78D', + 'AzureAPIManagement': '\uF37F', + 'BookAnswers': '\uF8A4', + 'BranchMerge': '\uF295', + 'Cancel': '\uE711', + 'CheckboxComposite': '\uE73A', + 'CheckMark': '\uE73E', + 'ChevronDown': '\uE70D', + 'ChevronLeft': '\uE76B', + 'ChevronRight': '\uE76C', + 'ChevronUp': '\uE70E', + 'ChromeMinimize': '\uE921', + 'ChromeRestore': '\uE923', + 'CircleRing': '\uEA3A', + 'ClearFilter': '\uEF8F', + 'Cloud': '\uE753', + 'Copy': '\uE8C8', + 'Delete': '\uE74D', + 'Documentation': '\uEC17', + 'DocumentManagement': '\uEFFC', + 'Down': '\uE74B', + 'Download': '\uE896', + 'Edit': '\uE70F', + 'FieldChanged': "\uF2C3", + 'FieldNotChanged': "\uF2C4", + 'Filter': '\uE71C', + 'GroupedList': '\uEF74', + 'GroupList': '\uF168', + 'Help': '\uE897', + 'Hide3': '\uF6AC', + 'Home': '\uE80F', + 'Info': '\uE946', + 'Insights': '\uE3AF', + 'KeyPhraseExtraction': '\uE395', + 'Label': '\uE932', + 'Link': '\uE71B', + 'MachineLearning': '\uE3B8', + 'MapLayers': '\uE81E', + 'Merge': '\uE7D5', + 'More': '\uE712', + 'OpenFolderHorizontal': '\uED25', + 'Plug': '\uF300', + 'PlugConnected': '\uF302', + 'ReceiptProcessing': '\uE496', + 'RectangleShape': '\uF1A9', + 'Refresh': '\uE72C', + 'Relationship': '\uF003', + 'Rename': '\uE8AC', + 'Rotate90Clockwise': '\uF80D', + 'Rotate90CounterClockwise': '\uF80E', + 'Search': '\uE721', + 'Settings': '\uE713', + 'Share': '\uE72D', + 'SortDown': '\uEE69', + 'SortUp': '\uEE68', + 'SquareShape': '\uF1A6', + 'StatusCircleCheckmark': '\uF13E', + 'System': '\uE770', + 'Table': '\uED86', + 'Tag': '\uE8EC', + 'TagGroup': '\uE3F6', + 'TextDocument': '\uF029', + 'TextField': '\uEDC3', + 'Up': '\uE74A', + 'View': '\uE890', + 'WarningSolid': '\uF736', + 'ZoomIn': '\uE8A3', + 'ZoomOut': '\uE71F', }, }); } diff --git a/src/services/assetService.test.ts b/src/services/assetService.test.ts index 24939da59..78611fc26 100644 --- a/src/services/assetService.test.ts +++ b/src/services/assetService.test.ts @@ -83,6 +83,7 @@ describe("Asset Service", () => { beforeEach(() => { assetProviderMock = { getAssets: () => Promise.resolve(testAssets), + getAsset:(folderPath: string, assetName: string) => Promise.resolve(testAssets[0]), }; storageProviderMock = { diff --git a/src/services/assetService.ts b/src/services/assetService.ts index a76a4cba5..771a5061c 100644 --- a/src/services/assetService.ts +++ b/src/services/assetService.ts @@ -316,6 +316,10 @@ export class AssetService { return this.filterAssets(assets, folderPath); } + public async getAsset(assetName: string): Promise { + return await this.assetProvider.getAsset(this.project.folderPath, assetName); + } + private filterAssets = (assets, folderPath) => { if (this.project.sourceConnection.providerType === "localFileSystemProxy") { return assets.map((asset) => { @@ -541,6 +545,17 @@ export class AssetService { assetMetadata.regions = assetMetadata.regions.filter((region) => region.tags.length > 0); assetMetadata.asset.state = _.get(assetMetadata, "labelData.labels.length") ? AssetState.Tagged : AssetState.Visited; + if(assetMetadata.asset.labelingState===AssetLabelingState.Trained){ + assetMetadata.asset.labelingState=AssetLabelingState.ManuallyLabeled; + if(assetMetadata.labelData){ + assetMetadata.labelData.labelingState=AssetLabelingState.ManuallyLabeled; + } + }else if(assetMetadata.asset.labelingState===AssetLabelingState.AutoLabeled){ + assetMetadata.asset.labelingState=AssetLabelingState.AutoLabeledAndAdjusted; + if(assetMetadata.labelData){ + assetMetadata.labelData.labelingState=AssetLabelingState.AutoLabeledAndAdjusted; + } + } return true; } diff --git a/src/services/ocrService.ts b/src/services/ocrService.ts index e62ff0d32..eadca1c1c 100644 --- a/src/services/ocrService.ts +++ b/src/services/ocrService.ts @@ -9,9 +9,9 @@ import ServiceHelper from "./serviceHelper"; import { strings } from "../common/strings"; export enum OcrStatus { - loadingFromAzureBlob, - runningOCR, - done, + loadingFromAzureBlob="loadingFromAzureBlob", + runningOCR="runningOCR", + done="done", } /** @@ -110,8 +110,8 @@ export class OCRService { return this.poll( () => ServiceHelper.getWithAutoRetry(operationLocation, { headers }, this.project.apiKey as string), 120000, - 1500).then((data) => { - this.save(ocrFileName, data); + 1500).then(async (data) => { + await this.save(ocrFileName, data); return data; }); } catch (error) {