From 860d8742a6c77a99a0f5d23a13f54bcbef17c193 Mon Sep 17 00:00:00 2001 From: Philipp Otto Date: Fri, 2 Aug 2019 15:57:21 +0200 Subject: [PATCH 1/4] prefix local storage access with user email address --- .../javascripts/dashboard/dashboard_view.js | 5 +-- .../javascripts/dashboard/dataset_view.js | 7 ++-- .../dashboard/explorative_annotations_view.js | 7 ++-- .../javascripts/libs/user_local_storage.js | 32 +++++++++++++++++++ .../view/action-bar/add_new_layout_modal.js | 14 +++++--- .../view/layouting/layout_persistence.js | 22 ++++++++++--- .../view/layouting/tracing_layout_view.js | 2 +- 7 files changed, 70 insertions(+), 19 deletions(-) create mode 100644 frontend/javascripts/libs/user_local_storage.js diff --git a/frontend/javascripts/dashboard/dashboard_view.js b/frontend/javascripts/dashboard/dashboard_view.js index 38e0af2ade8..03fe9dc30f4 100644 --- a/frontend/javascripts/dashboard/dashboard_view.js +++ b/frontend/javascripts/dashboard/dashboard_view.js @@ -14,6 +14,7 @@ import DatasetView from "dashboard/dataset_view"; import ExplorativeAnnotationsView from "dashboard/explorative_annotations_view"; import NmlUploadZoneContainer from "oxalis/view/nml_upload_zone_container"; import Request from "libs/request"; +import UserLocalStorage from "libs/user_local_storage"; const { TabPane } = Tabs; @@ -45,7 +46,7 @@ class DashboardView extends React.PureComponent { const validTabKeys = this.getValidTabKeys(); const { initialTabKey } = this.props; - const lastUsedTabKey = localStorage.getItem("lastUsedDashboardTab"); + const lastUsedTabKey = UserLocalStorage.getItem("lastUsedDashboardTab"); const defaultTabKey = this.props.isAdminView ? "tasks" : "datasets"; // Flow doesn't allow validTabKeys[key] where key may be null, so check that first @@ -132,7 +133,7 @@ class DashboardView extends React.PureComponent { const tabKeyToURLMap = _.invert(urlTokenToTabKeyMap); const url = tabKeyToURLMap[activeTabKey]; if (url) { - localStorage.setItem("lastUsedDashboardTab", activeTabKey); + UserLocalStorage.setItem("lastUsedDashboardTab", activeTabKey); if (!this.props.isAdminView) { this.props.history.push(`/dashboard/${url}`); } diff --git a/frontend/javascripts/dashboard/dataset_view.js b/frontend/javascripts/dashboard/dataset_view.js index 8c2aa97a04c..031f8e7b608 100644 --- a/frontend/javascripts/dashboard/dataset_view.js +++ b/frontend/javascripts/dashboard/dataset_view.js @@ -14,6 +14,7 @@ import Persistence from "libs/persistence"; import SampleDatasetsModal from "dashboard/dataset/sample_datasets_modal"; import * as Utils from "libs/utils"; import renderIndependently from "libs/render_independently"; +import UserLocalStorage from "libs/user_local_storage"; const { Search, Group: InputGroup } = Input; @@ -46,13 +47,13 @@ const persistence: Persistence = new Persistence( export const wkDatasetsCacheKey = "wk.datasets"; export const datasetCache = { set(datasets: APIMaybeUnimportedDataset[]): void { - localStorage.setItem(wkDatasetsCacheKey, JSON.stringify(datasets)); + UserLocalStorage.setItem(wkDatasetsCacheKey, JSON.stringify(datasets)); }, get(): APIMaybeUnimportedDataset[] { - return Utils.parseAsMaybe(localStorage.getItem(wkDatasetsCacheKey)).getOrElse([]); + return Utils.parseAsMaybe(UserLocalStorage.getItem(wkDatasetsCacheKey)).getOrElse([]); }, clear(): void { - localStorage.removeItem(wkDatasetsCacheKey); + UserLocalStorage.removeItem(wkDatasetsCacheKey); }, }; diff --git a/frontend/javascripts/dashboard/explorative_annotations_view.js b/frontend/javascripts/dashboard/explorative_annotations_view.js index 4a4dc9a827a..7c49539aa3a 100644 --- a/frontend/javascripts/dashboard/explorative_annotations_view.js +++ b/frontend/javascripts/dashboard/explorative_annotations_view.js @@ -30,6 +30,7 @@ import Toast from "libs/toast"; import * as Utils from "libs/utils"; import messages from "messages"; import { trackAction } from "oxalis/model/helpers/analytics"; +import UserLocalStorage from "libs/user_local_storage"; const { Column } = Table; const { Search } = Input; @@ -99,7 +100,7 @@ class ExplorativeAnnotationsView extends React.PureComponent { restoreSearchTags() { // restore the search query tags from the last session - const searchTagString = localStorage.getItem("lastDashboardSearchTags"); + const searchTagString = UserLocalStorage.getItem("lastDashboardSearchTags"); if (searchTagString) { try { const searchTags = JSON.parse(searchTagString); @@ -297,7 +298,7 @@ class ExplorativeAnnotationsView extends React.PureComponent { if (!this.state.tags.includes(tag)) { this.setState(prevState => { const newTags = update(prevState.tags, { $push: [tag] }); - localStorage.setItem("lastDashboardSearchTags", JSON.stringify(newTags)); + UserLocalStorage.setItem("lastDashboardSearchTags", JSON.stringify(newTags)); return { tags: newTags }; }); } @@ -306,7 +307,7 @@ class ExplorativeAnnotationsView extends React.PureComponent { removeTagFromSearch = (tag: string): void => { this.setState(prevState => { const newTags = prevState.tags.filter(t => t !== tag); - localStorage.setItem("lastDashboardSearchTags", JSON.stringify(newTags)); + UserLocalStorage.setItem("lastDashboardSearchTags", JSON.stringify(newTags)); return { tags: newTags }; }); }; diff --git a/frontend/javascripts/libs/user_local_storage.js b/frontend/javascripts/libs/user_local_storage.js new file mode 100644 index 00000000000..d5e9f7fa2c6 --- /dev/null +++ b/frontend/javascripts/libs/user_local_storage.js @@ -0,0 +1,32 @@ +// @flow + +import Store from "oxalis/store"; + +function prefixKey(key) { + const { activeUser } = Store.getState(); + console.log("activeUser", activeUser); + const prefix = !activeUser ? "Anonymous" : activeUser.email; + return `${prefix}-${key}`; +} + +const UserLocalStorage = { + getItem(key: string): ?string { + console.log("getting", key); + return localStorage.getItem(prefixKey(key)); + }, + + setItem(key: string, value: string): void { + console.log("setting", key); + return localStorage.setItem(prefixKey(key), value); + }, + + clear(): void { + localStorage.clear(); + }, + + removeItem(key: string): void { + return localStorage.removeItem(key); + }, +}; + +export default UserLocalStorage; diff --git a/frontend/javascripts/oxalis/view/action-bar/add_new_layout_modal.js b/frontend/javascripts/oxalis/view/action-bar/add_new_layout_modal.js index 9d88a639a66..ca41e5011e3 100644 --- a/frontend/javascripts/oxalis/view/action-bar/add_new_layout_modal.js +++ b/frontend/javascripts/oxalis/view/action-bar/add_new_layout_modal.js @@ -18,16 +18,18 @@ class AddNewLayoutModal extends React.PureComponent { value: "", }; + onConfirm = () => { + const value = this.state.value; + this.setState({ value: "" }); + this.props.addLayout(value); + }; + render() { return ( { - const value = this.state.value; - this.setState({ value: "" }); - this.props.addLayout(value); - }} + onOk={this.onConfirm} onCancel={this.props.onCancel} > { onChange={evt => { this.setState({ value: evt.target.value }); }} + autoFocus + onPressEnter={this.onConfirm} /> ); diff --git a/frontend/javascripts/oxalis/view/layouting/layout_persistence.js b/frontend/javascripts/oxalis/view/layouting/layout_persistence.js index 44f83be728c..46835195bef 100644 --- a/frontend/javascripts/oxalis/view/layouting/layout_persistence.js +++ b/frontend/javascripts/oxalis/view/layouting/layout_persistence.js @@ -3,9 +3,11 @@ import NanoEvents from "nanoevents"; import _ from "lodash"; import { getIsInIframe } from "libs/utils"; +import { listenToStoreProperty } from "oxalis/model/helpers/listener_helpers"; import { setStoredLayoutsAction } from "oxalis/model/actions/ui_actions"; import Store from "oxalis/store"; import Toast from "libs/toast"; +import UserLocalStorage from "libs/user_local_storage"; import getDefaultLayouts, { currentLayoutVersion, @@ -25,12 +27,12 @@ const localStorageKeys = { }; function readStoredLayoutConfigs() { - const storedLayoutVersion = localStorage.getItem(localStorageKeys.currentLayoutVersion); + const storedLayoutVersion = UserLocalStorage.getItem(localStorageKeys.currentLayoutVersion); const defaultLayoutConfig = getCurrentDefaultLayoutConfig(); if (getIsInIframe() || !storedLayoutVersion || disableLayoutPersistance) { return defaultLayoutConfig; } - const layoutString = localStorage.getItem(localStorageKeys.goldenWkLayouts); + const layoutString = UserLocalStorage.getItem(localStorageKeys.goldenWkLayouts); if (!layoutString) { return defaultLayoutConfig; } @@ -80,7 +82,14 @@ function readStoredLayoutConfigs() { return defaultLayoutConfig; } -Store.dispatch(setStoredLayoutsAction(readStoredLayoutConfigs())); +listenToStoreProperty( + storeState => storeState.activeUser, + () => { + console.log("Dispatching setStoredLayoutsAction"); + Store.dispatch(setStoredLayoutsAction(readStoredLayoutConfigs())); + }, + true, +); function persistLayoutConfigs() { if (getIsInIframe()) { @@ -88,8 +97,11 @@ function persistLayoutConfigs() { return; } const { storedLayouts } = Store.getState().uiInformation; - localStorage.setItem(localStorageKeys.goldenWkLayouts, JSON.stringify(storedLayouts)); - localStorage.setItem(localStorageKeys.currentLayoutVersion, JSON.stringify(currentLayoutVersion)); + UserLocalStorage.setItem(localStorageKeys.goldenWkLayouts, JSON.stringify(storedLayouts)); + UserLocalStorage.setItem( + localStorageKeys.currentLayoutVersion, + JSON.stringify(currentLayoutVersion), + ); } layoutEmitter.on("resetLayout", (layoutKey: LayoutKeys, activeLayout: string) => { diff --git a/frontend/javascripts/oxalis/view/layouting/tracing_layout_view.js b/frontend/javascripts/oxalis/view/layouting/tracing_layout_view.js index 5455407f9d8..f79f8607a56 100644 --- a/frontend/javascripts/oxalis/view/layouting/tracing_layout_view.js +++ b/frontend/javascripts/oxalis/view/layouting/tracing_layout_view.js @@ -95,7 +95,7 @@ class TracingLayoutView extends React.PureComponent { ) { lastActiveLayout = props.storedLayouts.LastActiveLayouts[layoutType]; } else { - // added as a valide fallback when there are no stored last active layouts + // added as a fallback when there are no stored last active layouts const firstStoredLayout = Object.keys(props.storedLayouts[layoutType])[0]; lastActiveLayout = firstStoredLayout; } From 63964bf12ec0858ec913473d51050e4dc53b14d7 Mon Sep 17 00:00:00 2001 From: Philipp Otto Date: Fri, 2 Aug 2019 16:09:13 +0200 Subject: [PATCH 2/4] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fa05ec931e..1979b243131 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.md). - Fixed a bug where for uint24 color layers, scrambled data was shown for missing magnifications. [#4188](https://github.com/scalableminds/webknossos/pull/4188) - Fixed a bug where collapsing/expanding all tree groups would trigger when toggling a single tree [#4178](https://github.com/scalableminds/webknossos/pull/4178) - Fixed performance for time logging. [#4196](https://github.com/scalableminds/webknossos/pull/4196) +- Personal tracing layouts are saved per user now. [#4217](https://github.com/scalableminds/webknossos/pull/4217) ### Removed - From 028c56cc0aaa8ca34c7a67ca5eb091fa51c8dc78 Mon Sep 17 00:00:00 2001 From: Philipp Otto Date: Wed, 7 Aug 2019 12:54:37 +0200 Subject: [PATCH 3/4] Apply suggestions from code review Co-Authored-By: Daniel --- frontend/javascripts/libs/user_local_storage.js | 3 --- .../javascripts/oxalis/view/layouting/layout_persistence.js | 1 - 2 files changed, 4 deletions(-) diff --git a/frontend/javascripts/libs/user_local_storage.js b/frontend/javascripts/libs/user_local_storage.js index d5e9f7fa2c6..5a12d36488d 100644 --- a/frontend/javascripts/libs/user_local_storage.js +++ b/frontend/javascripts/libs/user_local_storage.js @@ -4,19 +4,16 @@ import Store from "oxalis/store"; function prefixKey(key) { const { activeUser } = Store.getState(); - console.log("activeUser", activeUser); const prefix = !activeUser ? "Anonymous" : activeUser.email; return `${prefix}-${key}`; } const UserLocalStorage = { getItem(key: string): ?string { - console.log("getting", key); return localStorage.getItem(prefixKey(key)); }, setItem(key: string, value: string): void { - console.log("setting", key); return localStorage.setItem(prefixKey(key), value); }, diff --git a/frontend/javascripts/oxalis/view/layouting/layout_persistence.js b/frontend/javascripts/oxalis/view/layouting/layout_persistence.js index 46835195bef..cc74e024c73 100644 --- a/frontend/javascripts/oxalis/view/layouting/layout_persistence.js +++ b/frontend/javascripts/oxalis/view/layouting/layout_persistence.js @@ -85,7 +85,6 @@ function readStoredLayoutConfigs() { listenToStoreProperty( storeState => storeState.activeUser, () => { - console.log("Dispatching setStoredLayoutsAction"); Store.dispatch(setStoredLayoutsAction(readStoredLayoutConfigs())); }, true, From 1d27925428a9a16aeabdfaff3685a367c3f870c0 Mon Sep 17 00:00:00 2001 From: Philipp Otto Date: Wed, 7 Aug 2019 12:57:08 +0200 Subject: [PATCH 4/4] add prefixKey to UserLocalStorage.clear() --- frontend/javascripts/libs/user_local_storage.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/javascripts/libs/user_local_storage.js b/frontend/javascripts/libs/user_local_storage.js index 5a12d36488d..50d19035a1c 100644 --- a/frontend/javascripts/libs/user_local_storage.js +++ b/frontend/javascripts/libs/user_local_storage.js @@ -17,12 +17,12 @@ const UserLocalStorage = { return localStorage.setItem(prefixKey(key), value); }, - clear(): void { - localStorage.clear(); + removeItem(key: string): void { + return localStorage.removeItem(prefixKey(key)); }, - removeItem(key: string): void { - return localStorage.removeItem(key); + clear(): void { + localStorage.clear(); }, };