feat: show error message when not connected to internet while collabo… (#6165)
Co-authored-by: dwelle <luzar.david@gmail.com> Resolves https://github.com/excalidraw/excalidraw/issues/5994
This commit is contained in:
parent
11e2f90ca1
commit
a8e6028c33
@ -124,7 +124,6 @@ const LayerUI = ({
|
|||||||
children,
|
children,
|
||||||
}: LayerUIProps) => {
|
}: LayerUIProps) => {
|
||||||
const device = useDevice();
|
const device = useDevice();
|
||||||
|
|
||||||
const tunnels = useInitializeTunnels();
|
const tunnels = useInitializeTunnels();
|
||||||
|
|
||||||
const renderJSONExportDialog = () => {
|
const renderJSONExportDialog = () => {
|
||||||
|
@ -95,6 +95,9 @@
|
|||||||
--color-gray-90: #1e1e1e;
|
--color-gray-90: #1e1e1e;
|
||||||
--color-gray-100: #121212;
|
--color-gray-100: #121212;
|
||||||
|
|
||||||
|
--color-warning: #fceeca;
|
||||||
|
--color-text-warning: var(--text-primary-color);
|
||||||
|
|
||||||
--color-danger: #db6965;
|
--color-danger: #db6965;
|
||||||
--color-promo: #e70078;
|
--color-promo: #e70078;
|
||||||
|
|
||||||
@ -163,6 +166,8 @@
|
|||||||
--color-primary-darkest: #beb9ff;
|
--color-primary-darkest: #beb9ff;
|
||||||
--color-primary-light: #4f4d6f;
|
--color-primary-light: #4f4d6f;
|
||||||
|
|
||||||
|
--color-text-warning: var(--color-gray-80);
|
||||||
|
|
||||||
--color-danger: #ffa8a5;
|
--color-danger: #ffa8a5;
|
||||||
--color-promo: #d297ff;
|
--color-promo: #d297ff;
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,7 @@ import { jotaiStore } from "../../jotai";
|
|||||||
export const collabAPIAtom = atom<CollabAPI | null>(null);
|
export const collabAPIAtom = atom<CollabAPI | null>(null);
|
||||||
export const collabDialogShownAtom = atom(false);
|
export const collabDialogShownAtom = atom(false);
|
||||||
export const isCollaboratingAtom = atom(false);
|
export const isCollaboratingAtom = atom(false);
|
||||||
|
export const isOfflineAtom = atom(false);
|
||||||
|
|
||||||
interface CollabState {
|
interface CollabState {
|
||||||
errorMessage: string;
|
errorMessage: string;
|
||||||
@ -152,6 +153,8 @@ class Collab extends PureComponent<Props, CollabState> {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window.addEventListener(EVENT.BEFORE_UNLOAD, this.beforeUnload);
|
window.addEventListener(EVENT.BEFORE_UNLOAD, this.beforeUnload);
|
||||||
|
window.addEventListener("online", this.onOfflineStatusToggle);
|
||||||
|
window.addEventListener("offline", this.onOfflineStatusToggle);
|
||||||
window.addEventListener(EVENT.UNLOAD, this.onUnload);
|
window.addEventListener(EVENT.UNLOAD, this.onUnload);
|
||||||
|
|
||||||
const collabAPI: CollabAPI = {
|
const collabAPI: CollabAPI = {
|
||||||
@ -165,6 +168,7 @@ class Collab extends PureComponent<Props, CollabState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
jotaiStore.set(collabAPIAtom, collabAPI);
|
jotaiStore.set(collabAPIAtom, collabAPI);
|
||||||
|
this.onOfflineStatusToggle();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
process.env.NODE_ENV === ENV.TEST ||
|
process.env.NODE_ENV === ENV.TEST ||
|
||||||
@ -180,7 +184,13 @@ class Collab extends PureComponent<Props, CollabState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onOfflineStatusToggle = () => {
|
||||||
|
jotaiStore.set(isOfflineAtom, !window.navigator.onLine);
|
||||||
|
};
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener("online", this.onOfflineStatusToggle);
|
||||||
|
window.removeEventListener("offline", this.onOfflineStatusToggle);
|
||||||
window.removeEventListener(EVENT.BEFORE_UNLOAD, this.beforeUnload);
|
window.removeEventListener(EVENT.BEFORE_UNLOAD, this.beforeUnload);
|
||||||
window.removeEventListener(EVENT.UNLOAD, this.onUnload);
|
window.removeEventListener(EVENT.UNLOAD, this.onUnload);
|
||||||
window.removeEventListener(EVENT.POINTER_MOVE, this.onPointerMove);
|
window.removeEventListener(EVENT.POINTER_MOVE, this.onPointerMove);
|
||||||
|
@ -45,6 +45,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.collab-offline-warning {
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 6.5rem;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.5;
|
||||||
|
border-radius: var(--border-radius-md);
|
||||||
|
background-color: var(--color-warning);
|
||||||
|
color: var(--color-text-warning);
|
||||||
|
z-index: 6;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.excalidraw-app.is-collaborating {
|
.excalidraw-app.is-collaborating {
|
||||||
|
@ -52,6 +52,7 @@ import Collab, {
|
|||||||
collabAPIAtom,
|
collabAPIAtom,
|
||||||
collabDialogShownAtom,
|
collabDialogShownAtom,
|
||||||
isCollaboratingAtom,
|
isCollaboratingAtom,
|
||||||
|
isOfflineAtom,
|
||||||
} from "./collab/Collab";
|
} from "./collab/Collab";
|
||||||
import {
|
import {
|
||||||
exportToBackend,
|
exportToBackend,
|
||||||
@ -66,10 +67,7 @@ import {
|
|||||||
} from "./data/localStorage";
|
} from "./data/localStorage";
|
||||||
import CustomStats from "./CustomStats";
|
import CustomStats from "./CustomStats";
|
||||||
import { restore, restoreAppState, RestoredDataState } from "../data/restore";
|
import { restore, restoreAppState, RestoredDataState } from "../data/restore";
|
||||||
|
|
||||||
import "./index.scss";
|
|
||||||
import { ExportToExcalidrawPlus } from "./components/ExportToExcalidrawPlus";
|
import { ExportToExcalidrawPlus } from "./components/ExportToExcalidrawPlus";
|
||||||
|
|
||||||
import { updateStaleImageStatuses } from "./data/FileManager";
|
import { updateStaleImageStatuses } from "./data/FileManager";
|
||||||
import { newElementWith } from "../element/mutateElement";
|
import { newElementWith } from "../element/mutateElement";
|
||||||
import { isInitializedImageElement } from "../element/typeChecks";
|
import { isInitializedImageElement } from "../element/typeChecks";
|
||||||
@ -77,7 +75,7 @@ import { loadFilesFromFirebase } from "./data/firebase";
|
|||||||
import { LocalData } from "./data/LocalData";
|
import { LocalData } from "./data/LocalData";
|
||||||
import { isBrowserStorageStateNewer } from "./data/tabSync";
|
import { isBrowserStorageStateNewer } from "./data/tabSync";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { atom, Provider, useAtom } from "jotai";
|
import { atom, Provider, useAtom, useAtomValue } from "jotai";
|
||||||
import { jotaiStore, useAtomWithInitialValue } from "../jotai";
|
import { jotaiStore, useAtomWithInitialValue } from "../jotai";
|
||||||
import { reconcileElements } from "./collab/reconciliation";
|
import { reconcileElements } from "./collab/reconciliation";
|
||||||
import { parseLibraryTokensFromUrl, useHandleLibrary } from "../data/library";
|
import { parseLibraryTokensFromUrl, useHandleLibrary } from "../data/library";
|
||||||
@ -85,6 +83,8 @@ import { AppMainMenu } from "./components/AppMainMenu";
|
|||||||
import { AppWelcomeScreen } from "./components/AppWelcomeScreen";
|
import { AppWelcomeScreen } from "./components/AppWelcomeScreen";
|
||||||
import { AppFooter } from "./components/AppFooter";
|
import { AppFooter } from "./components/AppFooter";
|
||||||
|
|
||||||
|
import "./index.scss";
|
||||||
|
|
||||||
polyfill();
|
polyfill();
|
||||||
|
|
||||||
window.EXCALIDRAW_THROTTLE_RENDER = true;
|
window.EXCALIDRAW_THROTTLE_RENDER = true;
|
||||||
@ -599,6 +599,8 @@ const ExcalidrawWrapper = () => {
|
|||||||
localStorage.setItem(STORAGE_KEYS.LOCAL_STORAGE_LIBRARY, serializedItems);
|
localStorage.setItem(STORAGE_KEYS.LOCAL_STORAGE_LIBRARY, serializedItems);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isOffline = useAtomValue(isOfflineAtom);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{ height: "100%" }}
|
style={{ height: "100%" }}
|
||||||
@ -661,6 +663,11 @@ const ExcalidrawWrapper = () => {
|
|||||||
/>
|
/>
|
||||||
<AppWelcomeScreen setCollabDialogShown={setCollabDialogShown} />
|
<AppWelcomeScreen setCollabDialogShown={setCollabDialogShown} />
|
||||||
<AppFooter />
|
<AppFooter />
|
||||||
|
{isCollaborating && isOffline && (
|
||||||
|
<div className="collab-offline-warning">
|
||||||
|
{t("alerts.collabOfflineWarning")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</Excalidraw>
|
</Excalidraw>
|
||||||
{excalidrawAPI && <Collab excalidrawAPI={excalidrawAPI} />}
|
{excalidrawAPI && <Collab excalidrawAPI={excalidrawAPI} />}
|
||||||
{errorMessage && (
|
{errorMessage && (
|
||||||
|
@ -193,7 +193,8 @@
|
|||||||
"invalidSceneUrl": "Couldn't import scene from the supplied URL. It's either malformed, or doesn't contain valid Excalidraw JSON data.",
|
"invalidSceneUrl": "Couldn't import scene from the supplied URL. It's either malformed, or doesn't contain valid Excalidraw JSON data.",
|
||||||
"resetLibrary": "This will clear your library. Are you sure?",
|
"resetLibrary": "This will clear your library. Are you sure?",
|
||||||
"removeItemsFromsLibrary": "Delete {{count}} item(s) from library?",
|
"removeItemsFromsLibrary": "Delete {{count}} item(s) from library?",
|
||||||
"invalidEncryptionKey": "Encryption key must be of 22 characters. Live collaboration is disabled."
|
"invalidEncryptionKey": "Encryption key must be of 22 characters. Live collaboration is disabled.",
|
||||||
|
"collabOfflineWarning": "No internet connection available.\nYour changes will not be saved!"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"unsupportedFileType": "Unsupported file type.",
|
"unsupportedFileType": "Unsupported file type.",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user