mirror of
https://github.com/hcengineering/platform.git
synced 2026-10-01 14:05:05 +02:00
Updated navigator layout (#5619)
Signed-off-by: Alexander Platov <alexander.platov@hardcoreeng.com>
This commit is contained in:
@@ -17,8 +17,10 @@
|
||||
import { Label } from '@hcengineering/ui'
|
||||
|
||||
export let label: IntlString
|
||||
export let withButton: boolean = false
|
||||
</script>
|
||||
|
||||
<div class="antiNav-header overflow-label">
|
||||
<Label {label} />
|
||||
<div class="hulyNavPanel-header" class:withButton>
|
||||
<span class="overflow-label"><Label {label} /></span>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
@@ -17,12 +17,11 @@
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import preference, { SpacePreference } from '@hcengineering/preference'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Scroller } from '@hcengineering/ui'
|
||||
import { Scroller, NavItem } from '@hcengineering/ui'
|
||||
import { NavLink } from '@hcengineering/view-resources'
|
||||
import type { Application, NavigatorModel, SpecialNavModel } from '@hcengineering/workbench'
|
||||
import { getSpecialSpaceClass } from '../utils'
|
||||
import SpacesNav from './navigator/SpacesNav.svelte'
|
||||
import SpecialElement from './navigator/SpecialElement.svelte'
|
||||
import StarredNav from './navigator/StarredNav.svelte'
|
||||
import TreeSeparator from './navigator/TreeSeparator.svelte'
|
||||
import SavedView from './SavedView.svelte'
|
||||
@@ -150,18 +149,20 @@
|
||||
{/if}
|
||||
{#await checkIsDisabled(special) then disabled}
|
||||
<NavLink space={special.id} {disabled}>
|
||||
<SpecialElement
|
||||
<NavItem
|
||||
label={special.label}
|
||||
icon={special.icon}
|
||||
selected={menuSelection ? false : special.id === currentSpecial}
|
||||
selected={menuSelection
|
||||
? false
|
||||
: special.id === currentSpecial && (currentFragment === undefined || currentFragment === '')}
|
||||
{disabled}
|
||||
/>
|
||||
</NavLink>
|
||||
{/await}
|
||||
{/each}
|
||||
{/if}
|
||||
<div class="min-h-3 flex-no-shrink" />
|
||||
|
||||
{#if specials.length > 0 && (starred.length > 0 || savedMenu)}<TreeSeparator line />{/if}
|
||||
<SavedView
|
||||
{currentApplication}
|
||||
on:shown={(res) => (savedMenu = res.detail)}
|
||||
@@ -181,7 +182,6 @@
|
||||
{/if}
|
||||
|
||||
{#each model.spaces as m, i (m.label)}
|
||||
{#if (i === 0 && (specials.length > 0 || starred.length > 0 || savedMenu)) || i !== 0}<TreeSeparator line />{/if}
|
||||
<SpacesNav
|
||||
spaces={shownSpaces.filter((it) => hierarchy.isDerived(it._class, m.spaceClass))}
|
||||
{currentSpace}
|
||||
@@ -190,9 +190,8 @@
|
||||
on:open
|
||||
{currentSpecial}
|
||||
{currentFragment}
|
||||
deselect={menuSelection}
|
||||
deselect={menuSelection || starred.some((s) => s._id === currentSpace)}
|
||||
/>
|
||||
{/each}
|
||||
<div class="antiNav-space" />
|
||||
</Scroller>
|
||||
{/if}
|
||||
|
||||
@@ -264,14 +264,18 @@
|
||||
return []
|
||||
}
|
||||
}
|
||||
$: visibleFilter = myFilteredViews.find((fv) => fv._id === selectedId)
|
||||
</script>
|
||||
|
||||
{#if shown}
|
||||
<TreeNode
|
||||
_id={'tree-saved'}
|
||||
label={view.string.FilteredViews}
|
||||
node
|
||||
highlighted={selectedId !== undefined}
|
||||
actions={async () => await getActions(availableFilteredViews)}
|
||||
isFold
|
||||
empty={myFilteredViews.length === 0}
|
||||
visible={selectedId !== undefined}
|
||||
>
|
||||
{#each myFilteredViews as fv}
|
||||
<TreeItem
|
||||
@@ -284,5 +288,12 @@
|
||||
actions={async (ov) => await viewAction(fv, ov)}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
<svelte:fragment slot="visible">
|
||||
{#if visibleFilter}
|
||||
{@const item = visibleFilter}
|
||||
<TreeItem _id={item._id} title={item.name} selected actions={async (ov) => await viewAction(item, ov)} />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</TreeNode>
|
||||
{/if}
|
||||
|
||||
@@ -260,7 +260,13 @@
|
||||
loc.path[4] = (currentSpecial as string) ?? resolved.defaultLocation.path[4]
|
||||
} else {
|
||||
loc.path[3] = resolvedSpace
|
||||
loc.path[4] = resolvedSpecial ?? currentSpecial ?? resolved.defaultLocation.path[4]
|
||||
if (resolvedSpecial) {
|
||||
loc.path[4] = resolvedSpecial
|
||||
} else if (currentSpace && currentSpecial) {
|
||||
loc.path[4] = currentSpecial
|
||||
} else {
|
||||
loc.path[4] = resolved.defaultLocation.path[4]
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let index = 0; index < loc.path.length; index++) {
|
||||
@@ -728,7 +734,7 @@
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
{#if navFloat}<div class="cover shown" on:click={() => (visibleNav = false)} />{/if}
|
||||
<div class="antiPanel-navigator no-print {appsDirection === 'horizontal' ? 'portrait' : 'landscape'}">
|
||||
<div class="antiPanel-wrap__content">
|
||||
<div class="antiPanel-wrap__content hulyNavPanel-container">
|
||||
{#if currentApplication}
|
||||
<NavHeader label={currentApplication.label} />
|
||||
{#if currentApplication.navHeaderComponent}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Doc, Ref, Space } from '@hcengineering/core'
|
||||
import core, { AccountRole, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||
import { AccountRole, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||
import { IntlString, getResource } from '@hcengineering/platform'
|
||||
import preference from '@hcengineering/preference'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
@@ -23,28 +23,20 @@
|
||||
Action,
|
||||
AnyComponent,
|
||||
IconAdd,
|
||||
IconEdit,
|
||||
IconSearch,
|
||||
getCurrentResolvedLocation,
|
||||
navigate,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import {
|
||||
NavLink,
|
||||
TreeItem,
|
||||
TreeNode,
|
||||
getActions as getContributedActions,
|
||||
getSpacePresenter,
|
||||
classIcon
|
||||
} from '@hcengineering/view-resources'
|
||||
import { TreeNode } from '@hcengineering/view-resources'
|
||||
import { SpacesNavModel } from '@hcengineering/workbench'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
||||
import { DocNotifyContext, InboxNotification } from '@hcengineering/notification'
|
||||
|
||||
import plugin from '../../plugin'
|
||||
import { getSpaceName } from '../../utils'
|
||||
import TreeSeparator from './TreeSeparator.svelte'
|
||||
import SpacesNavItem from './SpacesNavItem.svelte'
|
||||
|
||||
export let model: SpacesNavModel
|
||||
export let currentSpace: Ref<Space> | undefined
|
||||
@@ -89,24 +81,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function getActions (space: Space): Promise<Action[]> {
|
||||
const result = [starSpace]
|
||||
|
||||
const extraActions = await getContributedActions(client, space, core.class.Space)
|
||||
for (const act of extraActions) {
|
||||
result.push({
|
||||
icon: act.icon ?? IconEdit,
|
||||
label: act.label,
|
||||
inline: act.inline,
|
||||
action: async (ctx: any, evt: Event) => {
|
||||
const impl = await getResource(act.action)
|
||||
await impl(space, evt, act.actionProps)
|
||||
}
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const inboxClient = InboxNotificationsClientImpl.getClient()
|
||||
const notifyContextByDocStore = inboxClient.contextByDoc
|
||||
const inboxNotificationsByContextStore = inboxClient.inboxNotificationsByContext
|
||||
@@ -164,38 +138,51 @@
|
||||
} else {
|
||||
filteredSpaces = spaces
|
||||
}
|
||||
$: visibleSpace = filteredSpaces.find((fs) => fs._id === currentSpace)
|
||||
$: empty = filteredSpaces.length === 0 || filteredSpaces === undefined
|
||||
$: visible =
|
||||
visibleSpace !== undefined &&
|
||||
(currentSpecial !== undefined || currentFragment !== undefined || currentFragment !== '') &&
|
||||
!deselect &&
|
||||
!empty
|
||||
</script>
|
||||
|
||||
<TreeNode _id={'tree-' + model.id} label={model.label} node actions={async () => getParentActions()}>
|
||||
<TreeNode
|
||||
_id={'tree-' + model.id}
|
||||
label={model.label}
|
||||
actions={async () => getParentActions()}
|
||||
highlighted={visible}
|
||||
isFold={!empty}
|
||||
{empty}
|
||||
{visible}
|
||||
>
|
||||
{#each filteredSpaces as space, i (space._id)}
|
||||
{#await getSpacePresenter(client, space._class) then presenter}
|
||||
{#if separate && model.specials && i !== 0}<TreeSeparator line />{/if}
|
||||
{#if model.specials && presenter}
|
||||
<svelte:component
|
||||
this={presenter}
|
||||
{space}
|
||||
{model}
|
||||
{currentSpace}
|
||||
{currentSpecial}
|
||||
{currentFragment}
|
||||
{getActions}
|
||||
{deselect}
|
||||
/>
|
||||
{:else}
|
||||
<NavLink space={space._id}>
|
||||
{#await getSpaceName(client, space) then name}
|
||||
<TreeItem
|
||||
_id={space._id}
|
||||
title={name}
|
||||
icon={classIcon(client, space._class)}
|
||||
selected={deselect ? false : currentSpace === space._id}
|
||||
actions={async () => await getActions(space)}
|
||||
bold={isChanged(space, $notifyContextByDocStore, $inboxNotificationsByContextStore)}
|
||||
indent
|
||||
/>
|
||||
{/await}
|
||||
</NavLink>
|
||||
{/if}
|
||||
{/await}
|
||||
{#if separate && model.specials && i !== 0}<TreeSeparator line />{/if}
|
||||
<SpacesNavItem
|
||||
{model}
|
||||
{space}
|
||||
{currentSpace}
|
||||
{currentSpecial}
|
||||
{currentFragment}
|
||||
{deselect}
|
||||
isChanged={isChanged(space, $notifyContextByDocStore, $inboxNotificationsByContextStore)}
|
||||
spaceActions={[starSpace]}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
<svelte:fragment slot="visible">
|
||||
{#if visibleSpace}
|
||||
<SpacesNavItem
|
||||
{model}
|
||||
space={visibleSpace}
|
||||
{currentSpace}
|
||||
{currentSpecial}
|
||||
{currentFragment}
|
||||
{deselect}
|
||||
isChanged={isChanged(visibleSpace, $notifyContextByDocStore, $inboxNotificationsByContextStore)}
|
||||
spaceActions={[starSpace]}
|
||||
forciblyСollapsed
|
||||
/>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</TreeNode>
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
// 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 type { Ref, Space } from '@hcengineering/core'
|
||||
import core from '@hcengineering/core'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Action, IconEdit } from '@hcengineering/ui'
|
||||
import {
|
||||
NavLink,
|
||||
TreeItem,
|
||||
getActions as getContributedActions,
|
||||
getSpacePresenter,
|
||||
classIcon
|
||||
} from '@hcengineering/view-resources'
|
||||
import { SpacesNavModel } from '@hcengineering/workbench'
|
||||
import { getSpaceName } from '../../utils'
|
||||
|
||||
export let model: SpacesNavModel
|
||||
export let currentSpace: Ref<Space> | undefined
|
||||
export let space: Space
|
||||
export let currentSpecial: string | undefined
|
||||
export let currentFragment: string | undefined
|
||||
export let deselect: boolean = false
|
||||
export let isChanged: boolean = false
|
||||
export let spaceActions: Action[] | undefined
|
||||
export let forciblyСollapsed: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
|
||||
async function getActions (space: Space): Promise<Action[]> {
|
||||
const result = [...(spaceActions ?? [])]
|
||||
|
||||
const extraActions = await getContributedActions(client, space, core.class.Space)
|
||||
for (const act of extraActions) {
|
||||
result.push({
|
||||
icon: act.icon ?? IconEdit,
|
||||
label: act.label,
|
||||
inline: act.inline,
|
||||
action: async (ctx: any, evt: Event) => {
|
||||
const impl = await getResource(act.action)
|
||||
await impl(space, evt, act.actionProps)
|
||||
}
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
</script>
|
||||
|
||||
{#await getSpacePresenter(client, space._class) then presenter}
|
||||
{#if model.specials && presenter}
|
||||
<svelte:component
|
||||
this={presenter}
|
||||
{space}
|
||||
{model}
|
||||
{currentSpace}
|
||||
{currentSpecial}
|
||||
{currentFragment}
|
||||
{getActions}
|
||||
{deselect}
|
||||
{forciblyСollapsed}
|
||||
selected={deselect ? false : currentSpace === space._id}
|
||||
/>
|
||||
{:else}
|
||||
<NavLink space={space._id}>
|
||||
{#await getSpaceName(client, space) then name}
|
||||
<TreeItem
|
||||
_id={space._id}
|
||||
title={name}
|
||||
icon={classIcon(client, space._class)}
|
||||
selected={deselect ? false : currentSpace === space._id}
|
||||
actions={async () => await getActions(space)}
|
||||
bold={isChanged}
|
||||
{forciblyСollapsed}
|
||||
indent
|
||||
/>
|
||||
{/await}
|
||||
</NavLink>
|
||||
{/if}
|
||||
{/await}
|
||||
@@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||
import type { Action } from '@hcengineering/ui'
|
||||
import { ActionIcon, Icon, Label } from '@hcengineering/ui'
|
||||
import { ButtonIcon, NavItem } from '@hcengineering/ui'
|
||||
|
||||
export let icon: Asset | undefined = undefined
|
||||
export let iconProps: Record<string, any> | undefined = undefined
|
||||
@@ -25,35 +25,33 @@
|
||||
export let selected: boolean = false
|
||||
export let disabled: boolean = false
|
||||
export let indent: boolean = false
|
||||
export let forciblyСollapsed: boolean = false
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="antiNav-element" class:selected class:disabled class:indent>
|
||||
<div class="an-element__icon">
|
||||
{#if icon}
|
||||
<Icon {icon} size={'small'} {iconProps} />
|
||||
{/if}
|
||||
</div>
|
||||
<span class="an-element__label">
|
||||
{#if label}<Label {label} />{/if}
|
||||
</span>
|
||||
<div class="an-element__grow" />
|
||||
{#each actions as action}
|
||||
{#if action.icon}
|
||||
<div class="an-element__tool">
|
||||
<ActionIcon
|
||||
label={action.label}
|
||||
<NavItem
|
||||
{icon}
|
||||
{iconProps}
|
||||
iconSize={'small'}
|
||||
{label}
|
||||
count={notifications > 0 ? notifications : null}
|
||||
{selected}
|
||||
{disabled}
|
||||
{indent}
|
||||
{forciblyСollapsed}
|
||||
>
|
||||
<svelte:fragment slot="actions">
|
||||
{#each actions as action}
|
||||
{#if action.icon}
|
||||
<ButtonIcon
|
||||
icon={action.icon}
|
||||
size={'small'}
|
||||
action={async (evt) => {
|
||||
kind={'tertiary'}
|
||||
size={'extra-small'}
|
||||
tooltip={{ label: action.label }}
|
||||
on:click={async (evt) => {
|
||||
await action.action({}, evt)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
{#if notifications > 0}
|
||||
<div class="an-element__counter">{notifications}</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</svelte:fragment>
|
||||
</NavItem>
|
||||
|
||||
@@ -14,24 +14,16 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Class, Doc, Ref, Space } from '@hcengineering/core'
|
||||
import core from '@hcengineering/core'
|
||||
import { DocNotifyContext, InboxNotification } from '@hcengineering/notification'
|
||||
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
||||
import { IntlString, getResource } from '@hcengineering/platform'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import preference from '@hcengineering/preference'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Action, IconEdit } from '@hcengineering/ui'
|
||||
import { Action } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import {
|
||||
NavLink,
|
||||
TreeItem,
|
||||
TreeNode,
|
||||
getActions as getContributedActions,
|
||||
getSpacePresenter,
|
||||
classIcon
|
||||
} from '@hcengineering/view-resources'
|
||||
import { TreeNode } from '@hcengineering/view-resources'
|
||||
import { SpacesNavModel } from '@hcengineering/workbench'
|
||||
import { getSpaceName } from '../../utils'
|
||||
import StarredNavItem from './StarredNavItem.svelte'
|
||||
|
||||
export let label: IntlString
|
||||
export let spaces: Space[]
|
||||
@@ -43,17 +35,6 @@
|
||||
|
||||
const client = getClient()
|
||||
|
||||
const unStarSpace: Action = {
|
||||
label: preference.string.Unstar,
|
||||
icon: preference.icon.Star,
|
||||
action: async (_id: Ref<Doc>): Promise<void> => {
|
||||
const current = await client.findOne(preference.class.SpacePreference, { attachedTo: _id as Ref<Space> })
|
||||
if (current !== undefined) {
|
||||
await client.remove(current)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const unStarAll: Action = {
|
||||
label: preference.string.DeleteStarred,
|
||||
icon: view.icon.Delete,
|
||||
@@ -69,23 +50,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function getActions (space: Space): Promise<Action[]> {
|
||||
const result = [unStarSpace]
|
||||
|
||||
const extraActions = await getContributedActions(client, space, core.class.Space)
|
||||
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(space, evt, act.actionProps)
|
||||
}
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function getSpaceModel (space: Ref<Class<Space>>): SpacesNavModel | undefined {
|
||||
const hierarchy = client.getHierarchy()
|
||||
const ancestors = [space, ...[...hierarchy.getAncestors(space)].reverse()]
|
||||
@@ -109,37 +73,44 @@
|
||||
if (notifyContext === undefined) return false
|
||||
return !notifyContext.hidden && !!inboxNotificationsByContext.get(notifyContext._id)?.length
|
||||
}
|
||||
$: visibleSpace = spaces.find((space) => currentSpace === space._id)
|
||||
</script>
|
||||
|
||||
<TreeNode _id={'tree-stared'} {label} node actions={async () => [unStarAll]}>
|
||||
<TreeNode
|
||||
_id={'tree-stared'}
|
||||
{label}
|
||||
actions={async () => [unStarAll]}
|
||||
highlighted={spaces.some((s) => s._id === currentSpace) && !deselect}
|
||||
isFold
|
||||
empty={spaces.length === 0}
|
||||
visible={visibleSpace !== undefined && !deselect}
|
||||
>
|
||||
{#each spaces as space (space._id)}
|
||||
{@const model = getSpaceModel(space._class)}
|
||||
{#await getSpacePresenter(client, space._class) then presenter}
|
||||
{#if presenter && model}
|
||||
<svelte:component
|
||||
this={presenter}
|
||||
{space}
|
||||
{model}
|
||||
{currentSpace}
|
||||
{currentSpecial}
|
||||
{currentFragment}
|
||||
{getActions}
|
||||
{deselect}
|
||||
/>
|
||||
{:else}
|
||||
{#await getSpaceName(client, space) then name}
|
||||
<NavLink space={space._id}>
|
||||
<TreeItem
|
||||
_id={space._id}
|
||||
title={name}
|
||||
icon={classIcon(client, space._class)}
|
||||
selected={currentSpace === space._id}
|
||||
actions={async () => await getActions(space)}
|
||||
bold={isChanged(space, $notifyContextByDocStore, $inboxNotificationsByContextStore)}
|
||||
/>
|
||||
</NavLink>
|
||||
{/await}
|
||||
{/if}
|
||||
{/await}
|
||||
<StarredNavItem
|
||||
{space}
|
||||
{model}
|
||||
{currentSpace}
|
||||
{currentSpecial}
|
||||
{currentFragment}
|
||||
{deselect}
|
||||
isChanged={isChanged(space, $notifyContextByDocStore, $inboxNotificationsByContextStore)}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
<svelte:fragment slot="visible">
|
||||
{#if visibleSpace}
|
||||
{@const model = getSpaceModel(visibleSpace._class)}
|
||||
<StarredNavItem
|
||||
space={visibleSpace}
|
||||
{model}
|
||||
{currentSpace}
|
||||
{currentSpecial}
|
||||
{currentFragment}
|
||||
{deselect}
|
||||
isChanged={isChanged(visibleSpace, $notifyContextByDocStore, $inboxNotificationsByContextStore)}
|
||||
forciblyСollapsed
|
||||
/>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</TreeNode>
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
<!--
|
||||
// Copyright © 2022, 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 type { Doc, Ref, Space } from '@hcengineering/core'
|
||||
import core from '@hcengineering/core'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import preference from '@hcengineering/preference'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Action, IconEdit } from '@hcengineering/ui'
|
||||
import {
|
||||
NavLink,
|
||||
TreeItem,
|
||||
getActions as getContributedActions,
|
||||
getSpacePresenter,
|
||||
classIcon
|
||||
} from '@hcengineering/view-resources'
|
||||
import { SpacesNavModel } from '@hcengineering/workbench'
|
||||
import { getSpaceName } from '../../utils'
|
||||
|
||||
export let space: Space
|
||||
export let model: SpacesNavModel | undefined
|
||||
export let currentSpace: Ref<Space> | undefined
|
||||
export let currentSpecial: string | undefined
|
||||
export let currentFragment: string | undefined
|
||||
export let deselect: boolean = false
|
||||
export let isChanged: boolean = false
|
||||
export let forciblyСollapsed: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
|
||||
const unStarSpace: Action = {
|
||||
label: preference.string.Unstar,
|
||||
icon: preference.icon.Star,
|
||||
action: async (_id: Ref<Doc>): Promise<void> => {
|
||||
const current = await client.findOne(preference.class.SpacePreference, { attachedTo: _id as Ref<Space> })
|
||||
if (current !== undefined) {
|
||||
await client.remove(current)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getActions (space: Space): Promise<Action[]> {
|
||||
const result = [unStarSpace]
|
||||
|
||||
const extraActions = await getContributedActions(client, space, core.class.Space)
|
||||
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(space, evt, act.actionProps)
|
||||
}
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
</script>
|
||||
|
||||
{#await getSpacePresenter(client, space._class) then presenter}
|
||||
{#if presenter && model}
|
||||
<svelte:component
|
||||
this={presenter}
|
||||
{space}
|
||||
{model}
|
||||
{currentSpace}
|
||||
{currentSpecial}
|
||||
{currentFragment}
|
||||
{getActions}
|
||||
{deselect}
|
||||
{forciblyСollapsed}
|
||||
type={'nested'}
|
||||
/>
|
||||
{:else}
|
||||
{#await getSpaceName(client, space) then name}
|
||||
<NavLink space={space._id}>
|
||||
<TreeItem
|
||||
_id={space._id}
|
||||
title={name}
|
||||
icon={classIcon(client, space._class)}
|
||||
selected={currentSpace === space._id}
|
||||
actions={async () => await getActions(space)}
|
||||
bold={isChanged}
|
||||
{forciblyСollapsed}
|
||||
/>
|
||||
</NavLink>
|
||||
{/await}
|
||||
{/if}
|
||||
{/await}
|
||||
Reference in New Issue
Block a user