Warn on invalid JSON file (#1159)
* add error dialog * show error modal on file dnd * add locales * Update src/locales/en.json Co-Authored-By: Lipis <lipiridis@gmail.com> * Update src/data/blob.ts * Update src/data/blob.ts * fix titles, update snapshots * make modal smaller * fix dnd wrong file type * reset errorMessage Co-authored-by: Faustino Kialungila <faustino.kialungila@gmail.com> Co-authored-by: Lipis <lipiridis@gmail.com>
This commit is contained in:
parent
2be34effd4
commit
0c9459e9e5
@ -64,11 +64,14 @@ export const actionLoadScene = register({
|
||||
perform: (
|
||||
elements,
|
||||
appState,
|
||||
{ elements: loadedElements, appState: loadedAppState },
|
||||
{ elements: loadedElements, appState: loadedAppState, error },
|
||||
) => {
|
||||
return {
|
||||
elements: loadedElements,
|
||||
appState: loadedAppState,
|
||||
appState: {
|
||||
...loadedAppState,
|
||||
errorMessage: error,
|
||||
},
|
||||
commitToHistory: false,
|
||||
};
|
||||
},
|
||||
@ -84,7 +87,9 @@ export const actionLoadScene = register({
|
||||
.then(({ elements, appState }) => {
|
||||
updateData({ elements: elements, appState: appState });
|
||||
})
|
||||
.catch((error) => console.error(error));
|
||||
.catch((error) => {
|
||||
updateData({ error: error });
|
||||
});
|
||||
}}
|
||||
/>
|
||||
),
|
||||
|
@ -6,6 +6,7 @@ export const DEFAULT_FONT = "20px Virgil";
|
||||
export function getDefaultAppState(): AppState {
|
||||
return {
|
||||
isLoading: false,
|
||||
errorMessage: null,
|
||||
draggingElement: null,
|
||||
resizingElement: null,
|
||||
multiElement: null,
|
||||
@ -52,6 +53,7 @@ export function clearAppStateForLocalStorage(appState: AppState) {
|
||||
collaborators,
|
||||
isCollaborating,
|
||||
isLoading,
|
||||
errorMessage,
|
||||
...exportedState
|
||||
} = appState;
|
||||
return exportedState;
|
||||
|
@ -247,9 +247,13 @@ export class App extends React.Component<any, AppState> {
|
||||
}),
|
||||
)
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
this.setState({ isLoading: false });
|
||||
this.setState({ isLoading: false, errorMessage: error });
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
errorMessage: t("alerts.couldNotLoadInvalidFile"),
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
36
src/components/ErrorDialog.tsx
Normal file
36
src/components/ErrorDialog.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import React, { useState } from "react";
|
||||
import { t } from "../i18n";
|
||||
|
||||
import { Dialog } from "./Dialog";
|
||||
|
||||
export function ErrorDialog({
|
||||
message,
|
||||
onClose,
|
||||
}: {
|
||||
message: string;
|
||||
onClose?: () => void;
|
||||
}) {
|
||||
const [modalIsShown, setModalIsShown] = useState(!!message);
|
||||
|
||||
const handleClose = React.useCallback(() => {
|
||||
setModalIsShown(false);
|
||||
|
||||
if (onClose) {
|
||||
onClose();
|
||||
}
|
||||
}, [onClose]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{modalIsShown && (
|
||||
<Dialog
|
||||
maxWidth={500}
|
||||
onCloseRequest={handleClose}
|
||||
title={t("errorDialog.title")}
|
||||
>
|
||||
<div>{message}</div>
|
||||
</Dialog>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
@ -22,6 +22,7 @@ import { MobileMenu } from "./MobileMenu";
|
||||
import { ZoomActions, SelectedShapeActions, ShapesSwitcher } from "./Actions";
|
||||
import { Section } from "./Section";
|
||||
import { RoomDialog } from "./RoomDialog";
|
||||
import { ErrorDialog } from "./ErrorDialog";
|
||||
import { LoadingMessage } from "./LoadingMessage";
|
||||
|
||||
interface LayerUIProps {
|
||||
@ -105,6 +106,12 @@ export const LayerUI = React.memo(
|
||||
) : (
|
||||
<>
|
||||
{appState.isLoading && <LoadingMessage />}
|
||||
{appState.errorMessage && (
|
||||
<ErrorDialog
|
||||
message={appState.errorMessage}
|
||||
onClose={() => setAppState({ errorMessage: null })}
|
||||
/>
|
||||
)}
|
||||
<FixedSideContainer side="top">
|
||||
<HintViewer appState={appState} elements={elements} />
|
||||
<div className="App-menu App-menu_top">
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { getDefaultAppState } from "../appState";
|
||||
import { DataState } from "./types";
|
||||
import { restore } from "./restore";
|
||||
import { t } from "../i18n";
|
||||
|
||||
export async function loadFromBlob(blob: any) {
|
||||
const updateAppState = (contents: string) => {
|
||||
@ -10,7 +11,7 @@ export async function loadFromBlob(blob: any) {
|
||||
try {
|
||||
const data = JSON.parse(contents);
|
||||
if (data.type !== "excalidraw") {
|
||||
throw new Error("Cannot load invalid json");
|
||||
throw new Error(t("alerts.couldNotLoadInvalidFile"));
|
||||
}
|
||||
elements = data.elements || [];
|
||||
appState = { ...defaultAppState, ...data.appState };
|
||||
@ -39,7 +40,7 @@ export async function loadFromBlob(blob: any) {
|
||||
}
|
||||
const { elements, appState } = updateAppState(contents);
|
||||
if (!elements.length) {
|
||||
return Promise.reject("Cannot load invalid json");
|
||||
return Promise.reject(t("alerts.couldNotLoadInvalidFile"));
|
||||
}
|
||||
return new Promise<DataState>((resolve) => {
|
||||
resolve(restore(elements, appState, { scrollToContent: true }));
|
||||
|
@ -74,6 +74,7 @@
|
||||
"alerts": {
|
||||
"clearReset": "This will clear the whole canvas. Are you sure?",
|
||||
"couldNotCreateShareableLink": "Couldn't create shareable link.",
|
||||
"couldNotLoadInvalidFile": "Couldn't load invalid file",
|
||||
"importBackendFailed": "Importing from backend failed.",
|
||||
"cannotExportEmptyCanvas": "Cannot export empty canvas.",
|
||||
"couldNotCopyToClipboard": "Couldn't copy to clipboard. Try using Chrome browser.",
|
||||
@ -123,5 +124,8 @@
|
||||
"desc_persistenceWarning": "Note that the scene data is shared across collaborators in a P2P fashion, and not persisted to our server. Thus, if all of you disconnect, you will loose the data unless you export it to a file or a shareable link.",
|
||||
"desc_shareLink": "Share this link with anyone you want to collaborate with:",
|
||||
"desc_exitSession": "Stopping the session will disconnect your from the room, but you'll be able to continue working with the scene, locally. Note that this won't affect other people, and they'll still be able to collaborate on their version."
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "Error"
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -202,6 +203,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -311,6 +313,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -560,6 +563,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -705,6 +709,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -886,6 +891,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -1072,6 +1078,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -1354,6 +1361,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -1949,6 +1957,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -2058,6 +2067,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -2167,6 +2177,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -2276,6 +2287,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -2407,6 +2419,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -2538,6 +2551,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -2669,6 +2683,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -2778,6 +2793,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -2887,6 +2903,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -3018,6 +3035,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -3127,6 +3145,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -3178,6 +3197,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -3863,6 +3883,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -4224,6 +4245,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -4513,6 +4535,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -4730,6 +4753,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -4875,6 +4899,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -5524,6 +5549,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -6101,6 +6127,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -6606,6 +6633,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -7039,6 +7067,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -7436,6 +7465,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -7761,6 +7791,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -8014,6 +8045,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -8195,6 +8227,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -8880,6 +8913,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -9493,6 +9527,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -10034,6 +10069,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -10503,6 +10539,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -10746,6 +10783,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -10795,6 +10833,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -10846,6 +10885,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
@ -11127,6 +11167,7 @@ Object {
|
||||
"editingElement": null,
|
||||
"elementLocked": false,
|
||||
"elementType": "selection",
|
||||
"errorMessage": null,
|
||||
"exportBackground": true,
|
||||
"isCollaborating": false,
|
||||
"isLoading": false,
|
||||
|
@ -11,6 +11,7 @@ export type Point = Readonly<RoughPoint>;
|
||||
|
||||
export type AppState = {
|
||||
isLoading: boolean;
|
||||
errorMessage: string | null;
|
||||
draggingElement: ExcalidrawElement | null;
|
||||
resizingElement: ExcalidrawElement | null;
|
||||
multiElement: ExcalidrawLinearElement | null;
|
||||
|
Loading…
x
Reference in New Issue
Block a user