fix: Catch error while tfrecord image not loaded (#701)
Fixes bug where tfrecords show error loading image Resolves AB#17680
Esse commit está contido em:
@@ -133,3 +133,7 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.Toastify .vott-toast-container {
|
||||
top: 3em;
|
||||
}
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ export default class App extends React.Component<IAppProps> {
|
||||
<StatusBar>
|
||||
<StatusBarMetrics project={this.props.currentProject} />
|
||||
</StatusBar>
|
||||
<ToastContainer />
|
||||
<ToastContainer className="vott-toast-container" />
|
||||
</div>
|
||||
</Router >
|
||||
</KeyboardManager>
|
||||
|
||||
@@ -123,6 +123,20 @@ export default class MockFactory {
|
||||
},
|
||||
};
|
||||
break;
|
||||
case AssetType.TFRecord:
|
||||
testAsset = {
|
||||
id: `tfrecordasset-${name}`,
|
||||
format: "tfrecord",
|
||||
name: `tfrecordasset-${name}.tfrecord`,
|
||||
path: `${path}.tfrecord`,
|
||||
state: assetState,
|
||||
type: assetType,
|
||||
size: {
|
||||
width: 800,
|
||||
height: 600,
|
||||
},
|
||||
};
|
||||
break;
|
||||
default:
|
||||
testAsset = {
|
||||
id: `asset-${name}`,
|
||||
|
||||
@@ -4,7 +4,8 @@ import { AssetPreview, IAssetPreviewProps, IAssetPreviewState } from "./assetPre
|
||||
import MockFactory from "../../../../common/mockFactory";
|
||||
import { ImageAsset } from "./imageAsset";
|
||||
import { VideoAsset } from "./videoAsset";
|
||||
import { AssetType } from "../../../../models/applicationState";
|
||||
import { AssetType, AssetState } from "../../../../models/applicationState";
|
||||
import { TFRecordAsset } from "./tfrecordAsset";
|
||||
|
||||
describe("Asset Preview Component", () => {
|
||||
let wrapper: ReactWrapper<IAssetPreviewProps, IAssetPreviewState> = null;
|
||||
@@ -48,6 +49,19 @@ describe("Asset Preview Component", () => {
|
||||
expect(wrapper.find(VideoAsset).exists()).toBe(true);
|
||||
});
|
||||
|
||||
it("renders a tfrecord asset when asset type is tfrecord", () => {
|
||||
const props: IAssetPreviewProps = {
|
||||
...defaultProps,
|
||||
asset: MockFactory.createTestAsset("test-record-asset",
|
||||
AssetState.Visited,
|
||||
dataUri,
|
||||
AssetType.TFRecord),
|
||||
};
|
||||
wrapper = createComponent(props);
|
||||
expect(wrapper.find(TFRecordAsset).exists()).toBe(true);
|
||||
expect(wrapper.instance().state).toMatchObject({hasError: false});
|
||||
});
|
||||
|
||||
it("renders loading indicator if asset isn't fully loaded", () => {
|
||||
wrapper = createComponent();
|
||||
expect(wrapper.find(".asset-loading").exists()).toBe(true);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { IAssetProps } from "./assetPreview";
|
||||
import { ReactWrapper, mount } from "enzyme";
|
||||
import { TFRecordAsset } from "./tfrecordAsset";
|
||||
import { TFRecordAsset, ITFRecordState } from "./tfrecordAsset";
|
||||
import MockFactory from "../../../../common/mockFactory";
|
||||
import { TFRecordsBuilder, FeatureType } from "../../../../providers/export/tensorFlowRecords/tensorFlowBuilder";
|
||||
import HtmlFileReader from "../../../../common/htmlFileReader";
|
||||
@@ -10,9 +10,13 @@ describe("TFRecord Asset Component", () => {
|
||||
// tslint:disable-next-line:max-line-length
|
||||
const dataImage64 = "R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7";
|
||||
const dataImage = new Uint8Array(Buffer.from(dataImage64, "base64"));
|
||||
|
||||
const dataUri = "data:image;base64," + dataImage64;
|
||||
|
||||
let wrapper: ReactWrapper<IAssetProps> = null;
|
||||
|
||||
const onLoadHandler = jest.fn();
|
||||
const onErrorHandler = jest.fn();
|
||||
|
||||
let tfrecords: Buffer;
|
||||
beforeEach(() => {
|
||||
let builder: TFRecordsBuilder;
|
||||
@@ -21,37 +25,34 @@ describe("TFRecord Asset Component", () => {
|
||||
|
||||
const buffer = builder.build();
|
||||
tfrecords = TFRecordsBuilder.buildTFRecords([buffer]);
|
||||
|
||||
onLoadHandler.mockClear();
|
||||
onErrorHandler.mockClear();
|
||||
});
|
||||
|
||||
HtmlFileReader.getAssetArray = jest.fn((asset) => {
|
||||
return Promise.resolve<Uint8Array>(new Uint8Array(tfrecords));
|
||||
return Promise.resolve<ArrayBuffer>(new Uint8Array(tfrecords));
|
||||
});
|
||||
|
||||
let wrapper: ReactWrapper<IAssetProps> = null;
|
||||
const onLoadHandler = jest.fn();
|
||||
MockFactory.createTestAsset("test");
|
||||
const defaultProps: IAssetProps = {
|
||||
asset: {
|
||||
...MockFactory.createTestAsset("test"),
|
||||
path: "abc",
|
||||
},
|
||||
onLoaded: onLoadHandler,
|
||||
onError: onErrorHandler,
|
||||
};
|
||||
|
||||
function createComponent(props?: IAssetProps): ReactWrapper<IAssetProps> {
|
||||
function createComponent(props?: IAssetProps): ReactWrapper<IAssetProps, ITFRecordState> {
|
||||
props = props || defaultProps;
|
||||
return mount(<TFRecordAsset {...props} />);
|
||||
}
|
||||
|
||||
function wait() {
|
||||
return new Promise((resolve) => setImmediate(resolve));
|
||||
}
|
||||
|
||||
it("load image correctly", async () => {
|
||||
const props = { ...defaultProps };
|
||||
|
||||
wrapper = createComponent(props);
|
||||
await wait();
|
||||
await MockFactory.flushUi();
|
||||
|
||||
const img = wrapper.find("img");
|
||||
expect(img.exists()).toBe(true);
|
||||
@@ -63,11 +64,39 @@ describe("TFRecord Asset Component", () => {
|
||||
|
||||
it("raises onLoad handler when image has completed loading", async () => {
|
||||
wrapper = createComponent();
|
||||
await wait();
|
||||
await MockFactory.flushUi();
|
||||
|
||||
const img = wrapper.find("img").getDOMNode() as HTMLImageElement;
|
||||
img.dispatchEvent(new Event("load"));
|
||||
|
||||
expect(onLoadHandler).toBeCalledWith(expect.any(HTMLImageElement));
|
||||
});
|
||||
|
||||
it("raises onError handler when the image has an error", async () => {
|
||||
wrapper = createComponent();
|
||||
await MockFactory.flushUi();
|
||||
|
||||
const img = wrapper.find("img").getDOMNode() as HTMLImageElement;
|
||||
img.dispatchEvent(new Event("error"));
|
||||
|
||||
expect(onErrorHandler).toBeCalled();
|
||||
});
|
||||
|
||||
it("raises onError handler when there is an error reading image data from tf record", async () => {
|
||||
HtmlFileReader.getAssetArray = jest.fn(() => Promise.resolve());
|
||||
|
||||
wrapper = createComponent();
|
||||
await MockFactory.flushUi();
|
||||
|
||||
expect(onErrorHandler).toBeCalled();
|
||||
});
|
||||
|
||||
it("does not raise onError handler when there the tf record has not yet been read", async () => {
|
||||
wrapper = createComponent();
|
||||
|
||||
const img = wrapper.find("img").getDOMNode() as HTMLImageElement;
|
||||
img.dispatchEvent(new Event("error"));
|
||||
|
||||
expect(onErrorHandler).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { SyntheticEvent } from "react";
|
||||
import React from "react";
|
||||
import { IAssetProps } from "./assetPreview";
|
||||
import { IAsset } from "../../../../models/applicationState";
|
||||
import HtmlFileReader from "../../../../common/htmlFileReader";
|
||||
@@ -8,9 +8,11 @@ import { FeatureType } from "../../../../providers/export/tensorFlowRecords/tens
|
||||
/**
|
||||
* State for TFRecord Asset Image component
|
||||
* @member tfRecordImage64 - base64 representation of the image data
|
||||
* @member hasError - Whether or not there was an error loading the image data from the tf record
|
||||
*/
|
||||
export interface ITFRecordState {
|
||||
tfRecordImage64: string;
|
||||
hasError: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -19,6 +21,7 @@ export interface ITFRecordState {
|
||||
export class TFRecordAsset extends React.Component<IAssetProps, ITFRecordState> {
|
||||
public state: ITFRecordState = {
|
||||
tfRecordImage64: "",
|
||||
hasError: false,
|
||||
};
|
||||
|
||||
private image: React.RefObject<HTMLImageElement> = React.createRef();
|
||||
@@ -28,7 +31,7 @@ export class TFRecordAsset extends React.Component<IAssetProps, ITFRecordState>
|
||||
<img ref={this.image}
|
||||
src={this.state.tfRecordImage64}
|
||||
onLoad={this.onLoad}
|
||||
onError={this.props.onError} />
|
||||
onError={this.onError} />
|
||||
);
|
||||
}
|
||||
|
||||
@@ -42,10 +45,20 @@ export class TFRecordAsset extends React.Component<IAssetProps, ITFRecordState>
|
||||
}
|
||||
}
|
||||
|
||||
private async updateImage() {
|
||||
this.setState({
|
||||
tfRecordImage64: await this.getTFRecordBase64Image(this.props.asset),
|
||||
});
|
||||
private updateImage = async (): Promise<void> => {
|
||||
try {
|
||||
const base64ImageData = await this.getTFRecordBase64Image(this.props.asset);
|
||||
this.setState({
|
||||
tfRecordImage64: base64ImageData,
|
||||
hasError: !(!!base64ImageData),
|
||||
});
|
||||
} catch (e) {
|
||||
this.setState({
|
||||
hasError: true,
|
||||
});
|
||||
|
||||
this.onError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private onLoad = () => {
|
||||
@@ -54,6 +67,12 @@ export class TFRecordAsset extends React.Component<IAssetProps, ITFRecordState>
|
||||
}
|
||||
}
|
||||
|
||||
private onError = (e: React.SyntheticEvent<Element>) => {
|
||||
if (this.props.onError && (this.state.tfRecordImage64 || this.state.hasError)) {
|
||||
this.props.onError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private async getTFRecordBase64Image(asset: IAsset): Promise<string> {
|
||||
const tfrecords = new Buffer(await HtmlFileReader.getAssetArray(asset));
|
||||
const reader = new TFRecordsReader(tfrecords);
|
||||
|
||||
@@ -8,7 +8,7 @@ import EditorPage, { IEditorPageProps, IEditorPageState } from "./editorPage";
|
||||
import MockFactory from "../../../../common/mockFactory";
|
||||
import {
|
||||
IApplicationState, IAssetMetadata, IProject,
|
||||
EditorMode, IAsset, AssetState, ISize,
|
||||
EditorMode, IAsset, AssetState, AssetType, ISize,
|
||||
} from "../../../../models/applicationState";
|
||||
import { AssetProviderFactory } from "../../../../providers/storage/assetProviderFactory";
|
||||
import createReduxStore from "../../../../redux/store/store";
|
||||
@@ -385,6 +385,7 @@ describe("Editor Page Component", () => {
|
||||
expect(matchingRootAsset.state).toEqual(AssetState.Tagged);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Basic toolbar test and hotkey tests", () => {
|
||||
let wrapper: ReactWrapper = null;
|
||||
let editorPage: ReactWrapper<IEditorPageProps, IEditorPageState> = null;
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário