|
@@ -81,6 +81,7 @@ import { appJotaiStore } from "../app-jotai";
|
|
import { Mutable, ValueOf } from "../../packages/excalidraw/utility-types";
|
|
import { Mutable, ValueOf } from "../../packages/excalidraw/utility-types";
|
|
import { getVisibleSceneBounds } from "../../packages/excalidraw/element/bounds";
|
|
import { getVisibleSceneBounds } from "../../packages/excalidraw/element/bounds";
|
|
import { withBatchedUpdates } from "../../packages/excalidraw/reactUtils";
|
|
import { withBatchedUpdates } from "../../packages/excalidraw/reactUtils";
|
|
|
|
+import { collabErrorIndicatorAtom } from "./CollabError";
|
|
|
|
|
|
export const collabAPIAtom = atom<CollabAPI | null>(null);
|
|
export const collabAPIAtom = atom<CollabAPI | null>(null);
|
|
export const isCollaboratingAtom = atom(false);
|
|
export const isCollaboratingAtom = atom(false);
|
|
@@ -88,6 +89,8 @@ export const isOfflineAtom = atom(false);
|
|
|
|
|
|
interface CollabState {
|
|
interface CollabState {
|
|
errorMessage: string | null;
|
|
errorMessage: string | null;
|
|
|
|
+ /** errors related to saving */
|
|
|
|
+ dialogNotifiedErrors: Record<string, boolean>;
|
|
username: string;
|
|
username: string;
|
|
activeRoomLink: string | null;
|
|
activeRoomLink: string | null;
|
|
}
|
|
}
|
|
@@ -107,7 +110,7 @@ export interface CollabAPI {
|
|
setUsername: CollabInstance["setUsername"];
|
|
setUsername: CollabInstance["setUsername"];
|
|
getUsername: CollabInstance["getUsername"];
|
|
getUsername: CollabInstance["getUsername"];
|
|
getActiveRoomLink: CollabInstance["getActiveRoomLink"];
|
|
getActiveRoomLink: CollabInstance["getActiveRoomLink"];
|
|
- setErrorMessage: CollabInstance["setErrorMessage"];
|
|
|
|
|
|
+ setCollabError: CollabInstance["setErrorDialog"];
|
|
}
|
|
}
|
|
|
|
|
|
interface CollabProps {
|
|
interface CollabProps {
|
|
@@ -129,6 +132,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
|
super(props);
|
|
super(props);
|
|
this.state = {
|
|
this.state = {
|
|
errorMessage: null,
|
|
errorMessage: null,
|
|
|
|
+ dialogNotifiedErrors: {},
|
|
username: importUsernameFromLocalStorage() || "",
|
|
username: importUsernameFromLocalStorage() || "",
|
|
activeRoomLink: null,
|
|
activeRoomLink: null,
|
|
};
|
|
};
|
|
@@ -197,7 +201,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
|
setUsername: this.setUsername,
|
|
setUsername: this.setUsername,
|
|
getUsername: this.getUsername,
|
|
getUsername: this.getUsername,
|
|
getActiveRoomLink: this.getActiveRoomLink,
|
|
getActiveRoomLink: this.getActiveRoomLink,
|
|
- setErrorMessage: this.setErrorMessage,
|
|
|
|
|
|
+ setCollabError: this.setErrorDialog,
|
|
};
|
|
};
|
|
|
|
|
|
appJotaiStore.set(collabAPIAtom, collabAPI);
|
|
appJotaiStore.set(collabAPIAtom, collabAPI);
|
|
@@ -276,18 +280,35 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
|
this.excalidrawAPI.getAppState(),
|
|
this.excalidrawAPI.getAppState(),
|
|
);
|
|
);
|
|
|
|
|
|
|
|
+ this.resetErrorIndicator();
|
|
|
|
+
|
|
if (this.isCollaborating() && savedData && savedData.reconciledElements) {
|
|
if (this.isCollaborating() && savedData && savedData.reconciledElements) {
|
|
this.handleRemoteSceneUpdate(
|
|
this.handleRemoteSceneUpdate(
|
|
this.reconcileElements(savedData.reconciledElements),
|
|
this.reconcileElements(savedData.reconciledElements),
|
|
);
|
|
);
|
|
}
|
|
}
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
- this.setState({
|
|
|
|
- // firestore doesn't return a specific error code when size exceeded
|
|
|
|
- errorMessage: /is longer than.*?bytes/.test(error.message)
|
|
|
|
- ? t("errors.collabSaveFailed_sizeExceeded")
|
|
|
|
- : t("errors.collabSaveFailed"),
|
|
|
|
- });
|
|
|
|
|
|
+ const errorMessage = /is longer than.*?bytes/.test(error.message)
|
|
|
|
+ ? t("errors.collabSaveFailed_sizeExceeded")
|
|
|
|
+ : t("errors.collabSaveFailed");
|
|
|
|
+
|
|
|
|
+ if (
|
|
|
|
+ !this.state.dialogNotifiedErrors[errorMessage] ||
|
|
|
|
+ !this.isCollaborating()
|
|
|
|
+ ) {
|
|
|
|
+ this.setErrorDialog(errorMessage);
|
|
|
|
+ this.setState({
|
|
|
|
+ dialogNotifiedErrors: {
|
|
|
|
+ ...this.state.dialogNotifiedErrors,
|
|
|
|
+ [errorMessage]: true,
|
|
|
|
+ },
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (this.isCollaborating()) {
|
|
|
|
+ this.setErrorIndicator(errorMessage);
|
|
|
|
+ }
|
|
|
|
+
|
|
console.error(error);
|
|
console.error(error);
|
|
}
|
|
}
|
|
};
|
|
};
|
|
@@ -296,6 +317,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
|
this.queueBroadcastAllElements.cancel();
|
|
this.queueBroadcastAllElements.cancel();
|
|
this.queueSaveToFirebase.cancel();
|
|
this.queueSaveToFirebase.cancel();
|
|
this.loadImageFiles.cancel();
|
|
this.loadImageFiles.cancel();
|
|
|
|
+ this.resetErrorIndicator(true);
|
|
|
|
|
|
this.saveCollabRoomToFirebase(
|
|
this.saveCollabRoomToFirebase(
|
|
getSyncableElements(
|
|
getSyncableElements(
|
|
@@ -464,7 +486,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
|
this.portal.socket.once("connect_error", fallbackInitializationHandler);
|
|
this.portal.socket.once("connect_error", fallbackInitializationHandler);
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
console.error(error);
|
|
console.error(error);
|
|
- this.setState({ errorMessage: error.message });
|
|
|
|
|
|
+ this.setErrorDialog(error.message);
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -923,8 +945,26 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
|
|
|
|
|
getActiveRoomLink = () => this.state.activeRoomLink;
|
|
getActiveRoomLink = () => this.state.activeRoomLink;
|
|
|
|
|
|
- setErrorMessage = (errorMessage: string | null) => {
|
|
|
|
- this.setState({ errorMessage });
|
|
|
|
|
|
+ setErrorIndicator = (errorMessage: string | null) => {
|
|
|
|
+ appJotaiStore.set(collabErrorIndicatorAtom, {
|
|
|
|
+ message: errorMessage,
|
|
|
|
+ nonce: Date.now(),
|
|
|
|
+ });
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ resetErrorIndicator = (resetDialogNotifiedErrors = false) => {
|
|
|
|
+ appJotaiStore.set(collabErrorIndicatorAtom, { message: null, nonce: 0 });
|
|
|
|
+ if (resetDialogNotifiedErrors) {
|
|
|
|
+ this.setState({
|
|
|
|
+ dialogNotifiedErrors: {},
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ setErrorDialog = (errorMessage: string | null) => {
|
|
|
|
+ this.setState({
|
|
|
|
+ errorMessage,
|
|
|
|
+ });
|
|
};
|
|
};
|
|
|
|
|
|
render() {
|
|
render() {
|
|
@@ -933,7 +973,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
|
return (
|
|
return (
|
|
<>
|
|
<>
|
|
{errorMessage != null && (
|
|
{errorMessage != null && (
|
|
- <ErrorDialog onClose={() => this.setState({ errorMessage: null })}>
|
|
|
|
|
|
+ <ErrorDialog onClose={() => this.setErrorDialog(null)}>
|
|
{errorMessage}
|
|
{errorMessage}
|
|
</ErrorDialog>
|
|
</ErrorDialog>
|
|
)}
|
|
)}
|