Commit 07e786e0 authored by Alejandro Celaya's avatar Alejandro Celaya Committed by Alejandro Celaya

Render error toast message if an error occurs when exporting annotations

parent 84bef73b
...@@ -4,6 +4,7 @@ import { useRef } from 'preact/hooks'; ...@@ -4,6 +4,7 @@ import { useRef } from 'preact/hooks';
import { downloadJSONFile } from '../../../shared/download-json-file'; import { downloadJSONFile } from '../../../shared/download-json-file';
import { withServices } from '../../service-context'; import { withServices } from '../../service-context';
import type { AnnotationsExporter } from '../../services/annotations-exporter'; import type { AnnotationsExporter } from '../../services/annotations-exporter';
import type { ToastMessengerService } from '../../services/toast-messenger';
import { useSidebarStore } from '../../store'; import { useSidebarStore } from '../../store';
import { suggestedFilename } from '../../util/export-annotations'; import { suggestedFilename } from '../../util/export-annotations';
import LoadingSpinner from './LoadingSpinner'; import LoadingSpinner from './LoadingSpinner';
...@@ -11,6 +12,7 @@ import LoadingSpinner from './LoadingSpinner'; ...@@ -11,6 +12,7 @@ import LoadingSpinner from './LoadingSpinner';
export type ExportAnnotationsProps = { export type ExportAnnotationsProps = {
// injected // injected
annotationsExporter: AnnotationsExporter; annotationsExporter: AnnotationsExporter;
toastMessenger: ToastMessengerService;
}; };
// TODO: Validate user-entered filename // TODO: Validate user-entered filename
...@@ -20,7 +22,10 @@ export type ExportAnnotationsProps = { ...@@ -20,7 +22,10 @@ export type ExportAnnotationsProps = {
* Render content for "export" tab panel: allow user to export annotations * Render content for "export" tab panel: allow user to export annotations
* with a specified filename. * with a specified filename.
*/ */
function ExportAnnotations({ annotationsExporter }: ExportAnnotationsProps) { function ExportAnnotations({
annotationsExporter,
toastMessenger,
}: ExportAnnotationsProps) {
const store = useSidebarStore(); const store = useSidebarStore();
const group = store.focusedGroup(); const group = store.focusedGroup();
const exportReady = group && !store.isLoading(); const exportReady = group && !store.isLoading();
...@@ -35,11 +40,15 @@ function ExportAnnotations({ annotationsExporter }: ExportAnnotationsProps) { ...@@ -35,11 +40,15 @@ function ExportAnnotations({ annotationsExporter }: ExportAnnotationsProps) {
} }
const exportAnnotations = () => { const exportAnnotations = () => {
const filename = `${inputRef.current!.value}.json`; try {
const exportData = annotationsExporter.buildExportContent( const filename = `${inputRef.current!.value}.json`;
exportableAnnotations, const exportData = annotationsExporter.buildExportContent(
); exportableAnnotations,
downloadJSONFile(exportData, filename); );
downloadJSONFile(exportData, filename);
} catch (e) {
toastMessenger.error('Exporting annotations failed');
}
}; };
// Naive simple English pluralization // Naive simple English pluralization
...@@ -90,4 +99,7 @@ function ExportAnnotations({ annotationsExporter }: ExportAnnotationsProps) { ...@@ -90,4 +99,7 @@ function ExportAnnotations({ annotationsExporter }: ExportAnnotationsProps) {
); );
} }
export default withServices(ExportAnnotations, ['annotationsExporter']); export default withServices(ExportAnnotations, [
'annotationsExporter',
'toastMessenger',
]);
...@@ -8,6 +8,7 @@ import ExportAnnotations, { $imports } from '../ExportAnnotations'; ...@@ -8,6 +8,7 @@ import ExportAnnotations, { $imports } from '../ExportAnnotations';
describe('ExportAnnotations', () => { describe('ExportAnnotations', () => {
let fakeStore; let fakeStore;
let fakeAnnotationsExporter; let fakeAnnotationsExporter;
let fakeToastMessenger;
let fakeDownloadJSONFile; let fakeDownloadJSONFile;
const fakePrivateGroup = { const fakePrivateGroup = {
...@@ -20,6 +21,7 @@ describe('ExportAnnotations', () => { ...@@ -20,6 +21,7 @@ describe('ExportAnnotations', () => {
mount( mount(
<ExportAnnotations <ExportAnnotations
annotationsExporter={fakeAnnotationsExporter} annotationsExporter={fakeAnnotationsExporter}
toastMessenger={fakeToastMessenger}
{...props} {...props}
/>, />,
); );
...@@ -28,6 +30,9 @@ describe('ExportAnnotations', () => { ...@@ -28,6 +30,9 @@ describe('ExportAnnotations', () => {
fakeAnnotationsExporter = { fakeAnnotationsExporter = {
buildExportContent: sinon.stub().returns({}), buildExportContent: sinon.stub().returns({}),
}; };
fakeToastMessenger = {
error: sinon.stub(),
};
fakeDownloadJSONFile = sinon.stub(); fakeDownloadJSONFile = sinon.stub();
fakeStore = { fakeStore = {
countDrafts: sinon.stub().returns(0), countDrafts: sinon.stub().returns(0),
...@@ -107,6 +112,9 @@ describe('ExportAnnotations', () => { ...@@ -107,6 +112,9 @@ describe('ExportAnnotations', () => {
}); });
describe('export button clicked', () => { describe('export button clicked', () => {
const clickExportButton = wrapper =>
wrapper.find('button[data-testid="export-button"]').simulate('click');
it('builds an export file from the non-draft annotations', () => { it('builds an export file from the non-draft annotations', () => {
const wrapper = createComponent(); const wrapper = createComponent();
const annotationsToExport = [ const annotationsToExport = [
...@@ -115,13 +123,14 @@ describe('ExportAnnotations', () => { ...@@ -115,13 +123,14 @@ describe('ExportAnnotations', () => {
]; ];
fakeStore.savedAnnotations.returns(annotationsToExport); fakeStore.savedAnnotations.returns(annotationsToExport);
wrapper.find('button[data-testid="export-button"]').simulate('click'); clickExportButton(wrapper);
assert.calledOnce(fakeAnnotationsExporter.buildExportContent); assert.calledOnce(fakeAnnotationsExporter.buildExportContent);
assert.calledWith( assert.calledWith(
fakeAnnotationsExporter.buildExportContent, fakeAnnotationsExporter.buildExportContent,
annotationsToExport, annotationsToExport,
); );
assert.notCalled(fakeToastMessenger.error);
}); });
it('downloads a file using user-entered filename appended with `.json`', () => { it('downloads a file using user-entered filename appended with `.json`', () => {
...@@ -130,7 +139,7 @@ describe('ExportAnnotations', () => { ...@@ -130,7 +139,7 @@ describe('ExportAnnotations', () => {
wrapper.find('input[data-testid="export-filename"]').getDOMNode().value = wrapper.find('input[data-testid="export-filename"]').getDOMNode().value =
'my-filename'; 'my-filename';
wrapper.find('button[data-testid="export-button"]').simulate('click'); clickExportButton(wrapper);
assert.calledOnce(fakeDownloadJSONFile); assert.calledOnce(fakeDownloadJSONFile);
assert.calledWith( assert.calledWith(
...@@ -139,6 +148,25 @@ describe('ExportAnnotations', () => { ...@@ -139,6 +148,25 @@ describe('ExportAnnotations', () => {
'my-filename.json', 'my-filename.json',
); );
}); });
context('when exporting annotations fails', () => {
it('displays error toast message', () => {
fakeAnnotationsExporter.buildExportContent.throws(
new Error('Error exporting'),
);
const wrapper = createComponent();
clickExportButton(wrapper);
assert.notCalled(fakeDownloadJSONFile);
assert.calledOnce(fakeAnnotationsExporter.buildExportContent);
assert.calledWith(
fakeToastMessenger.error,
'Exporting annotations failed',
);
});
});
}); });
context('no annotations available to export', () => { context('no annotations available to export', () => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment