From a8e6028c33d83457f317b5977c0c296c617a9906 Mon Sep 17 00:00:00 2001 From: Matthieu Rossignon <51274353+Mattross45@users.noreply.github.com> Date: Sat, 4 Feb 2023 15:03:39 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20show=20error=20message=20when=20not=20c?= =?UTF-8?q?onnected=20to=20internet=20while=20collabo=E2=80=A6=20(#6165)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: dwelle Resolves https://github.com/excalidraw/excalidraw/issues/5994 --- src/components/LayerUI.tsx | 1 - src/css/theme.scss | 5 +++++ src/excalidraw-app/collab/Collab.tsx | 10 ++++++++++ src/excalidraw-app/index.scss | 17 +++++++++++++++++ src/excalidraw-app/index.tsx | 15 +++++++++++---- src/locales/en.json | 3 ++- 6 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/components/LayerUI.tsx b/src/components/LayerUI.tsx index b7d765a8..bea074d6 100644 --- a/src/components/LayerUI.tsx +++ b/src/components/LayerUI.tsx @@ -124,7 +124,6 @@ const LayerUI = ({ children, }: LayerUIProps) => { const device = useDevice(); - const tunnels = useInitializeTunnels(); const renderJSONExportDialog = () => { diff --git a/src/css/theme.scss b/src/css/theme.scss index 90b1bcde..fd806796 100644 --- a/src/css/theme.scss +++ b/src/css/theme.scss @@ -95,6 +95,9 @@ --color-gray-90: #1e1e1e; --color-gray-100: #121212; + --color-warning: #fceeca; + --color-text-warning: var(--text-primary-color); + --color-danger: #db6965; --color-promo: #e70078; @@ -163,6 +166,8 @@ --color-primary-darkest: #beb9ff; --color-primary-light: #4f4d6f; + --color-text-warning: var(--color-gray-80); + --color-danger: #ffa8a5; --color-promo: #d297ff; } diff --git a/src/excalidraw-app/collab/Collab.tsx b/src/excalidraw-app/collab/Collab.tsx index 4f98f58f..1a996f03 100644 --- a/src/excalidraw-app/collab/Collab.tsx +++ b/src/excalidraw-app/collab/Collab.tsx @@ -75,6 +75,7 @@ import { jotaiStore } from "../../jotai"; export const collabAPIAtom = atom(null); export const collabDialogShownAtom = atom(false); export const isCollaboratingAtom = atom(false); +export const isOfflineAtom = atom(false); interface CollabState { errorMessage: string; @@ -152,6 +153,8 @@ class Collab extends PureComponent { componentDidMount() { window.addEventListener(EVENT.BEFORE_UNLOAD, this.beforeUnload); + window.addEventListener("online", this.onOfflineStatusToggle); + window.addEventListener("offline", this.onOfflineStatusToggle); window.addEventListener(EVENT.UNLOAD, this.onUnload); const collabAPI: CollabAPI = { @@ -165,6 +168,7 @@ class Collab extends PureComponent { }; jotaiStore.set(collabAPIAtom, collabAPI); + this.onOfflineStatusToggle(); if ( process.env.NODE_ENV === ENV.TEST || @@ -180,7 +184,13 @@ class Collab extends PureComponent { } } + onOfflineStatusToggle = () => { + jotaiStore.set(isOfflineAtom, !window.navigator.onLine); + }; + componentWillUnmount() { + window.removeEventListener("online", this.onOfflineStatusToggle); + window.removeEventListener("offline", this.onOfflineStatusToggle); window.removeEventListener(EVENT.BEFORE_UNLOAD, this.beforeUnload); window.removeEventListener(EVENT.UNLOAD, this.onUnload); window.removeEventListener(EVENT.POINTER_MOVE, this.onPointerMove); diff --git a/src/excalidraw-app/index.scss b/src/excalidraw-app/index.scss index b9e693ec..38c4c1a3 100644 --- a/src/excalidraw-app/index.scss +++ b/src/excalidraw-app/index.scss @@ -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 { diff --git a/src/excalidraw-app/index.tsx b/src/excalidraw-app/index.tsx index 6d6c9fe7..fe2ac1a1 100644 --- a/src/excalidraw-app/index.tsx +++ b/src/excalidraw-app/index.tsx @@ -52,6 +52,7 @@ import Collab, { collabAPIAtom, collabDialogShownAtom, isCollaboratingAtom, + isOfflineAtom, } from "./collab/Collab"; import { exportToBackend, @@ -66,10 +67,7 @@ import { } from "./data/localStorage"; import CustomStats from "./CustomStats"; import { restore, restoreAppState, RestoredDataState } from "../data/restore"; - -import "./index.scss"; import { ExportToExcalidrawPlus } from "./components/ExportToExcalidrawPlus"; - import { updateStaleImageStatuses } from "./data/FileManager"; import { newElementWith } from "../element/mutateElement"; import { isInitializedImageElement } from "../element/typeChecks"; @@ -77,7 +75,7 @@ import { loadFilesFromFirebase } from "./data/firebase"; import { LocalData } from "./data/LocalData"; import { isBrowserStorageStateNewer } from "./data/tabSync"; import clsx from "clsx"; -import { atom, Provider, useAtom } from "jotai"; +import { atom, Provider, useAtom, useAtomValue } from "jotai"; import { jotaiStore, useAtomWithInitialValue } from "../jotai"; import { reconcileElements } from "./collab/reconciliation"; import { parseLibraryTokensFromUrl, useHandleLibrary } from "../data/library"; @@ -85,6 +83,8 @@ import { AppMainMenu } from "./components/AppMainMenu"; import { AppWelcomeScreen } from "./components/AppWelcomeScreen"; import { AppFooter } from "./components/AppFooter"; +import "./index.scss"; + polyfill(); window.EXCALIDRAW_THROTTLE_RENDER = true; @@ -599,6 +599,8 @@ const ExcalidrawWrapper = () => { localStorage.setItem(STORAGE_KEYS.LOCAL_STORAGE_LIBRARY, serializedItems); }; + const isOffline = useAtomValue(isOfflineAtom); + return (
{ /> + {isCollaborating && isOffline && ( +
+ {t("alerts.collabOfflineWarning")} +
+ )} {excalidrawAPI && } {errorMessage && ( diff --git a/src/locales/en.json b/src/locales/en.json index 1a46b20e..31005cb4 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -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.", "resetLibrary": "This will clear your library. Are you sure?", "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": { "unsupportedFileType": "Unsupported file type.",