From ccc164ee1433c1a4c85db095c904ac8620549564 Mon Sep 17 00:00:00 2001 From: Tim Alyakin <31693137+TimSPb89@users.noreply.github.com> Date: Wed, 25 Jan 2023 15:31:37 +0300 Subject: [PATCH] #1818: Persist user settings (#2097) * #1818 - Persist user settings * #1818 - fixed missing check * #2033 - review fix * #2033 - one more place to restore saved selection tool --- packages/ketcher-react/src/constants.ts | 2 + .../src/script/ui/action/index.js | 7 ++- .../src/script/ui/state/action/index.js | 10 +++- .../src/script/ui/state/hotkeys.ts | 4 +- .../src/script/ui/state/shared.ts | 4 +- .../src/script/ui/utils/settingsManager.ts | 55 +++++++++++++++++++ .../ToolbarMultiToolItem.tsx | 23 ++++++-- 7 files changed, 96 insertions(+), 9 deletions(-) create mode 100644 packages/ketcher-react/src/script/ui/utils/settingsManager.ts diff --git a/packages/ketcher-react/src/constants.ts b/packages/ketcher-react/src/constants.ts index 187613bec9..38ff054622 100644 --- a/packages/ketcher-react/src/constants.ts +++ b/packages/ketcher-react/src/constants.ts @@ -15,3 +15,5 @@ ***************************************************************************/ export const KETCHER_INIT_EVENT_NAME = 'ketcher-init' + +export const KETCHER_SAVED_SETTINGS_KEY = 'ketcher_editor_saved_settings' diff --git a/packages/ketcher-react/src/script/ui/action/index.js b/packages/ketcher-react/src/script/ui/action/index.js index 6387c70890..c96aeb6ea1 100644 --- a/packages/ketcher-react/src/script/ui/action/index.js +++ b/packages/ketcher-react/src/script/ui/action/index.js @@ -27,6 +27,7 @@ import zoom from './zoom' import help from './help' import functionalGroups from './functionalGroups' import fullscreen from './fullscreen' +import { SettingsManager } from '../utils/settingsManager' export * from './action.types' @@ -38,7 +39,11 @@ const config = { thunk: (dispatch, getState) => { const editor = getState().editor if (!editor.struct().isBlank()) editor.struct(null) - dispatch({ type: 'ACTION', action: tools['select-rectangle'].action }) + const savedSelectedTool = SettingsManager.selectionTool + dispatch({ + type: 'ACTION', + action: savedSelectedTool || tools['select-rectangle'].action + }) } }, hidden: (options) => isHidden(options, 'clear') diff --git a/packages/ketcher-react/src/script/ui/state/action/index.js b/packages/ketcher-react/src/script/ui/state/action/index.js index 7a243d753f..7b2fb9853e 100644 --- a/packages/ketcher-react/src/script/ui/state/action/index.js +++ b/packages/ketcher-react/src/script/ui/state/action/index.js @@ -16,6 +16,7 @@ import { isEmpty, isEqual, pickBy } from 'lodash/fp' +import { SettingsManager } from '../../utils/settingsManager' import actions from '../../action' function execute(activeTool, { action, editor, server, options }) { @@ -62,13 +63,18 @@ function status(actionName, activeTool, params) { export default function (state = null, { type, action, ...params }) { let activeTool switch (type) { - case 'INIT': - action = actions['select-rectangle'].action + case 'INIT': { + const savedSelectedTool = SettingsManager.selectionTool + action = savedSelectedTool || actions['select-rectangle'].action + } case 'ACTION': activeTool = execute(state && state.activeTool, { ...params, action }) + if (activeTool.tool === 'select') { + SettingsManager.selectionTool = activeTool + } case 'UPDATE': return Object.keys(actions).reduce( (res, actionName) => { diff --git a/packages/ketcher-react/src/script/ui/state/hotkeys.ts b/packages/ketcher-react/src/script/ui/state/hotkeys.ts index da5ec75c92..4001cc4544 100644 --- a/packages/ketcher-react/src/script/ui/state/hotkeys.ts +++ b/packages/ketcher-react/src/script/ui/state/hotkeys.ts @@ -32,6 +32,7 @@ import keyNorm from '../data/convert/keynorm' import { openDialog } from './modal' import { isIE } from 'react-device-detect' import { handleHotkeyOverAtom } from './handleHotkeysOverAtom' +import { SettingsManager } from '../utils/settingsManager' export function initKeydownListener(element) { return function (dispatch, getState) { @@ -45,9 +46,10 @@ export function initKeydownListener(element) { function removeNotRenderedStruct(actionTool, event, dispatch) { const { code, metaKey } = event if (actionTool.tool === 'paste' && code === 'KeyS' && metaKey) { + const savedSelectedTool = SettingsManager.selectionTool dispatch({ type: 'ACTION', - action: tools['select-rectangle'].action + action: savedSelectedTool || tools['select-rectangle'].action }) } } diff --git a/packages/ketcher-react/src/script/ui/state/shared.ts b/packages/ketcher-react/src/script/ui/state/shared.ts index 1df8dbbe12..24a7b154d6 100644 --- a/packages/ketcher-react/src/script/ui/state/shared.ts +++ b/packages/ketcher-react/src/script/ui/state/shared.ts @@ -27,6 +27,7 @@ import { import { supportedSGroupTypes } from './constants' import { setAnalyzingFile } from './request' import tools from '../action/tools' +import { SettingsManager } from '../utils/settingsManager' export function onAction(action) { if (action && action.dialog) { @@ -142,9 +143,10 @@ export function load(struct: Struct, options?) { if (fragment) { if (parsedStruct.isBlank()) { + const savedSelectedTool = SettingsManager.selectionTool dispatch({ type: 'ACTION', - action: tools['select-rectangle'].action + action: savedSelectedTool || tools['select-rectangle'].action }) } else { dispatch(onAction({ tool: 'paste', opts: parsedStruct })) diff --git a/packages/ketcher-react/src/script/ui/utils/settingsManager.ts b/packages/ketcher-react/src/script/ui/utils/settingsManager.ts new file mode 100644 index 0000000000..7f7145ea9b --- /dev/null +++ b/packages/ketcher-react/src/script/ui/utils/settingsManager.ts @@ -0,0 +1,55 @@ +/**************************************************************************** + * Copyright 2021 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ + +import { KETCHER_SAVED_SETTINGS_KEY } from '../../../constants' + +interface SavedSettings { + selectionTool?: any +} + +export class SettingsManager { + static getSettings(): SavedSettings { + try { + return JSON.parse( + localStorage.getItem(KETCHER_SAVED_SETTINGS_KEY) || '{}' + ) + } catch (e) { + return {} as SavedSettings + } + } + + static saveSettings(settings: SavedSettings) { + if (!settings) { + return + } + localStorage.setItem(KETCHER_SAVED_SETTINGS_KEY, JSON.stringify(settings)) + } + + static get selectionTool() { + const { selectionTool } = this.getSettings() + + return selectionTool + } + + static set selectionTool(selectionTool) { + const settings = this.getSettings() + + this.saveSettings({ + ...settings, + selectionTool + }) + } +} diff --git a/packages/ketcher-react/src/script/ui/views/toolbars/ToolbarGroupItem/ToolbarMultiToolItem/ToolbarMultiToolItem.tsx b/packages/ketcher-react/src/script/ui/views/toolbars/ToolbarGroupItem/ToolbarMultiToolItem/ToolbarMultiToolItem.tsx index e6ea3aaabe..9b80fb59a7 100644 --- a/packages/ketcher-react/src/script/ui/views/toolbars/ToolbarGroupItem/ToolbarMultiToolItem/ToolbarMultiToolItem.tsx +++ b/packages/ketcher-react/src/script/ui/views/toolbars/ToolbarGroupItem/ToolbarMultiToolItem/ToolbarMultiToolItem.tsx @@ -23,14 +23,15 @@ import { GroupDescriptor, MultiToolVariant } from './variants/variants.types' import { ToolbarItem, ToolbarItemVariant } from '../../toolbar.types' import action, { UiAction, UiActionAction } from '../../../../action' +import { useRef } from 'react' +import clsx from 'clsx' import Icon from '../../../../component/view/icon' import { Portal } from '../../../../Portal' import { chooseMultiTool } from './variants/chooseMultiTool' import classes from './ToolbarMultiToolItem.module.less' -import clsx from 'clsx' import { usePortalOpening } from './usePortalOpening' import { usePortalStyle } from './usePortalStyle' -import { useRef } from 'react' +import { SettingsManager } from '../../../../utils/settingsManager' interface ToolbarMultiToolItemProps { id: ToolbarItemVariant @@ -97,9 +98,23 @@ const ToolbarMultiToolItem = (props: Props) => { const displayMultiToolItem = !(allInnerItemsHidden || currentStatus?.hidden) if (!currentStatus && options.length) { + const savedSelectionTool = SettingsManager.selectionTool + const savedSelectionToolId = + savedSelectionTool && + `${savedSelectionTool.tool}-${savedSelectionTool.opts}` currentId = - options.filter((option) => !status[option.id]?.hidden)[0]?.id || - options[0].id + savedSelectionTool && + savedSelectionToolId && + options.filter( + (option) => + !status[option.id]?.hidden && option.id === savedSelectionToolId + )[0]?.id + + if (!currentId) { + currentId = + options.filter((option) => !status[option.id]?.hidden)[0]?.id || + options[0].id + } } const actionButtonProps: Omit<