From 1e20e4fcf956ab526bca28b70ed3f3bf83f339c8 Mon Sep 17 00:00:00 2001 From: Nicola Thouliss Date: Fri, 14 May 2021 14:15:30 +1000 Subject: [PATCH 01/31] Added sentry integrations package --- package.json | 3 +- yarn.lock | 123 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 81 insertions(+), 45 deletions(-) diff --git a/package.json b/package.json index 5fa1a20..9293d40 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "@babylonjs/loaders": "^4.2.0", "@mitchemmc/dexie-export-import": "^1.0.1", "@msgpack/msgpack": "^2.4.1", - "@sentry/react": "^6.2.2", + "@sentry/integrations": "^6.3.0", + "@sentry/react": "^6.3.0", "@stripe/stripe-js": "^1.13.1", "@tensorflow/tfjs": "^3.3.0", "@testing-library/jest-dom": "^5.11.9", diff --git a/yarn.lock b/yarn.lock index 439014e..f7afee8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2286,68 +2286,78 @@ estree-walker "^1.0.1" picomatch "^2.2.2" -"@sentry/browser@6.2.2": - version "6.2.2" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.2.2.tgz#4df4ad7026b269d85b63b79a75387ce5370bc705" - integrity sha512-K5UGyEePtVPZIFMoiRafhd4Ov0M1kdozVsVKIPZrOpJyjQdPNX+fYDNL/h0nVmgOlE2S/uu4fl4mEfe/6aLShw== +"@sentry/browser@6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.3.0.tgz#523430667bff290220909fb96f35706ff808fed6" + integrity sha512-Rse9j5XwN9n7GnfW1mNscTS4YQ0oiBNJcaSk3Mw/vQT872Wh60yKyx5wxAw5GujFZI0NgdyPlZwZ/tGQwirRxA== dependencies: - "@sentry/core" "6.2.2" - "@sentry/types" "6.2.2" - "@sentry/utils" "6.2.2" + "@sentry/core" "6.3.0" + "@sentry/types" "6.3.0" + "@sentry/utils" "6.3.0" tslib "^1.9.3" -"@sentry/core@6.2.2": - version "6.2.2" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.2.2.tgz#ec86b5769f8855f43cb58e839f81f87074ec9a3f" - integrity sha512-qqWbvvXtymfXh7N5eEvk97MCnMURuyFIgqWdVD4MQM6yIfDCy36CyGfuQ3ViHTLZGdIfEOhLL9/f4kzf1RzqBA== +"@sentry/core@6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.3.0.tgz#3b8db24918a00c0b77f1663fc6d9be925f66bb3e" + integrity sha512-voot/lJ9gRXB6bx6tVqbEbD6jOd4Sx6Rfmm6pzfpom9C0q+fjIZTatTLq8GdXj8DzxaH1MBDSwtaq/eC3NqYpA== dependencies: - "@sentry/hub" "6.2.2" - "@sentry/minimal" "6.2.2" - "@sentry/types" "6.2.2" - "@sentry/utils" "6.2.2" + "@sentry/hub" "6.3.0" + "@sentry/minimal" "6.3.0" + "@sentry/types" "6.3.0" + "@sentry/utils" "6.3.0" tslib "^1.9.3" -"@sentry/hub@6.2.2": - version "6.2.2" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.2.2.tgz#f451d8d3ad207e81556b4846d810226693e0444e" - integrity sha512-VR6uQGRYt6RP633FHShlSLj0LUKGVrlTeSlwCoooWM5FR9lmi6akAaweuxpG78/kZvXrAWpjX6/nuYwHKGwzGA== +"@sentry/hub@6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.3.0.tgz#4225b3b0f31fe47f24d80753b257a4b57de5d651" + integrity sha512-lAnW3Om66t9IR+t1wya1NpOF9lGbvYG6Ca8wxJJGJ1t2PxKwyxpZKzRx0q8M1QFhlZ5cETCzxmM7lBEZ4QVCBg== dependencies: - "@sentry/types" "6.2.2" - "@sentry/utils" "6.2.2" + "@sentry/types" "6.3.0" + "@sentry/utils" "6.3.0" tslib "^1.9.3" -"@sentry/minimal@6.2.2": - version "6.2.2" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.2.2.tgz#01f41e0a6a6a2becfc99f6bb6f9c4bddf54f8dae" - integrity sha512-l0IgoGQgg1lTd4qDU8bQn25sbZBg8PwIHfuTLbGMlRr1flDXHOM1UXajWK/UKbAPelnU7M2JBSVzgl7PwjprzA== +"@sentry/integrations@^6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-6.3.0.tgz#2091889d1d4a319d48e84ebce43405c6a7fee5b7" + integrity sha512-/bl0wykJr+7zJHmnAulI+/J1kT5AI/019jWSXX7nmfIhp2sRXNUw0jeNVh+xfwrbR6Ik6IleAyzwHNYKzedGVQ== dependencies: - "@sentry/hub" "6.2.2" - "@sentry/types" "6.2.2" + "@sentry/types" "6.3.0" + "@sentry/utils" "6.3.0" + localforage "^1.8.1" tslib "^1.9.3" -"@sentry/react@^6.2.2": - version "6.2.2" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-6.2.2.tgz#6a93fa1013b2b9e37a8c0bc16cf0cbf4353de4c6" - integrity sha512-yDuxPOD4j2WE5nX1p48GIqXwrrmwkjryFjtYvLgzGJkiGWLmGTrxrSqtUKrbqahJpKt3mi24Nkg0cMlsFB178g== +"@sentry/minimal@6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.3.0.tgz#e64d87c92a4676a11168672a96589f46985f2b22" + integrity sha512-ZdPUwdPQkaKroy67NkwQRqmnfKyd/C1OyouM9IqYKyBjAInjOijwwc/Rd91PMHalvCOGfp1scNZYbZ+YFs/qQQ== dependencies: - "@sentry/browser" "6.2.2" - "@sentry/minimal" "6.2.2" - "@sentry/types" "6.2.2" - "@sentry/utils" "6.2.2" + "@sentry/hub" "6.3.0" + "@sentry/types" "6.3.0" + tslib "^1.9.3" + +"@sentry/react@^6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-6.3.0.tgz#97763bf006991460126fa7235ebc662cd340f804" + integrity sha512-5+Q2p65WMxslaW96209wUp0kfqT0HTyVV+4TTCIOA6Aj3rnKesQaR44mXHXlQVTQh2/8fk1PTkMEsvWJdSPkjA== + dependencies: + "@sentry/browser" "6.3.0" + "@sentry/minimal" "6.3.0" + "@sentry/types" "6.3.0" + "@sentry/utils" "6.3.0" hoist-non-react-statics "^3.3.2" tslib "^1.9.3" -"@sentry/types@6.2.2": - version "6.2.2" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.2.2.tgz#9fc7795156680d3da5fc6ecc66702d8f7917f2b1" - integrity sha512-Y/1sRtw3a5JU4YdNBig8lLSVJ1UdYtuge+QP1CVLcLSAbq07Ok1bvF+Z+BlNcnHqle2Fl8aKuryG5Yu86enOyQ== +"@sentry/types@6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.3.0.tgz#919cc1870f34b7126546c77e3c695052795d3add" + integrity sha512-xWyCYDmFPjS5ex60kxOOHbHEs4vs00qHbm0iShQfjl4OSg9S2azkcWofDmX8Xbn0FSOUXgdPCjNJW1B0bPVhCA== -"@sentry/utils@6.2.2": - version "6.2.2" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.2.2.tgz#69f7151db74e65a010cec062cc9ab3e30bf2c80a" - integrity sha512-qaee6X6VDNZ8HeO83/veaKw0KuhDE7j1R+Yryme3PywFzsoTzutDrEQjb7gvcHAhBaAYX8IHUBHgxcFI9BxI+w== +"@sentry/utils@6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.3.0.tgz#e28645b6d4acd03a478e58bfe112ea02f81e94a0" + integrity sha512-NZzw4oLelgvCsVBG2e+ZtFtaBvgA7rZYtcGFbZTphhAlYoJ6JMCQUzYk0iwJK79yR1quh510x4UE0jynvvToWg== dependencies: - "@sentry/types" "6.2.2" + "@sentry/types" "6.3.0" tslib "^1.9.3" "@sinonjs/commons@^1.7.0": @@ -5680,6 +5690,11 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w== +err-code@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + err-code@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/err-code/-/err-code-3.0.1.tgz#a444c7b992705f2b120ee320b09972eef331c920" @@ -7121,6 +7136,11 @@ ignore@^5.1.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= + immer@8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656" @@ -8390,6 +8410,13 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +lie@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4= + dependencies: + immediate "~3.0.5" + line-column@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/line-column/-/line-column-1.0.2.tgz#d25af2936b6f4849172b312e4792d1d987bc34a2" @@ -8445,6 +8472,13 @@ loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: emojis-list "^3.0.0" json5 "^1.0.1" +localforage@^1.8.1: + version "1.9.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.9.0.tgz#f3e4d32a8300b362b4634cc4e066d9d00d2f09d1" + integrity sha512-rR1oyNrKulpe+VM9cYmcFn6tsHuokyVHFaCM3+osEmxaHTbEk8oQu6eGDfS6DQLWi/N67XRmB8ECG37OES368g== + dependencies: + lie "3.1.1" + locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -11756,6 +11790,7 @@ simple-peer@feross/simple-peer#694/head: resolved "https://codeload.github.com/feross/simple-peer/tar.gz/0d08d07b83ff3b8c60401688d80642d24dfeffe2" dependencies: debug "^4.0.1" + err-code "^2.0.3" get-browser-rtc "^1.0.0" queue-microtask "^1.1.0" randombytes "^2.0.3" From e0e90ff0e5d06857fba39c686567d54800649db3 Mon Sep 17 00:00:00 2001 From: Nicola Thouliss Date: Fri, 14 May 2021 14:15:54 +1000 Subject: [PATCH 02/31] Added dedupe integration to sentry in index.js --- src/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.js b/src/index.js index d21cd5b..f505727 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,7 @@ import React from "react"; import ReactDOM from "react-dom"; import * as Sentry from "@sentry/react"; +import Dedupe from "@sentry/integrations"; import App from "./App"; import Modal from "react-modal"; @@ -20,6 +21,7 @@ if (process.env.REACT_APP_LOGGING === "true") { Sentry.init({ dsn: process.env.REACT_APP_SENTRY_DSN, release: "owlbear-rodeo@" + process.env.REACT_APP_VERSION, + integrations: [new Dedupe()], // Ignore resize error as it is triggered by going fullscreen on slower computers // Ignore quota error // Ignore XDR encoding failure bug in Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1678243 From 265f04fc0a5bfccdba8e2aefbfc95e41f720bb63 Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Mon, 14 Jun 2021 11:57:08 +1000 Subject: [PATCH 03/31] Add toasts for unable to draw fog errors --- src/components/map/Map.js | 4 +++ src/components/map/MapFog.js | 60 +++++++++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/components/map/Map.js b/src/components/map/Map.js index 33fa62d..af5e9bc 100644 --- a/src/components/map/Map.js +++ b/src/components/map/Map.js @@ -1,5 +1,6 @@ import React, { useState } from "react"; import { Box } from "theme-ui"; +import { useToasts } from "react-toast-notifications"; import MapControls from "./MapControls"; import MapInteraction from "./MapInteraction"; @@ -49,6 +50,8 @@ function Map({ disabledTokens, session, }) { + const { addToast } = useToasts(); + const { tokensById } = useTokenData(); const [selectedToolId, setSelectedToolId] = useState("move"); @@ -232,6 +235,7 @@ function Map({ onShapesCut={handleFogShapesCut} onShapesRemove={handleFogShapesRemove} onShapesEdit={handleFogShapesEdit} + onShapeError={addToast} active={selectedToolId === "fog"} toolSettings={settings.fog} editable={allowFogDrawing && !settings.fog.preview} diff --git a/src/components/map/MapFog.js b/src/components/map/MapFog.js index 3e94081..f62fadf 100644 --- a/src/components/map/MapFog.js +++ b/src/components/map/MapFog.js @@ -38,8 +38,10 @@ import { Tick, getRelativePointerPosition, } from "../../helpers/konva"; +import { keyBy } from "../../helpers/shared"; import SubtractShapeAction from "../../actions/SubtractShapeAction"; +import CutShapeAction from "../../actions/CutShapeAction"; import useSetting from "../../hooks/useSetting"; @@ -52,6 +54,7 @@ function MapFog({ onShapesCut, onShapesRemove, onShapesEdit, + onShapeError, active, toolSettings, editable, @@ -214,6 +217,8 @@ function MapFog({ ) { const cut = toolSettings.useFogCut; let drawingShapes = [drawingShape]; + + // Filter out hidden or visible shapes if single layer enabled if (!toolSettings.multilayer) { const shapesToSubtract = shapes.filter((shape) => cut ? !shape.visible : shape.visible @@ -228,22 +233,32 @@ function MapFog({ } if (drawingShapes.length > 0) { - drawingShapes = drawingShapes.map((shape) => { - if (cut) { - return { - id: shape.id, - type: shape.type, - data: shape.data, - }; - } else { - return { ...shape, color: "black" }; - } - }); - if (cut) { - onShapesCut(drawingShapes); + // Run a pre-emptive cut action to check whether we've cut anything + const cutAction = new CutShapeAction(drawingShapes); + const state = cutAction.execute(keyBy(shapes, "id")); + + if (Object.keys(state).length === shapes.length) { + onShapeError("No fog found to cut"); + } else { + onShapesCut( + drawingShapes.map((shape) => ({ + id: shape.id, + type: shape.type, + data: shape.data, + })) + ); + } } else { - onShapesAdd(drawingShapes); + onShapesAdd( + drawingShapes.map((shape) => ({ ...shape, color: "black" })) + ); + } + } else { + if (cut) { + onShapeError("Fog already cut"); + } else { + onShapeError("Fog already placed"); } } setDrawingShape(null); @@ -373,6 +388,7 @@ function MapFog({ }; let polygonShapes = [polygonShape]; + // Filter out hidden or visible shapes if single layer enabled if (!toolSettings.multilayer) { const shapesToSubtract = shapes.filter((shape) => cut ? !shape.visible : shape.visible @@ -388,7 +404,15 @@ function MapFog({ if (polygonShapes.length > 0) { if (cut) { - onShapesCut(polygonShapes); + // Run a pre-emptive cut action to check whether we've cut anything + const cutAction = new CutShapeAction(polygonShapes); + const state = cutAction.execute(keyBy(shapes, "id")); + + if (Object.keys(state).length === shapes.length) { + onShapeError("No fog found to cut"); + } else { + onShapesCut(polygonShapes); + } } else { onShapesAdd( polygonShapes.map((shape) => ({ @@ -399,6 +423,12 @@ function MapFog({ })) ); } + } else { + if (cut) { + onShapeError("Fog already cut"); + } else { + onShapeError("Fog already placed"); + } } setDrawingShape(null); From 64dfb17fa15cc0e68f3bb14a14df0937bd6191b2 Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Mon, 14 Jun 2021 12:20:06 +1000 Subject: [PATCH 04/31] Move mouse tile drag to a distance constraint --- src/contexts/TileDragContext.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contexts/TileDragContext.js b/src/contexts/TileDragContext.js index 6f6644e..a146846 100644 --- a/src/contexts/TileDragContext.js +++ b/src/contexts/TileDragContext.js @@ -61,7 +61,7 @@ export function TileDragProvider({ } = useGroup(); const mouseSensor = useSensor(MouseSensor, { - activationConstraint: { delay: 250, tolerance: 5 }, + activationConstraint: { distance: 5 }, }); const touchSensor = useSensor(TouchSensor, { activationConstraint: { delay: 250, tolerance: 5 }, From 63421f824ac57167014569f7c62b717164934582 Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Mon, 14 Jun 2021 12:21:08 +1000 Subject: [PATCH 05/31] Fix fog useCallback dependency --- src/components/map/MapFog.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/map/MapFog.js b/src/components/map/MapFog.js index f62fadf..3d1d988 100644 --- a/src/components/map/MapFog.js +++ b/src/components/map/MapFog.js @@ -432,7 +432,14 @@ function MapFog({ } setDrawingShape(null); - }, [toolSettings, drawingShape, onShapesCut, onShapesAdd, shapes]); + }, [ + toolSettings, + drawingShape, + onShapesCut, + onShapesAdd, + onShapeError, + shapes, + ]); // Add keyboard shortcuts function handleKeyDown(event) { From 0fbd837449d7025c80410fa7359b4325ed1ff26a Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Mon, 14 Jun 2021 13:47:21 +1000 Subject: [PATCH 06/31] Fix global image drop outside triggering drag end --- src/components/image/GlobalImageDrop.js | 44 ++++++++++++++++++------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/src/components/image/GlobalImageDrop.js b/src/components/image/GlobalImageDrop.js index b1909e6..10efcd6 100644 --- a/src/components/image/GlobalImageDrop.js +++ b/src/components/image/GlobalImageDrop.js @@ -1,5 +1,5 @@ import React, { useState, useRef } from "react"; -import { Flex, Text } from "theme-ui"; +import { Box, Flex, Text } from "theme-ui"; import { useToasts } from "react-toast-notifications"; import LoadingOverlay from "../LoadingOverlay"; @@ -171,39 +171,61 @@ function GlobalImageDrop({ children, onMapChange, onMapTokensStateCreate }) { {...overlayListeners} > + Drop as map + Drop as token From 1e2619345782c9977108ce5766a9a88b3a9ded85 Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Mon, 14 Jun 2021 15:18:07 +1000 Subject: [PATCH 07/31] Optimise token database sync and add loading indicator for multiple token hiding --- src/components/map/MapTiles.js | 34 ++++++++++++++----------- src/components/token/TokenEditBar.js | 9 ++++++- src/components/token/TokenTiles.js | 38 +++++++++++++++------------- src/contexts/TokenDataContext.js | 37 +++++++++++++++++---------- 4 files changed, 72 insertions(+), 46 deletions(-) diff --git a/src/components/map/MapTiles.js b/src/components/map/MapTiles.js index 3adeba6..044575e 100644 --- a/src/components/map/MapTiles.js +++ b/src/components/map/MapTiles.js @@ -20,21 +20,25 @@ function MapTiles({ mapsById, onMapEdit, onMapSelect, subgroup }) { function renderTile(group) { if (group.type === "item") { const map = mapsById[group.id]; - const isSelected = selectedGroupIds.includes(group.id); - const canEdit = - isSelected && selectMode === "single" && selectedGroupIds.length === 1; - return ( - canEdit && onMapSelect(group.id)} - canEdit={canEdit} - badges={[`${map.grid.size.x}x${map.grid.size.y}`]} - /> - ); + if (map) { + const isSelected = selectedGroupIds.includes(group.id); + const canEdit = + isSelected && + selectMode === "single" && + selectedGroupIds.length === 1; + return ( + canEdit && onMapSelect(group.id)} + canEdit={canEdit} + badges={[`${map.grid.size.x}x${map.grid.size.y}`]} + /> + ); + } } else { const isSelected = selectedGroupIds.includes(group.id); const items = getGroupItems(group); diff --git a/src/components/token/TokenEditBar.js b/src/components/token/TokenEditBar.js index a759739..1150269 100644 --- a/src/components/token/TokenEditBar.js +++ b/src/components/token/TokenEditBar.js @@ -48,7 +48,14 @@ function TokenEditBar({ disabled, onLoad }) { async function handleTokensHide(hideInSidebar) { const selectedTokens = getSelectedTokens(); const selectedTokenIds = selectedTokens.map((token) => token.id); - updateTokensHidden(selectedTokenIds, hideInSidebar); + // Show loading indicator if hiding more than 10 tokens + if (selectedTokenIds.length > 10) { + onLoad(true); + await updateTokensHidden(selectedTokenIds, hideInSidebar); + onLoad(false); + } else { + updateTokensHidden(selectedTokenIds, hideInSidebar); + } } /** diff --git a/src/components/token/TokenTiles.js b/src/components/token/TokenTiles.js index 02d5059..e61277c 100644 --- a/src/components/token/TokenTiles.js +++ b/src/components/token/TokenTiles.js @@ -21,24 +21,28 @@ function TokenTiles({ tokensById, onTokenEdit, subgroup }) { function renderTile(group) { if (group.type === "item") { const token = tokensById[group.id]; - const isSelected = selectedGroupIds.includes(group.id); - const canEdit = - isSelected && selectMode === "single" && selectedGroupIds.length === 1; + if (token) { + const isSelected = selectedGroupIds.includes(group.id); + const canEdit = + isSelected && + selectMode === "single" && + selectedGroupIds.length === 1; - return ( -