Use actual viewlet config to copy table

Signed-off-by: Artem Savchenko <armisav@gmail.com>
This commit is contained in:
Artem Savchenko
2026-01-18 21:08:57 +07:00
parent 775006303f
commit c493dc318e
6 changed files with 147 additions and 5 deletions
@@ -0,0 +1,87 @@
<!--
// Copyright © 2025 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 { Button } from '@hcengineering/ui'
import { Class, Doc, DocumentQuery, Ref, WithLookup, mergeQueries } from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation'
import { Viewlet, ViewOptions, ViewOptionModel } from '@hcengineering/view'
import view from '../plugin'
import { getResultQuery } from '../viewOptions'
import { CopyAsMarkdownTable, type CopyAsMarkdownTableProps } from '../copyAsMarkdownTable'
export let _class: Ref<Class<Doc>> | undefined = undefined
export let query: DocumentQuery<Doc> | undefined = undefined
export let resultQuery: DocumentQuery<Doc> | undefined = undefined
export let config: (string | any)[] | undefined = undefined
export let viewletConfig: (string | any)[] | undefined = undefined
export let viewlet: WithLookup<Viewlet> | undefined = undefined
export let viewOptions: ViewOptions | undefined = undefined
export let viewOptionsConfig: ViewOptionModel[] | undefined = undefined
const client = getClient()
const hierarchy = client.getHierarchy()
// Determine viewlet type from descriptor - only regular tables supported via fallback
$: isRegularTable = viewlet?.descriptor === view.viewlet.Table
$: canCopy =
isRegularTable &&
(query !== undefined || resultQuery !== undefined) &&
viewlet !== undefined &&
_class !== undefined
async function handleCopy (evt: Event): Promise<void> {
if (query === undefined && resultQuery === undefined) return
if (viewlet === undefined || _class === undefined || !isRegularTable) return
// Use resultQuery if provided (already has filters applied), otherwise compute from query + viewOptions
let actualQuery: DocumentQuery<Doc>
if (resultQuery !== undefined) {
actualQuery = resultQuery
} else if (query !== undefined) {
// Compute resultQuery from query + viewOptions if filters are available
if (viewOptions !== undefined) {
const p = await getResultQuery(hierarchy, query, viewOptionsConfig, viewOptions)
actualQuery = mergeQueries(p, query)
} else {
actualQuery = query
}
} else {
return
}
const docs = await client.findAll(_class, actualQuery, { limit: 1000 })
if (docs.length === 0) return
const props: CopyAsMarkdownTableProps = {
cardClass: _class,
viewlet,
config: viewletConfig ?? config,
query: actualQuery
}
await CopyAsMarkdownTable(docs, evt, props)
}
</script>
{#if canCopy}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<Button
label={view.string.CopyAsMarkdownTable}
icon={view.icon.Print}
kind={'ghost'}
size={'small'}
on:click={handleCopy}
/>
{/if}
@@ -42,7 +42,14 @@
resizeObserver,
showPopup
} from '@hcengineering/ui'
import { AttributeModel, BuildModelKey, BuildModelOptions, ViewOptionModel, ViewOptions } from '@hcengineering/view'
import {
AttributeModel,
BuildModelKey,
BuildModelOptions,
ViewOptionModel,
ViewOptions,
Viewlet
} from '@hcengineering/view'
import { deepEqual } from 'fast-equals'
import { createEventDispatcher, onMount } from 'svelte'
import { Readable } from 'svelte/store'
@@ -67,6 +74,7 @@
export let showFooter = false
export let viewOptionsConfig: ViewOptionModel[] | undefined = undefined
export let viewOptions: ViewOptions | undefined = undefined
export let viewlet: Viewlet | undefined = undefined
export let totalQuery: DocumentQuery<Doc> | undefined = undefined
@@ -541,11 +549,20 @@
async function handleCopyAsMarkdown (e: MouseEvent): Promise<void> {
if (model === undefined || viewModel.length === 0) return
// Compute the actual query with viewOptions/filters applied
const p = await getResultQuery(hierarchy, query, viewOptionsConfig, viewOptions)
const resultQuery = mergeQueries(p, query)
await CopyRelationshipTableAsMarkdown(e, {
viewModel,
model,
objects,
cardClass: _class
cardClass: _class,
query: resultQuery,
viewlet,
config,
viewOptions
})
}
</script>
@@ -31,6 +31,8 @@
export let viewlet: Viewlet | undefined = undefined
export let readonly = false
let table: RelationshipTable
onMount(() => {
;(document.activeElement as HTMLElement)?.blur()
})
@@ -46,6 +48,7 @@
<Scroller fade={tableSP} horizontal>
<RelationshipTable
bind:this={table}
{_class}
{config}
{options}
@@ -56,6 +59,7 @@
showFooter
{viewOptions}
viewOptionsConfig={viewOptionsConfig ?? viewlet?.viewOptions?.other}
{viewlet}
{readonly}
/>
</Scroller>
@@ -42,7 +42,14 @@
mouseAttractor,
resizeObserver
} from '@hcengineering/ui'
import { AttributeModel, BuildModelKey, BuildModelOptions, ViewOptionModel, ViewOptions } from '@hcengineering/view'
import {
AttributeModel,
BuildModelKey,
BuildModelOptions,
ViewOptionModel,
ViewOptions,
Viewlet
} from '@hcengineering/view'
import { deepEqual } from 'fast-equals'
import { createEventDispatcher, onMount } from 'svelte'
import { showMenu } from '../actions'
@@ -55,6 +62,7 @@
import { Readable } from 'svelte/store'
import { getResource } from '@hcengineering/platform'
import { canChangeAttribute } from '../permissions'
import { CopyAsMarkdownTable, type CopyAsMarkdownTableProps } from '../copyAsMarkdownTable'
export let _class: Ref<Class<Doc>>
export let query: DocumentQuery<Doc>
@@ -70,6 +78,7 @@
export let showFooter = false
export let viewOptionsConfig: ViewOptionModel[] | undefined = undefined
export let viewOptions: ViewOptions | undefined = undefined
export let viewlet: Viewlet | undefined = undefined
export let totalQuery: DocumentQuery<Doc> | undefined = undefined
@@ -365,6 +374,26 @@
}
return true
}
export async function copyTableAsMarkdown (evt: Event): Promise<void> {
if (objects.length === 0) {
return
}
// Compute the actual query with viewOptions/filters applied
const p = await getResultQuery(hierarchy, query, viewOptionsConfig, viewOptions)
const resultQuery = mergeQueries(p, query)
const props: CopyAsMarkdownTableProps = {
cardClass: _class,
viewlet,
config,
query: resultQuery,
valueFormatter: undefined
}
await CopyAsMarkdownTable(objects, evt, props)
}
</script>
{#if !model || isBuildingModel}
@@ -85,6 +85,7 @@
{tableId}
{viewOptions}
viewOptionsConfig={viewOptionsConfig ?? viewlet?.viewOptions?.other}
{viewlet}
selection={listProvider.current($focusStore)}
{readonly}
on:row-focus={(evt) => {
@@ -32,7 +32,8 @@ import viewPlugin, {
type Viewlet,
type AttributeModel,
type BuildModelKey,
type BuildMarkdownTableMetadata
type BuildMarkdownTableMetadata,
type ViewOptions
} from '@hcengineering/view'
import presentation, { getClient } from '@hcengineering/presentation'
import { getName, getPersonByPersonId } from '@hcengineering/contact'
@@ -476,7 +477,10 @@ export interface CopyRelationshipTableAsMarkdownProps {
objects: Doc[]
cardClass: Ref<Class<Doc>>
valueFormatter?: ValueFormatter
query?: DocumentQuery<Doc> // Original query used to fetch documents
query?: DocumentQuery<Doc> // Actual query with filters applied
viewlet?: Viewlet // The viewlet being used (if any)
config?: Array<string | BuildModelKey> // The actual config from viewlet/preferences
viewOptions?: ViewOptions // View options including filters
}
/**