From f636fc72f836fcadf80a44af54b1925e61fc6ebc Mon Sep 17 00:00:00 2001 From: Cristian Necula Date: Fri, 15 Oct 2021 12:00:54 +0300 Subject: [PATCH] feat: save settings locally Re RM:27156 Re #418 --- cosmoz-omnitable.js | 14 +++++++--- demo/helpers/x-page.js | 2 +- lib/cosmoz-omnitable-settings.js | 37 +++++++++++++++++++++----- lib/normalize-settings.js | 31 +++++++++++++++------- lib/use-omnitable.js | 11 +++++--- lib/use-saved-settings.js | 45 ++++++++++++++++++++++++++++++++ 6 files changed, 118 insertions(+), 22 deletions(-) create mode 100644 lib/use-saved-settings.js diff --git a/cosmoz-omnitable.js b/cosmoz-omnitable.js index 5f6e758d..25d6369c 100644 --- a/cosmoz-omnitable.js +++ b/cosmoz-omnitable.js @@ -64,7 +64,7 @@ class Omnitable extends hauntedPolymer(useOmnitable)(mixin({ isEmpty }, translat
@@ -411,6 +411,10 @@ class Omnitable extends hauntedPolymer(useOmnitable)(mixin({ isEmpty }, translat }, computedBarHeight: { type: Number + }, + settingsId: { + type: String, + value: undefined } }; } @@ -1281,11 +1285,15 @@ class Omnitable extends hauntedPolymer(useOmnitable)(mixin({ isEmpty }, translat }; } - _renderSettings(normalizedSettings, collapsed) { + _renderSettings(normalizedSettings, collapsed, settingsId, hasChangedSettings) { return litHtml` c.name) } + .collapsed=${ collapsed?.map(c => c.name) } + .settingsId=${ settingsId } + .hasChanges=${ hasChangedSettings } + .onSave=${ this.onSettingsSave } + .onReset=${ this.onSettingsReset } >`; } } diff --git a/demo/helpers/x-page.js b/demo/helpers/x-page.js index c51b66ae..a180d83e 100644 --- a/demo/helpers/x-page.js +++ b/demo/helpers/x-page.js @@ -69,7 +69,7 @@ class XPage extends translatable(PolymerElement) { + hash-param="[[ hashParam ]]" settings-id="test"> button { + flex: 1; + } + .footer > button:first-child { + margin-right: 5px; + } `, parseIndex = str => { @@ -75,6 +86,11 @@ const settingsStyles = ` settings: host.settings, collapsed: host.collapsed, + settingsId: host.settingsId, + hasChanges: host.hasChanges, + onSave: host.onSave, + onReset: host.onReset, + onDown: useCallback(e => { if (!e.target.closest('.sort')) { return; @@ -169,15 +185,23 @@ const settingsStyles = ` }, SettingsUI = host => { - const { settings, ...thru } = useSettings(host); - return html` - -
${ settings.map(renderItem(thru)) }
`; - + const { settings, settingsId, onSave, onReset, hasChanges, ...thru } = useSettings(host); + return [ + html` + +
${ settings.map(renderItem(thru)) }
+ `, + settingsId + ? html`` + : nothing + ]; }, Settings = host => { - const { settings, onSettings, collapsed } = host, + const { settings, onSettings, onSave, onReset, collapsed, settingsId, hasChanges } = host, { active, onFocus, onToggle } = useFocus(host), anchor = useCallback(() => host.shadowRoot.querySelector('.anchor'), []); @@ -204,6 +228,7 @@ const settingsStyles = ` ${ active ? portal(html``) : [] } `; diff --git a/lib/normalize-settings.js b/lib/normalize-settings.js index 7fedf17e..269650b9 100644 --- a/lib/normalize-settings.js +++ b/lib/normalize-settings.js @@ -1,16 +1,29 @@ +const byName = name => item => item.name === name; + export const columnSymbol = Symbol('column'), - normalizeSettings = (columns = [], settings = []) => { - const cols = columns.slice(); - for (const setting of settings) { - const idx = cols.findIndex(c => c.name === setting.name); - if (idx < 0) { - continue; - } - cols.splice(idx, 1); - } + normalizeSettings = (columns = [], settings = [], savedSettings = []) => { + const + cols = columns.filter(column => !settings.some(byName(column.name)) && !savedSettings.some(byName(column.name))), + _savedSettings = savedSettings.filter(column => !settings.some(byName(column.name))); + return [ ...settings, + ..._savedSettings + .flatMap(setting => { + const column = columns.find(c => c.name === setting.name); + + if (!column) { + return []; + } + + return { + ...setting, + title: column.title, + minWidth: parseInt(column.minWidth, 10), + [columnSymbol]: column + }; + }), ...cols.map(column => { const { name, title, priority, minWidth, width, flex } = column; return { diff --git a/lib/use-omnitable.js b/lib/use-omnitable.js index 93629fea..f1e9e564 100644 --- a/lib/use-omnitable.js +++ b/lib/use-omnitable.js @@ -1,13 +1,15 @@ import { useMemo, useState } from 'haunted'; import { columnSymbol, normalizeSettings } from './normalize-settings'; import { useFastLayout } from './use-fast-layout'; +import { useSavedSettings } from './use-saved-settings'; // eslint-disable-next-line max-lines-per-function export const useOmnitable = host => { const - { columns, groupOnColumn, resizeSpeedFactor } = host, + { columns, groupOnColumn, resizeSpeedFactor, settingsId } = host, [settings, setSettings] = useState([]), - normalizedSettings = useMemo(() => normalizeSettings(columns, settings), [columns, settings]), + { savedSettings, onSettingsSave, onSettingsReset, hasChangedSettings } = useSavedSettings(settingsId, settings, setSettings), + normalizedSettings = useMemo(() => normalizeSettings(columns, settings, savedSettings), [columns, settings, savedSettings]), normalizedColumns = useMemo(() => normalizedSettings.map(s => s[columnSymbol]), [columns, ...normalizedSettings.map(s => s.name)]), { layoutCss, collapsedColumns } = useFastLayout({ host, settings: normalizedSettings, setSettings, groupOnColumn, resizeSpeedFactor }); @@ -16,6 +18,9 @@ export const useOmnitable = host => { setSettings, normalizedSettings, normalizedColumns, - collapsedColumns + collapsedColumns, + onSettingsSave, + onSettingsReset, + hasChangedSettings }; }; diff --git a/lib/use-saved-settings.js b/lib/use-saved-settings.js new file mode 100644 index 00000000..191e9e6c --- /dev/null +++ b/lib/use-saved-settings.js @@ -0,0 +1,45 @@ +import { useCallback, useMemo, useState } from 'haunted'; +import { omit } from '@neovici/cosmoz-utils/lib/object'; + +const storagePrefix = 'omnitable-'; + +export const useSavedSettings = (settingsId, settings, setSettings) => { + const + [counter, setCounter] = useState(0), + savedSettings = useMemo(() => { + if (!settingsId) { + return []; + } + + try { + return JSON.parse(localStorage.getItem(storagePrefix + settingsId)) ?? []; + } catch (e) { + return []; + } + }, [settingsId, counter]); + + return { + savedSettings, + + onSettingsSave: useCallback(() => { + if (!settingsId) { + return; + } + + try { + localStorage.setItem(storagePrefix + settingsId, JSON.stringify(settings.map(omit(['title', 'minWidth'])))); + setSettings([]); + setCounter(counter => counter + 1); + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + } + }, [settings]), + + onSettingsReset: () => { + setSettings([]); + }, + + hasChangedSettings: settings.length !== 0 + }; +};