mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-11 18:58:54 +00:00

Some checks are pending
CI / test (push) Blocked by required conditions
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / formatting (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
CI / dist-build (push) Blocked by required conditions
Signed-off-by: Artem Savchenko <armisav@gmail.com>
170 lines
5.2 KiB
Svelte
170 lines
5.2 KiB
Svelte
<!--
|
||
// 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 { createEventDispatcher } from 'svelte'
|
||
|
||
import { Class, Doc, DocumentQuery, Ref, SortingOrder } from '@hcengineering/core'
|
||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||
import { Action, IconEdit, navigate, type Location, Scroller, location, getLocation } from '@hcengineering/ui'
|
||
import { getResource, type Resource } from '@hcengineering/platform'
|
||
import { IntlString, Asset } from '@hcengineering/platform'
|
||
|
||
import { FoldersStore, FoldersState, emptyFoldersState, getFoldersManager } from './store/folderStore'
|
||
import FolderTreeLevel from './FolderTreeLevel.svelte'
|
||
import { TreeNode, TreeItem, getActions as getContributedActions } from '../../index'
|
||
|
||
export let _class: Ref<Class<Doc>>
|
||
export let query: DocumentQuery<Doc>
|
||
export let titleKey: string = 'title'
|
||
export let parentKey: string = 'parent'
|
||
export let noParentId: Ref<Doc>
|
||
export let getFolderLink: Resource<(doc: Ref<Doc> | undefined) => Location> | undefined
|
||
export let allObjectsIcon: Asset
|
||
export let allObjectsLabel: IntlString
|
||
export let plainList: boolean = false
|
||
|
||
const dispatch = createEventDispatcher()
|
||
|
||
const getFolderId = (): Ref<Doc> => {
|
||
return (getLocation()?.query?.attachedTo as Ref<Doc>) ?? noParentId
|
||
}
|
||
|
||
export let forciblyСollapsed: boolean = false
|
||
|
||
const client = getClient()
|
||
|
||
let foldersState: FoldersState = emptyFoldersState()
|
||
|
||
const foldersManager = getFoldersManager(titleKey, parentKey, noParentId, plainList)
|
||
|
||
FoldersStore.subscribe((newState) => {
|
||
foldersState = newState
|
||
})
|
||
|
||
let selected: Ref<Doc> = getFolderId()
|
||
let visibleItem: Doc | undefined = foldersState.folderById.get(selected)
|
||
location.subscribe(() => {
|
||
selected = getFolderId()
|
||
visibleItem = foldersState.folderById.get(selected)
|
||
})
|
||
|
||
const q = createQuery()
|
||
q.query(
|
||
_class,
|
||
query ?? {},
|
||
async (result) => {
|
||
foldersManager.setFolders(result)
|
||
if (plainList && foldersState.folders?.length > 0) {
|
||
if (selected === undefined) {
|
||
await handleFolderSelected(foldersState.folders[0])
|
||
}
|
||
}
|
||
},
|
||
{
|
||
sort: {
|
||
name: SortingOrder.Ascending
|
||
}
|
||
}
|
||
)
|
||
|
||
async function handleFolderSelected (_id: Ref<Doc>): Promise<void> {
|
||
if (getFolderLink !== undefined) {
|
||
const getFolderLinkFunction = await getResource(getFolderLink)
|
||
navigate(getFolderLinkFunction(_id))
|
||
} else {
|
||
selected = _id
|
||
}
|
||
dispatch('select', _id)
|
||
}
|
||
|
||
async function handleAllItemsSelected (): Promise<void> {
|
||
await handleFolderSelected(noParentId)
|
||
}
|
||
|
||
async function getFolderActions (obj: Doc): 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
|
||
}
|
||
|
||
async function getRootActions (): Promise<Action[]> {
|
||
return []
|
||
}
|
||
</script>
|
||
|
||
<Scroller padding={'1rem 0'}>
|
||
{#if noParentId !== undefined}
|
||
<TreeNode
|
||
_id={noParentId}
|
||
icon={allObjectsIcon}
|
||
label={allObjectsLabel}
|
||
selected={selected === noParentId}
|
||
type={'nested-selectable'}
|
||
empty={foldersState?.folders?.length === 0}
|
||
actions={() => getRootActions()}
|
||
{forciblyСollapsed}
|
||
on:click={handleAllItemsSelected}
|
||
>
|
||
<FolderTreeLevel
|
||
folders={foldersState.folders}
|
||
descendants={foldersState.descendants}
|
||
folderById={foldersState.folderById}
|
||
{selected}
|
||
on:selected={async (ev) => {
|
||
await handleFolderSelected(ev.detail)
|
||
}}
|
||
/>
|
||
<svelte:fragment slot="visible">
|
||
{#if (selected || forciblyСollapsed) && visibleItem !== undefined}
|
||
{@const folder = visibleItem}
|
||
<TreeItem
|
||
_id={folder._id}
|
||
folderIcon
|
||
iconProps={{ fill: 'var(--global-accent-IconColor)' }}
|
||
title={foldersManager.getTitle(folder)}
|
||
selected
|
||
isFold
|
||
empty
|
||
actions={async () => await getFolderActions(folder)}
|
||
shouldTooltip
|
||
forciblyСollapsed
|
||
/>
|
||
{/if}
|
||
</svelte:fragment>
|
||
</TreeNode>
|
||
{:else}
|
||
<FolderTreeLevel
|
||
folders={foldersState.folders}
|
||
descendants={foldersState.descendants}
|
||
folderById={foldersState.folderById}
|
||
{selected}
|
||
on:selected={async (ev) => {
|
||
await handleFolderSelected(ev.detail)
|
||
}}
|
||
/>
|
||
{/if}
|
||
</Scroller>
|