2021-08-06 08:31:17 +00:00
|
|
|
<!--
|
2023-09-19 17:21:22 +00:00
|
|
|
// Copyright © 2022, 2023 Hardcore Engineering Inc.
|
2022-04-14 05:30:30 +00:00
|
|
|
//
|
2021-08-06 08:31:17 +00:00
|
|
|
// 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
|
2022-04-14 05:30:30 +00:00
|
|
|
//
|
2021-08-06 08:31:17 +00:00
|
|
|
// 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.
|
2022-04-14 05:30:30 +00:00
|
|
|
//
|
2021-08-06 08:31:17 +00:00
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
-->
|
|
|
|
<script lang="ts">
|
2023-04-19 02:24:03 +00:00
|
|
|
import core, { Doc, Ref, SortingOrder, Space } from '@hcengineering/core'
|
2022-09-21 08:08:25 +00:00
|
|
|
import { getResource } from '@hcengineering/platform'
|
2023-01-21 14:16:14 +00:00
|
|
|
import preference, { SpacePreference } from '@hcengineering/preference'
|
2022-09-21 08:08:25 +00:00
|
|
|
import { createQuery, getClient } from '@hcengineering/presentation'
|
2023-07-25 10:49:23 +00:00
|
|
|
import { Scroller } from '@hcengineering/ui'
|
2023-04-14 10:29:15 +00:00
|
|
|
import { NavLink } from '@hcengineering/view-resources'
|
2023-01-21 14:16:14 +00:00
|
|
|
import type { Application, NavigatorModel, SpecialNavModel } from '@hcengineering/workbench'
|
2022-03-04 09:01:46 +00:00
|
|
|
import { getSpecialSpaceClass } from '../utils'
|
2021-08-06 08:31:17 +00:00
|
|
|
import SpacesNav from './navigator/SpacesNav.svelte'
|
2021-11-22 12:06:14 +00:00
|
|
|
import SpecialElement from './navigator/SpecialElement.svelte'
|
2022-04-14 05:30:30 +00:00
|
|
|
import StarredNav from './navigator/StarredNav.svelte'
|
2022-02-03 09:03:53 +00:00
|
|
|
import TreeSeparator from './navigator/TreeSeparator.svelte'
|
2023-01-21 14:16:14 +00:00
|
|
|
import SavedView from './SavedView.svelte'
|
2021-08-06 08:31:17 +00:00
|
|
|
|
|
|
|
export let model: NavigatorModel | undefined
|
2022-02-03 09:03:53 +00:00
|
|
|
export let currentSpace: Ref<Space> | undefined
|
|
|
|
export let currentSpecial: string | undefined
|
2023-09-22 06:56:33 +00:00
|
|
|
export let currentFragment: string | undefined
|
2023-01-19 15:38:18 +00:00
|
|
|
export let currentApplication: Application | undefined
|
2022-04-14 05:30:30 +00:00
|
|
|
|
2022-03-04 09:04:21 +00:00
|
|
|
const client = getClient()
|
|
|
|
const hierarchy = client.getHierarchy()
|
2021-12-21 09:08:22 +00:00
|
|
|
const query = createQuery()
|
2022-04-14 05:30:30 +00:00
|
|
|
|
2022-02-03 09:03:53 +00:00
|
|
|
let spaces: Space[] = []
|
2022-04-14 05:30:30 +00:00
|
|
|
let starred: Space[] = []
|
2022-02-03 09:03:53 +00:00
|
|
|
let shownSpaces: Space[] = []
|
2022-04-14 05:30:30 +00:00
|
|
|
|
2021-12-21 09:08:22 +00:00
|
|
|
$: if (model) {
|
2024-04-09 19:20:49 +00:00
|
|
|
const classes = getSpecialSpaceClass(model).flatMap((c) => hierarchy.getDescendants(c))
|
2021-12-21 09:08:22 +00:00
|
|
|
query.query(
|
|
|
|
core.class.Space,
|
|
|
|
{
|
2024-04-09 19:20:49 +00:00
|
|
|
_class: { $in: classes }
|
2022-04-21 15:47:04 +00:00
|
|
|
// temp disabled, need way for default spaces
|
|
|
|
// members: getCurrentAccount()._id
|
|
|
|
},
|
|
|
|
(result) => {
|
|
|
|
spaces = result
|
2021-12-21 09:08:22 +00:00
|
|
|
},
|
2022-04-21 15:47:04 +00:00
|
|
|
{ sort: { name: SortingOrder.Ascending } }
|
|
|
|
)
|
2021-12-21 09:08:22 +00:00
|
|
|
}
|
2021-11-22 12:06:14 +00:00
|
|
|
|
2022-05-11 05:36:35 +00:00
|
|
|
let specials: SpecialNavModel[] = []
|
2022-02-03 09:03:53 +00:00
|
|
|
|
2022-04-14 05:30:30 +00:00
|
|
|
let preferences: Map<Ref<Doc>, SpacePreference> = new Map<Ref<Doc>, SpacePreference>()
|
|
|
|
|
|
|
|
const preferenceQuery = createQuery()
|
|
|
|
|
2023-01-21 14:16:14 +00:00
|
|
|
preferenceQuery.query(preference.class.SpacePreference, {}, (res) => {
|
2022-04-21 15:47:04 +00:00
|
|
|
preferences = new Map(
|
|
|
|
res.map((r) => {
|
|
|
|
return [r.attachedTo, r]
|
|
|
|
})
|
|
|
|
)
|
2022-04-14 05:30:30 +00:00
|
|
|
})
|
|
|
|
|
2022-06-10 18:36:47 +00:00
|
|
|
let requestIndex = 0
|
2022-04-29 05:27:17 +00:00
|
|
|
async function update (model: NavigatorModel, spaces: Space[], preferences: Map<Ref<Doc>, SpacePreference>) {
|
2023-04-19 02:24:03 +00:00
|
|
|
shownSpaces = spaces.filter((sp) => !sp.archived && !preferences.has(sp._id))
|
2022-06-10 18:36:47 +00:00
|
|
|
starred = spaces.filter((sp) => preferences.has(sp._id))
|
2022-02-03 09:03:53 +00:00
|
|
|
if (model.specials !== undefined) {
|
2022-06-10 18:36:47 +00:00
|
|
|
const [sp, resIndex] = await updateSpecials(model.specials, spaces, ++requestIndex)
|
|
|
|
if (resIndex !== requestIndex) return
|
2022-05-11 05:36:35 +00:00
|
|
|
const topSpecials = sp.get('top') ?? []
|
|
|
|
const bottomSpecials = sp.get('bottom') ?? []
|
|
|
|
sp.delete('top')
|
|
|
|
sp.delete('bottom')
|
|
|
|
|
|
|
|
const result = [...topSpecials]
|
|
|
|
|
|
|
|
for (const k of Array.from(sp.keys()).sort()) {
|
|
|
|
result.push(...(sp.get(k) ?? []))
|
|
|
|
}
|
|
|
|
|
|
|
|
result.push(...bottomSpecials)
|
|
|
|
specials = result
|
2022-02-09 09:06:53 +00:00
|
|
|
} else {
|
2022-05-11 05:36:35 +00:00
|
|
|
specials = []
|
2022-01-21 09:07:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-14 05:30:30 +00:00
|
|
|
$: if (model) update(model, spaces, preferences)
|
|
|
|
|
2022-06-10 18:36:47 +00:00
|
|
|
async function updateSpecials (
|
|
|
|
specials: SpecialNavModel[],
|
|
|
|
spaces: Space[],
|
|
|
|
requestIndex: number
|
|
|
|
): Promise<[Map<string, SpecialNavModel[]>, number]> {
|
2022-05-11 05:36:35 +00:00
|
|
|
const result = new Map<string, SpecialNavModel[]>()
|
2023-02-27 03:03:03 +00:00
|
|
|
|
|
|
|
const spHandlers = await Promise.all(
|
|
|
|
specials.map(async (sp) => {
|
|
|
|
const pos = sp.position ?? 'top'
|
|
|
|
let visible = true
|
|
|
|
if (sp.visibleIf !== undefined) {
|
|
|
|
const f = await getResource(sp.visibleIf)
|
|
|
|
visible = await f(spaces)
|
|
|
|
}
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
if (visible) {
|
|
|
|
const list = result.get(pos) ?? []
|
|
|
|
list.push(sp)
|
|
|
|
result.set(pos, list)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
)
|
2023-11-20 10:01:43 +00:00
|
|
|
spHandlers.forEach((spHandler) => {
|
|
|
|
spHandler()
|
|
|
|
})
|
2023-02-27 03:03:03 +00:00
|
|
|
|
2022-06-10 18:36:47 +00:00
|
|
|
return [result, requestIndex]
|
2021-12-30 09:04:32 +00:00
|
|
|
}
|
2023-03-03 16:56:04 +00:00
|
|
|
|
|
|
|
async function checkIsDisabled (special: SpecialNavModel) {
|
|
|
|
return special.checkIsDisabled && (await (await getResource(special.checkIsDisabled))())
|
|
|
|
}
|
2023-03-20 09:15:41 +00:00
|
|
|
|
|
|
|
let savedMenu: boolean = false
|
|
|
|
let menuSelection: boolean = false
|
2021-08-06 08:31:17 +00:00
|
|
|
</script>
|
|
|
|
|
|
|
|
{#if model}
|
2023-04-05 07:14:32 +00:00
|
|
|
<Scroller shrink>
|
2022-01-21 09:07:24 +00:00
|
|
|
{#if model.specials}
|
2022-05-11 05:36:35 +00:00
|
|
|
{#each specials as special, row}
|
|
|
|
{#if row > 0 && specials[row].position !== specials[row - 1].position}
|
2023-03-20 09:15:41 +00:00
|
|
|
<TreeSeparator line />
|
2022-05-11 05:36:35 +00:00
|
|
|
{/if}
|
2023-03-03 16:56:04 +00:00
|
|
|
{#await checkIsDisabled(special) then disabled}
|
|
|
|
<NavLink space={special.id} {disabled}>
|
|
|
|
<SpecialElement
|
|
|
|
label={special.label}
|
|
|
|
icon={special.icon}
|
2023-03-20 09:15:41 +00:00
|
|
|
selected={menuSelection ? false : special.id === currentSpecial}
|
2023-03-03 16:56:04 +00:00
|
|
|
{disabled}
|
|
|
|
/>
|
|
|
|
</NavLink>
|
|
|
|
{/await}
|
2022-04-02 04:06:48 +00:00
|
|
|
{/each}
|
2022-01-21 09:07:24 +00:00
|
|
|
{/if}
|
|
|
|
|
2023-03-20 09:15:41 +00:00
|
|
|
{#if specials.length > 0 && (starred.length > 0 || savedMenu)}<TreeSeparator line />{/if}
|
|
|
|
<SavedView
|
|
|
|
{currentApplication}
|
|
|
|
on:shown={(res) => (savedMenu = res.detail)}
|
|
|
|
on:select={(res) => (menuSelection = res.detail)}
|
|
|
|
/>
|
2022-04-14 05:30:30 +00:00
|
|
|
{#if starred.length}
|
2023-09-19 17:21:22 +00:00
|
|
|
<StarredNav
|
|
|
|
label={preference.string.Starred}
|
|
|
|
spaces={starred}
|
|
|
|
models={model.spaces}
|
|
|
|
on:space
|
|
|
|
{currentSpace}
|
|
|
|
{currentSpecial}
|
2023-09-22 06:56:33 +00:00
|
|
|
{currentFragment}
|
2023-09-19 17:21:22 +00:00
|
|
|
deselect={menuSelection}
|
|
|
|
/>
|
2022-04-14 05:30:30 +00:00
|
|
|
{/if}
|
|
|
|
|
2023-03-20 09:15:41 +00:00
|
|
|
{#each model.spaces as m, i (m.label)}
|
2023-11-20 10:01:43 +00:00
|
|
|
{#if (i === 0 && (specials.length > 0 || starred.length > 0 || savedMenu)) || i !== 0}<TreeSeparator line />{/if}
|
2022-04-21 15:47:04 +00:00
|
|
|
<SpacesNav
|
|
|
|
spaces={shownSpaces.filter((it) => hierarchy.isDerived(it._class, m.spaceClass))}
|
|
|
|
{currentSpace}
|
|
|
|
hasSpaceBrowser={model.specials?.find((p) => p.id === 'spaceBrowser') !== undefined}
|
|
|
|
model={m}
|
2022-04-27 05:50:07 +00:00
|
|
|
on:open
|
2022-04-21 15:47:04 +00:00
|
|
|
{currentSpecial}
|
2023-09-22 06:56:33 +00:00
|
|
|
{currentFragment}
|
2023-03-20 09:15:41 +00:00
|
|
|
deselect={menuSelection}
|
2022-04-21 15:47:04 +00:00
|
|
|
/>
|
2021-12-30 09:04:32 +00:00
|
|
|
{/each}
|
2022-01-21 09:07:24 +00:00
|
|
|
<div class="antiNav-space" />
|
|
|
|
</Scroller>
|
2021-08-06 08:31:17 +00:00
|
|
|
{/if}
|