platform/plugins/drive-resources/src/components/DriveSpacePresenter.svelte
Alexander Platov a437926f35
Updated navigator layout (#5619)
Signed-off-by: Alexander Platov <alexander.platov@hardcoreeng.com>
2024-06-05 12:50:13 +07:00

149 lines
4.8 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
// Copyright © 2024 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 { Doc, Ref, SortingOrder, Space } from '@hcengineering/core'
import { Drive, Folder } from '@hcengineering/drive'
import { createQuery, getClient } from '@hcengineering/presentation'
import { Action, navigate, IconEdit } from '@hcengineering/ui'
import { TreeNode, TreeItem, getActions as getContributedActions } from '@hcengineering/view-resources'
import { getResource } from '@hcengineering/platform'
import drive from '../plugin'
import { getDriveLink, getFolderIdFromFragment, getFolderLink } from '../navigation'
import FolderTreeLevel from './FolderTreeLevel.svelte'
export let space: Drive
export let currentSpace: Ref<Space> | undefined
export let currentSpecial: string | undefined
export let currentFragment: string | undefined
export let getActions: (space: Space) => Promise<Action[]> = async () => []
export let forciblyСollapsed: boolean = false
export let deselect: boolean = false
const client = getClient()
let folders: Ref<Folder>[] = []
let folderById: Map<Ref<Folder>, Folder> = new Map<Ref<Folder>, Folder>()
let descendants: Map<Ref<Folder>, Folder[]> = new Map<Ref<Folder>, Folder[]>()
function getDescendants (obj: Ref<Folder>): Ref<Folder>[] {
return (descendants.get(obj) ?? []).sort((a, b) => a.name.localeCompare(b.name)).map((p) => p._id)
}
let selected: Ref<Doc> | undefined
let visibleItem: Folder | undefined
$: selected = getFolderIdFromFragment(currentFragment ?? '')
$: visibleItem = selected !== undefined ? folderById.get(selected as Ref<Folder>) : undefined
const query = createQuery()
query.query(
drive.class.Folder,
{
space: space._id
},
(result) => {
folderById.clear()
descendants.clear()
for (const doc of result) {
const current = descendants.get(doc.parent) ?? []
current.push(doc)
descendants.set(doc.parent, current)
folderById.set(doc._id, doc)
}
folderById = folderById
descendants = descendants
folders = getDescendants(drive.ids.Root)
},
{
sort: {
name: SortingOrder.Ascending
}
}
)
function handleDriveSelected (_id: Ref<Drive>): void {
navigate(getDriveLink(_id))
}
function handleFolderSelected (_id: Ref<Folder>): void {
navigate(getFolderLink(_id))
}
async function getFolderActions (obj: Folder): Promise<Action[]> {
const result: Action[] = []
const extraActions = await getContributedActions(client, obj)
for (const act of extraActions) {
result.push({
icon: act.icon ?? IconEdit,
label: act.label,
action: async (ctx: any, evt: Event) => {
const impl = await getResource(act.action)
await impl(obj, evt, act.actionProps)
}
})
}
return result
}
</script>
{#if space}
<TreeNode
_id={space._id}
icon={drive.icon.Drive}
title={space.name}
highlighted={currentSpace === space._id && !deselect}
selected={currentSpace === space._id && selected === drive.ids.Root && currentFragment !== undefined && !deselect}
visible={(currentSpace === space._id && !deselect && descendants.size !== 0 && selected !== space._id) ||
(forciblyСollapsed && currentFragment !== undefined)}
type={'nested-selectable'}
empty={descendants.size === 0 || (forciblyСollapsed && selected === space._id && !deselect)}
actions={() => getActions(space)}
{forciblyСollapsed}
on:click={() => {
handleDriveSelected(space._id)
}}
>
<FolderTreeLevel
{folders}
{descendants}
{folderById}
{selected}
on:selected={(ev) => {
handleFolderSelected(ev.detail)
}}
/>
<svelte:fragment slot="visible">
{#if (selected || forciblyСollapsed) && visibleItem}
{@const folder = visibleItem}
<TreeItem
_id={folder._id}
folderIcon
iconProps={{ fill: 'var(--global-accent-IconColor)' }}
title={folder.name}
selected
isFold
empty
actions={async () => await getFolderActions(folder)}
shouldTooltip
forciblyСollapsed
/>
{/if}
</svelte:fragment>
</TreeNode>
{/if}