From 7382bf8ffbb4758e2a6acb3cdc79f841c4282e41 Mon Sep 17 00:00:00 2001 From: Alexander Platov <sas_lord@mail.ru> Date: Tue, 31 Oct 2023 12:21:29 +0300 Subject: [PATCH] UBER-1116: saving sidebar changes (#3919) Signed-off-by: Alexander Platov <sas_lord@mail.ru> --- packages/ui/src/location.ts | 13 +++ .../sidebar/DepartmentsHierarchy.svelte | 3 - .../src/components/sidebar/Sidebar.svelte | 2 +- .../src/components/sidebar/TreeElement.svelte | 94 ------------------- .../projects/ProjectSpacePresenter.svelte | 13 ++- .../components/navigator/TreeElement.svelte | 18 +++- .../src/components/navigator/TreeNode.svelte | 2 +- .../src/components/SavedView.svelte | 7 +- .../src/components/navigator/SpacesNav.svelte | 2 +- .../components/navigator/StarredNav.svelte | 2 +- 10 files changed, 44 insertions(+), 112 deletions(-) delete mode 100644 plugins/hr-resources/src/components/sidebar/TreeElement.svelte diff --git a/packages/ui/src/location.ts b/packages/ui/src/location.ts index d467f82bbb..8ca3aae3df 100644 --- a/packages/ui/src/location.ts +++ b/packages/ui/src/location.ts @@ -186,3 +186,16 @@ export function navigate (location: PlatformLocation, store = true): boolean { } return false } + +const COLLAPSED = 'COLLAPSED' +export const getCollapsedKey = (_id: string): string => `${getCurrentLocation().path[1]}_${_id}_collapsed` + +export const getTreeCollapsed = (_id: any): boolean => { + if (_id === undefined || _id === 'undefined') return false + return localStorage.getItem(getCollapsedKey(_id as string)) === COLLAPSED +} + +export const setTreeCollapsed = (_id: any, collapsed: boolean): void => { + if (_id === undefined || _id === 'undefined') return + localStorage.setItem(getCollapsedKey(_id), collapsed ? COLLAPSED : '') +} diff --git a/plugins/hr-resources/src/components/sidebar/DepartmentsHierarchy.svelte b/plugins/hr-resources/src/components/sidebar/DepartmentsHierarchy.svelte index 84f16d87d8..d379aa1db0 100644 --- a/plugins/hr-resources/src/components/sidebar/DepartmentsHierarchy.svelte +++ b/plugins/hr-resources/src/components/sidebar/DepartmentsHierarchy.svelte @@ -20,11 +20,8 @@ import { getClient } from '@hcengineering/presentation' import { Action, IconEdit } from '@hcengineering/ui' import { getActions as getContributedActions, TreeElement } from '@hcengineering/view-resources' - import hr from '../../plugin' - // import TreeElement from './TreeElement.svelte' - export let departments: Ref<Department>[] export let descendants: Map<Ref<Department>, Department[]> export let departmentById: Map<Ref<Department>, Department> diff --git a/plugins/hr-resources/src/components/sidebar/Sidebar.svelte b/plugins/hr-resources/src/components/sidebar/Sidebar.svelte index 3b096bbe6e..91cb5111e5 100644 --- a/plugins/hr-resources/src/components/sidebar/Sidebar.svelte +++ b/plugins/hr-resources/src/components/sidebar/Sidebar.svelte @@ -37,7 +37,7 @@ <NavHeader label={hr.string.HRApplication} /> <Scroller shrink> - <TreeNode label={hr.string.Departments} node> + <TreeNode _id={'tree-hr'} label={hr.string.Departments} node> <DepartmentsHierarchy {departments} {descendants} {departmentById} selected={department} on:selected /> </TreeNode> <div class="antiNav-space" /> diff --git a/plugins/hr-resources/src/components/sidebar/TreeElement.svelte b/plugins/hr-resources/src/components/sidebar/TreeElement.svelte deleted file mode 100644 index cad0250c70..0000000000 --- a/plugins/hr-resources/src/components/sidebar/TreeElement.svelte +++ /dev/null @@ -1,94 +0,0 @@ -<!-- -// Copyright © 2023 Hardcore Engineering Inc. -// -// Licensed under the Eclipse Public 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 https://www.eclipse.org/legal/epl-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. ---> -<script lang="ts"> - import { createEventDispatcher } from 'svelte' - import { Doc, Ref } from '@hcengineering/core' - import type { Asset, IntlString } from '@hcengineering/platform' - import type { AnySvelteComponent, Action } from '@hcengineering/ui' - import { Icon, IconChevronDown, IconMoreH, Label, Menu, showPopup } from '@hcengineering/ui' - - export let _id: Ref<Doc> | undefined = undefined - export let icon: Asset | AnySvelteComponent | undefined = undefined - export let iconProps: Record<string, any> | undefined = undefined - export let label: IntlString | undefined = undefined - export let title: string | undefined = undefined - export let node = false - export let parent = false - export let collapsed = false - export let selected = false - export let level = 0 - export let actions: (originalEvent?: MouseEvent) => Promise<Action[]> = async () => [] - - let hovered = false - async function onMenuClick (ev: MouseEvent) { - showPopup(Menu, { actions: await actions(ev), ctx: _id }, ev.target as HTMLElement, () => { - hovered = false - }) - hovered = true - } - - $: style = `padding-left: calc(${level} * 1.25rem);` - - const dispatch = createEventDispatcher() -</script> - -<!-- svelte-ignore a11y-click-events-have-key-events --> -<div - class="antiNav-element" - class:hovered - class:selected - class:parent - class:collapsed - {style} - on:click={() => { - if (selected) { - collapsed = !collapsed - } - dispatch('click') - }} -> - <span class="an-element__label" class:title={node}> - {#if icon && !parent} - <div class="an-element__icon"> - <Icon {icon} {iconProps} size={'small'} /> - </div> - {/if} - <span class="overflow-label"> - {#if label}<Label {label} />{:else}{title}{/if} - </span> - - {#if node} - <div - class="an-element__icon-arrow" - class:collapsed - on:click={(e) => { - e.stopPropagation() - e.preventDefault() - collapsed = !collapsed - }} - > - <IconChevronDown size={'small'} /> - </div> - {/if} - </span> - - <div class="an-element__tool" on:click|preventDefault|stopPropagation={onMenuClick}> - <IconMoreH size={'small'} /> - </div> -</div> - -{#if node && !collapsed} - <div class="antiNav-element__dropbox"><slot /></div> -{/if} diff --git a/plugins/tracker-resources/src/components/projects/ProjectSpacePresenter.svelte b/plugins/tracker-resources/src/components/projects/ProjectSpacePresenter.svelte index 53ab74e589..c6dd6775c9 100644 --- a/plugins/tracker-resources/src/components/projects/ProjectSpacePresenter.svelte +++ b/plugins/tracker-resources/src/components/projects/ProjectSpacePresenter.svelte @@ -18,10 +18,11 @@ import { Project } from '@hcengineering/tracker' import { IconWithEmoji, - getCurrentLocation, getPlatformColorDef, getPlatformColorForTextDef, - themeStore + themeStore, + getTreeCollapsed, + setTreeCollapsed } from '@hcengineering/ui' import view from '@hcengineering/view' import { NavLink, TreeNode } from '@hcengineering/view-resources' @@ -35,10 +36,8 @@ export let getActions: Function export let deselect: boolean = false - const COLLAPSED = 'COLLAPSED' - const getSpaceCollapsedKey = () => `${getCurrentLocation().path[1]}_${space._id}_collapsed` - - $: collapsed = localStorage.getItem(getSpaceCollapsedKey()) === COLLAPSED + let collapsed: boolean = getTreeCollapsed(space._id) + $: setTreeCollapsed(space._id, collapsed) let specials: SpecialNavModel[] = [] @@ -78,7 +77,7 @@ title={space.name} folder actions={() => getActions(space)} - on:click={() => localStorage.setItem(getSpaceCollapsedKey(), collapsed ? '' : COLLAPSED)} + on:click={() => (collapsed = !collapsed)} > {#each specials as special} <NavLink space={space._id} special={special.id}> diff --git a/plugins/view-resources/src/components/navigator/TreeElement.svelte b/plugins/view-resources/src/components/navigator/TreeElement.svelte index 9110f82715..fda7318c34 100644 --- a/plugins/view-resources/src/components/navigator/TreeElement.svelte +++ b/plugins/view-resources/src/components/navigator/TreeElement.svelte @@ -17,10 +17,20 @@ import type { Doc, Ref } from '@hcengineering/core' import type { Asset, IntlString } from '@hcengineering/platform' import type { Action, AnySvelteComponent } from '@hcengineering/ui' - import { ActionIcon, Icon, IconChevronDown, IconMoreH, Label, Menu, showPopup } from '@hcengineering/ui' + import { + ActionIcon, + Icon, + IconChevronDown, + IconMoreH, + Label, + Menu, + showPopup, + getTreeCollapsed, + setTreeCollapsed + } from '@hcengineering/ui' import { createEventDispatcher } from 'svelte' - export let _id: Ref<Doc> | undefined = undefined + export let _id: Ref<Doc> | string | undefined = undefined export let icon: Asset | AnySvelteComponent | undefined = undefined export let iconProps: Record<string, any> | undefined = undefined export let label: IntlString | undefined = undefined @@ -31,7 +41,7 @@ export let indent: boolean = false export let folder: boolean = false export let level: number = 0 - export let collapsed: boolean = false + export let collapsed: boolean = getTreeCollapsed(_id) export let selected: boolean = false export let bold: boolean = false export let actions: (originalEvent?: MouseEvent) => Promise<Action[]> = async () => [] @@ -45,6 +55,8 @@ } const dispatch = createEventDispatcher() + $: if (_id) collapsed = getTreeCollapsed(_id) + $: setTreeCollapsed(_id, collapsed) </script> <!-- svelte-ignore a11y-click-events-have-key-events --> diff --git a/plugins/view-resources/src/components/navigator/TreeNode.svelte b/plugins/view-resources/src/components/navigator/TreeNode.svelte index 0df078fe4d..4e832c4536 100644 --- a/plugins/view-resources/src/components/navigator/TreeNode.svelte +++ b/plugins/view-resources/src/components/navigator/TreeNode.svelte @@ -18,7 +18,7 @@ import type { Action, AnySvelteComponent } from '@hcengineering/ui' import TreeElement from './TreeElement.svelte' - export let _id: Ref<Doc> | undefined = undefined + export let _id: Ref<Doc> | string | undefined = undefined export let title: string | undefined = undefined export let label: IntlString | undefined = undefined export let icon: Asset | AnySvelteComponent | undefined = undefined diff --git a/plugins/workbench-resources/src/components/SavedView.svelte b/plugins/workbench-resources/src/components/SavedView.svelte index 4869b1fbcc..b862751bc2 100644 --- a/plugins/workbench-resources/src/components/SavedView.svelte +++ b/plugins/workbench-resources/src/components/SavedView.svelte @@ -203,7 +203,12 @@ </script> {#if shown} - <TreeNode label={view.string.FilteredViews} node actions={async () => getActions(availableFilteredViews)}> + <TreeNode + _id={'tree-saved'} + label={view.string.FilteredViews} + node + actions={async () => getActions(availableFilteredViews)} + > {#each myFilteredViews as fv} <TreeItem _id={fv._id} diff --git a/plugins/workbench-resources/src/components/navigator/SpacesNav.svelte b/plugins/workbench-resources/src/components/navigator/SpacesNav.svelte index fbfc6e99a0..ae0461e112 100644 --- a/plugins/workbench-resources/src/components/navigator/SpacesNav.svelte +++ b/plugins/workbench-resources/src/components/navigator/SpacesNav.svelte @@ -142,7 +142,7 @@ } </script> -<TreeNode label={model.label} node actions={async () => getParentActions()}> +<TreeNode _id={'tree-' + model.id} label={model.label} node actions={async () => getParentActions()}> {#each filteredSpaces as space, i (space._id)} {#await getSpacePresenter(client, space._class) then presenter} {#if separate && model.specials && i !== 0}<TreeSeparator line />{/if} diff --git a/plugins/workbench-resources/src/components/navigator/StarredNav.svelte b/plugins/workbench-resources/src/components/navigator/StarredNav.svelte index aed21d9734..c4b2dbd39a 100644 --- a/plugins/workbench-resources/src/components/navigator/StarredNav.svelte +++ b/plugins/workbench-resources/src/components/navigator/StarredNav.svelte @@ -89,7 +89,7 @@ } </script> -<TreeNode {label} node actions={async () => [unStarAll]}> +<TreeNode _id={'tree-stared'} {label} node actions={async () => [unStarAll]}> {#each spaces as space (space._id)} {@const model = models.find((p) => p.spaceClass === space._class)} {#await getSpacePresenter(client, space._class) then presenter}