platform/plugins/card-resources/src/components/Childs.svelte
Denis Bykhov e8a91c2c03
Child cards (#8154)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
2025-03-06 21:48:24 +07:00

192 lines
5.2 KiB
Svelte

<script lang="ts">
import { Card, CardEvents } from '@hcengineering/card'
import core, { Data, Doc, fillDefaults, MarkupBlobRef, SortingOrder, WithLookup } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation'
import {
Label,
Scroller,
Button,
getCurrentLocation,
IconAdd,
navigate,
resizeObserver,
Section
} from '@hcengineering/ui'
import view, { Viewlet, ViewletPreference, ViewOptions } from '@hcengineering/view'
import {
List,
ListSelectionProvider,
restrictionStore,
SelectDirection,
ViewletsSettingButton
} from '@hcengineering/view-resources'
import card from '../plugin'
import { Analytics } from '@hcengineering/analytics'
import { translate } from '@hcengineering/platform'
import { makeRank } from '@hcengineering/rank'
export let object: Card
export let readonly: boolean = false
let viewlet: WithLookup<Viewlet> | undefined
let viewOptions: ViewOptions | undefined
let preference: ViewletPreference | undefined = undefined
const query = createQuery()
const viewletId = card.viewlet.CardList
let list: List
const listProvider = new ListSelectionProvider(
(offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection, noScroll?: boolean) => {
if (dir === 'vertical') {
// Select next
list?.select(offset, of, noScroll)
}
}
)
let docs: Doc[] = []
$: query.query(
view.class.Viewlet,
{
_id: viewletId
},
(res) => {
viewlet = res[0]
},
{
lookup: {
descriptor: view.class.ViewletDescriptor
}
}
)
const preferenceQuery = createQuery()
$: if (viewlet != null) {
preferenceQuery.query(
view.class.ViewletPreference,
{
space: core.space.Workspace,
attachedTo: viewletId
},
(res) => {
preference = res[0]
},
{ limit: 1 }
)
} else {
preferenceQuery.unsubscribe()
preference = undefined
}
$: selectedConfig = preference?.config ?? viewlet?.config ?? []
$: config = selectedConfig?.filter((p) =>
typeof p === 'string'
? !p.includes('$lookup') && !p.startsWith('@')
: !p.key.includes('$lookup') && !p.key.startsWith('@')
)
let listWidth: number
async function createCard (): Promise<void> {
const client = getClient()
const hierarchy = client.getHierarchy()
const lastOne = await client.findOne(card.class.Card, {}, { sort: { rank: SortingOrder.Descending } })
const title = await translate(card.string.Card, {})
const data: Data<Card> = {
parent: object._id,
title,
rank: makeRank(lastOne?.rank, undefined),
content: '' as MarkupBlobRef,
parentInfo: [
...(object.parentInfo ?? []),
{
_id: object._id,
_class: object._class,
title: object.title
}
]
}
const filledData = fillDefaults(hierarchy, data, object._class)
const _id = await client.createDoc(object._class, core.space.Workspace, filledData)
Analytics.handleEvent(CardEvents.CardCreated)
const loc = getCurrentLocation()
loc.path[3] = _id
loc.path.length = 4
navigate(loc)
}
const selection = listProvider.selection
</script>
<Section label={card.string.Children} icon={card.icon.Card}>
<svelte:fragment slot="header">
<ViewletsSettingButton bind:viewOptions viewletQuery={{ _id: viewletId }} kind={'tertiary'} bind:viewlet />
{#if !$restrictionStore.readonly && !readonly}
<Button
id="add-child-card"
icon={IconAdd}
label={card.string.CreateChild}
kind={'ghost'}
showTooltip={{ label: card.string.CreateChild, direction: 'bottom' }}
on:click={() => {
void createCard()
}}
/>
{/if}
</svelte:fragment>
<svelte:fragment slot="content">
{#if (object?.children ?? 0) > 0 && viewOptions !== undefined && viewlet}
<Scroller horizontal>
<div
class="list"
use:resizeObserver={(evt) => {
listWidth = evt.clientWidth
}}
>
<List
bind:this={list}
{listProvider}
_class={card.class.Card}
query={{
parent: object._id
}}
selectedObjectIds={$selection ?? []}
configurations={undefined}
{config}
{viewOptions}
compactMode={listWidth <= 600}
on:docs
on:row-focus={(event) => {
listProvider.updateFocus(event.detail ?? undefined)
}}
on:check={(event) => {
listProvider.updateSelection(event.detail.docs, event.detail.value)
}}
on:content={(evt) => {
docs = evt.detail
listProvider.update(evt.detail)
}}
/>
</div>
</Scroller>
{:else if !readonly}
<div class="antiSection-empty solid clear-mins mt-3">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<span class="over-underline content-color" on:click={createCard}>
<Label label={card.string.CreateChild} />
</span>
</div>
{/if}
</svelte:fragment>
</Section>