mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-28 12:35:02 +02:00
UBER-1080 improve selection (#3857)
Signed-off-by: Alexander Onnikov <alexander.onnikov@xored.com>
This commit is contained in:
@@ -20,7 +20,7 @@
|
||||
import { Action, ViewContextType } from '@hcengineering/view'
|
||||
import { fly } from 'svelte/transition'
|
||||
import { getContextActions, getSelection } from '../actions'
|
||||
import { focusStore, previewDocument, selectionStore } from '../selection'
|
||||
import { ListSelectionProvider, SelectionStore, focusStore, previewDocument, selectionStore } from '../selection'
|
||||
import { getObjectPreview } from '../utils'
|
||||
|
||||
const client = getClient()
|
||||
@@ -28,8 +28,9 @@
|
||||
addTxListener((tx) => {
|
||||
if (tx._class === core.class.TxRemoveDoc) {
|
||||
const docId = (tx as TxRemoveDoc<Doc>).objectId
|
||||
if ($selectionStore.find((it) => it._id === docId) !== undefined) {
|
||||
selectionStore.update((old) => {
|
||||
const provider = ListSelectionProvider.Find(docId)
|
||||
if (provider !== undefined) {
|
||||
provider.selection.update((old) => {
|
||||
return old.filter((it) => it._id !== docId)
|
||||
})
|
||||
}
|
||||
@@ -47,13 +48,13 @@
|
||||
application?: Ref<Doc>
|
||||
},
|
||||
focus: Doc | undefined | null,
|
||||
selection: Doc[]
|
||||
selection: SelectionStore
|
||||
): Promise<Action[]> {
|
||||
let docs: Doc | Doc[] = []
|
||||
if (selection.find((it) => it._id === focus?._id) === undefined && focus != null) {
|
||||
if (selection.docs.find((it) => it._id === focus?._id) === undefined && focus != null) {
|
||||
docs = focus
|
||||
} else {
|
||||
docs = selection
|
||||
docs = selection.docs
|
||||
}
|
||||
|
||||
return await getContextActions(client, docs, context)
|
||||
|
||||
@@ -193,11 +193,11 @@
|
||||
on:keydown={onKeydown}
|
||||
use:resizeObserver={() => dispatch('changeContent')}
|
||||
>
|
||||
{#if $selectionStore.length > 0 || $focusStore.focus !== undefined || (activeAction && activeAction?.actionPopup !== undefined)}
|
||||
{#if $selectionStore.docs.length > 0 || $focusStore.focus !== undefined || (activeAction && activeAction?.actionPopup !== undefined)}
|
||||
<div class="mt-2 ml-2 flex-between flex-no-shrink">
|
||||
{#if $selectionStore.length > 0}
|
||||
{#if $selectionStore.docs.length > 0}
|
||||
<div class="item-box">
|
||||
<Label label={view.string.NumberItems} params={{ count: $selectionStore.length }} />
|
||||
<Label label={view.string.NumberItems} params={{ count: $selectionStore.docs.length }} />
|
||||
</div>
|
||||
{:else if $focusStore.focus !== undefined}
|
||||
<div class="item-box">
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
import { Scroller, tableSP, FadeOptions } from '@hcengineering/ui'
|
||||
import { BuildModelKey } from '@hcengineering/view'
|
||||
import { onMount } from 'svelte'
|
||||
import { focusStore, ListSelectionProvider, SelectDirection, selectionStore } from '../selection'
|
||||
import { focusStore, ListSelectionProvider, SelectDirection } from '../selection'
|
||||
import { LoadingProps } from '../utils'
|
||||
import SourcePresenter from './inference/SourcePresenter.svelte'
|
||||
import Table from './Table.svelte'
|
||||
@@ -48,6 +48,7 @@
|
||||
}
|
||||
}
|
||||
)
|
||||
const selection = listProvider.selection
|
||||
|
||||
onMount(() => {
|
||||
;(document.activeElement as HTMLElement)?.blur()
|
||||
@@ -101,7 +102,7 @@
|
||||
highlightRows={true}
|
||||
{enableChecking}
|
||||
showFooter
|
||||
checked={$selectionStore ?? []}
|
||||
checked={$selection ?? []}
|
||||
{prefferedSorting}
|
||||
{tableId}
|
||||
selection={listProvider.current($focusStore)}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import { AnyComponent, AnySvelteComponent } from '@hcengineering/ui'
|
||||
import { BuildModelKey, ViewOptionModel, ViewOptions, ViewQueryOption, Viewlet } from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { SelectionFocusProvider } from '../../selection'
|
||||
import { buildConfigLookup } from '../../utils'
|
||||
import ListCategories from './ListCategories.svelte'
|
||||
|
||||
@@ -40,6 +41,7 @@
|
||||
export let props: Record<string, any> = {}
|
||||
export let selection: number | undefined = undefined
|
||||
export let compactMode: boolean = false
|
||||
export let listProvider: SelectionFocusProvider
|
||||
|
||||
const limiter = new RateLimitter(() => ({ rate: 10 }))
|
||||
|
||||
@@ -189,6 +191,7 @@
|
||||
{viewOptionsConfig}
|
||||
{selectedObjectIds}
|
||||
{limiter}
|
||||
{listProvider}
|
||||
level={0}
|
||||
groupPersistKey={''}
|
||||
{createItemDialog}
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
ViewOptions
|
||||
} from '@hcengineering/view'
|
||||
import { createEventDispatcher, onDestroy, SvelteComponentTyped } from 'svelte'
|
||||
import { SelectionFocusProvider } from '../../selection'
|
||||
import {
|
||||
buildModel,
|
||||
concatCategories,
|
||||
@@ -83,6 +84,7 @@
|
||||
export let resultQuery: DocumentQuery<Doc>
|
||||
export let resultOptions: FindOptions<Doc>
|
||||
export let limiter: RateLimitter
|
||||
export let listProvider: SelectionFocusProvider
|
||||
|
||||
$: groupByKey = viewOptions.groupBy[level] ?? noCategory
|
||||
let categories: CategoryType[] = []
|
||||
@@ -380,6 +382,7 @@
|
||||
{resultQuery}
|
||||
{resultOptions}
|
||||
{limiter}
|
||||
{listProvider}
|
||||
on:check
|
||||
on:uncheckAll
|
||||
on:row-focus
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
import { AttributeModel, BuildModelKey, ViewOptionModel, ViewOptions, Viewlet } from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { fade } from 'svelte/transition'
|
||||
import { FocusSelection, focusStore } from '../../selection'
|
||||
import { FocusSelection, SelectionFocusProvider, focusStore } from '../../selection'
|
||||
import Menu from '../Menu.svelte'
|
||||
import ListHeader from './ListHeader.svelte'
|
||||
import ListItem from './ListItem.svelte'
|
||||
@@ -87,6 +87,7 @@
|
||||
export let resultOptions: FindOptions<Doc>
|
||||
export let parentCategories: number = 0
|
||||
export let limiter: RateLimitter
|
||||
export let listProvider: SelectionFocusProvider
|
||||
|
||||
$: lastLevel = level + 1 >= viewOptions.groupBy.length
|
||||
|
||||
@@ -432,6 +433,7 @@
|
||||
limited={lastLevel ? limited.length : itemProj.length}
|
||||
itemsProj={itemProj}
|
||||
items={limited}
|
||||
{listProvider}
|
||||
{headerComponent}
|
||||
{createItemDialog}
|
||||
{createItemDialogProps}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
import { AttributeModel, ViewOptions } from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import view from '../../plugin'
|
||||
import { selectionStore, selectionStoreMap } from '../../selection'
|
||||
import { SelectionFocusProvider } from '../../selection'
|
||||
import { noCategory } from '../../viewOptions'
|
||||
|
||||
export let groupByKey: string
|
||||
@@ -50,6 +50,7 @@
|
||||
export let collapsed = false
|
||||
export let lastCat = false
|
||||
export let level: number
|
||||
export let listProvider: SelectionFocusProvider
|
||||
|
||||
export let createItemDialog: AnyComponent | AnySvelteComponent | undefined
|
||||
export let createItemDialogProps: Record<string, any> | undefined
|
||||
@@ -82,7 +83,10 @@
|
||||
}
|
||||
let mouseOver = false
|
||||
|
||||
$: selected = items.filter((it) => $selectionStoreMap.has(it._id))
|
||||
const selection = listProvider.selection
|
||||
|
||||
$: selectionIds = new Set($selection.map((it) => it._id))
|
||||
$: selected = items.filter((it) => selectionIds.has(it._id))
|
||||
</script>
|
||||
|
||||
{#if headerComponent || groupByKey === noCategory}
|
||||
@@ -177,18 +181,18 @@
|
||||
kind={'ghost'}
|
||||
showTooltip={{ label: view.string.Select }}
|
||||
on:click={() => {
|
||||
let newSelection = [...$selectionStore]
|
||||
let newSelection = [...$selection]
|
||||
if (selected.length > 0) {
|
||||
const smap = new Map(selected.map((it) => [it._id, it]))
|
||||
newSelection = newSelection.filter((it) => !smap.has(it._id))
|
||||
} else {
|
||||
for (const s of items) {
|
||||
if (!$selectionStoreMap.has(s._id)) {
|
||||
if (!selectionIds.has(s._id)) {
|
||||
newSelection.push(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
selectionStore.set(newSelection)
|
||||
listProvider.selection.set(newSelection)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
<!--
|
||||
// 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 { Class, Doc, DocumentQuery, FindOptions, Ref, Space } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
@@ -5,7 +19,7 @@
|
||||
import { BuildModelKey, Viewlet, ViewOptions } from '@hcengineering/view'
|
||||
import { onMount } from 'svelte'
|
||||
import { ActionContext } from '@hcengineering/presentation'
|
||||
import { ListSelectionProvider, SelectDirection, focusStore, selectionStore } from '../..'
|
||||
import { ListSelectionProvider, SelectDirection, focusStore } from '../..'
|
||||
|
||||
import List from './List.svelte'
|
||||
|
||||
@@ -37,6 +51,7 @@
|
||||
}
|
||||
}
|
||||
)
|
||||
const selection = listProvider.selection
|
||||
|
||||
onMount(() => {
|
||||
;(document.activeElement as HTMLElement)?.blur()
|
||||
@@ -70,9 +85,10 @@
|
||||
{createItemLabel}
|
||||
{viewOptions}
|
||||
{props}
|
||||
{listProvider}
|
||||
compactMode={listWidth <= 800}
|
||||
viewOptionsConfig={viewlet.viewOptions?.other}
|
||||
selectedObjectIds={$selectionStore ?? []}
|
||||
selectedObjectIds={$selection ?? []}
|
||||
selection={listProvider.current($focusStore)}
|
||||
on:row-focus={(event) => {
|
||||
listProvider.updateFocus(event.detail ?? undefined)
|
||||
|
||||
Reference in New Issue
Block a user