TSK-1309, TSK-1310, TSK-571 (#3048)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev
2023-04-23 09:50:41 +06:00
committed by GitHub
parent 7aa6ff437e
commit f0a4edee49
14 changed files with 199 additions and 101 deletions
@@ -282,7 +282,7 @@
class:checking={checkedSet.has(object._id)}
class:fixed={row === selection}
class:selected={row === selection}
on:mouseover={() => onRow(object)}
on:mouseenter={() => onRow(object)}
on:focus={() => {}}
bind:this={refs[row]}
on:contextmenu|preventDefault={(ev) => {
@@ -37,13 +37,10 @@
export let flatHeaders = false
export let disableHeader = false
export let props: Record<string, any> = {}
export let selection: number | undefined = undefined
export let documents: Doc[] | undefined = undefined
const elementByIndex: Map<number, HTMLDivElement> = new Map()
const docByIndex: Map<number, Doc> = new Map()
const indexById: Map<Ref<Doc>, number> = new Map()
let docs: Doc[] = []
$: orderBy = viewOptions.orderBy
@@ -63,16 +60,16 @@
resultQuery,
(res) => {
docs = res
dispatch('content', docs)
},
resultOptions
)
} else {
docsQuery.unsubscribe()
docs = documents
dispatch('content', docs)
}
$: dispatch('content', docs)
const dispatch = createEventDispatcher()
const client = getClient()
@@ -100,26 +97,7 @@
}
export function select (offset: 1 | -1 | 0, of?: Doc): void {
let pos = (of !== undefined ? indexById.get(of._id) : -1) ?? -1
pos += offset
if (pos < 0) {
pos = 0
}
if (pos >= docs.length) {
pos = docs.length - 1
}
const target = docByIndex.get(pos)
if (target !== undefined) {
onRow(target)
}
const r = elementByIndex.get(pos)
if (r !== undefined) {
r.scrollIntoView({ behavior: 'auto', block: 'nearest' })
}
}
function onRow (object: Doc): void {
dispatch('row-focus', object)
listCategories?.select(offset, of)
}
const getLoadingElementsLength = (props: LoadingProps | undefined, options?: FindOptions<Doc>) => {
@@ -137,23 +115,23 @@
} = {}
let listDiv: HTMLDivElement
let listCategories: ListCategories
</script>
<div class="list-container" bind:this={listDiv}>
<ListCategories
bind:this={listCategories}
newObjectProps={() => (space ? { space } : {})}
{elementByIndex}
{indexById}
{docs}
{_class}
{space}
{selection}
query={resultQuery}
{lookup}
loadingPropsLength={getLoadingElementsLength(loadingProps, options)}
{baseMenuClass}
{config}
{viewOptions}
{docByIndex}
{viewOptionsConfig}
{selectedObjectIds}
level={0}
@@ -167,6 +145,9 @@
{props}
{listDiv}
bind:dragItem
on:select={(evt) => {
select(0, evt.detail)
}}
/>
</div>
@@ -18,7 +18,7 @@
import { getClient, statusStore } from '@hcengineering/presentation'
import { AnyComponent } from '@hcengineering/ui'
import { AttributeModel, BuildModelKey, CategoryOption, ViewOptionModel, ViewOptions } from '@hcengineering/view'
import { createEventDispatcher, onDestroy } from 'svelte'
import { createEventDispatcher, onDestroy, SvelteComponentTyped } from 'svelte'
import {
buildModel,
concatCategories,
@@ -31,8 +31,6 @@
import { CategoryQuery, noCategory } from '../../viewOptions'
import ListCategory from './ListCategory.svelte'
export let elementByIndex: Map<number, HTMLDivElement>
export let indexById: Map<Ref<Doc>, number>
export let docs: Doc[]
export let _class: Ref<Class<Doc>>
export let space: Ref<Space> | undefined
@@ -51,13 +49,13 @@
export let level: number
export let initIndex = 0
export let newObjectProps: (doc: Doc) => Record<string, any> | undefined
export let docByIndex: Map<number, Doc>
export let viewOptionsConfig: ViewOptionModel[] | undefined
export let dragItem: {
doc?: Doc
revert?: () => void
}
export let listDiv: HTMLDivElement
export let selection: number | undefined = undefined
$: groupByKey = viewOptions.groupBy[level] ?? noCategory
let categories: CategoryType[] = []
@@ -129,25 +127,118 @@
$: extraHeaders = getAdditionalHeader(client, _class)
const dispatch = createEventDispatcher()
function getState (doc: Doc): number {
let pos = 0
for (const st of categories) {
const stateObjs = getGroupByValues(groupByDocs, st) ?? []
if (stateObjs.findIndex((it) => it._id === doc._id) !== -1) {
return pos
}
pos++
}
return -1
}
export function select (offset: 1 | -1 | 0, of?: Doc, dir?: 'vertical' | 'horizontal'): void {
let pos = (of != null ? docs.findIndex((it) => it._id === of._id) : selection) ?? -1
if (pos === -1) {
for (const st of categories) {
const stateObjs = getGroupByValues(groupByDocs, st) ?? []
if (stateObjs.length > 0) {
pos = docs.findIndex((it) => it._id === stateObjs[0]._id)
break
}
}
}
if (pos < 0) {
pos = 0
}
if (pos >= docs.length) {
pos = docs.length - 1
}
const obj = docs[pos]
if (obj === undefined) {
return
}
// We found group
const objState = getState(obj)
if (objState === -1) {
return
}
if (level + 1 >= viewOptions.groupBy.length) {
const stateObjs = getGroupByValues(groupByDocs, categories[objState]) ?? []
const statePos = stateObjs.findIndex((it) => it._id === obj._id)
if (statePos === undefined) {
return
}
console.log(statePos, objState, offset)
if (offset === -1) {
if (dir === undefined || dir === 'vertical') {
if (statePos - 1 < 0 && objState > 0) {
const pstateObjs = getGroupByValues(groupByDocs, categories[objState - 1]) ?? []
dispatch('select', pstateObjs[pstateObjs.length - 1])
} else {
const obj = stateObjs[statePos - 1] ?? stateObjs[0]
scrollInto(objState, obj)
dispatch('row-focus', obj)
}
return
}
}
if (offset === 1) {
if (dir === undefined || dir === 'vertical') {
if (statePos + 1 >= stateObjs.length && objState < categories.length) {
const pstateObjs = getGroupByValues(groupByDocs, categories[objState + 1]) ?? []
if (pstateObjs[0] !== undefined) {
dispatch('select', pstateObjs[0])
}
} else {
const obj = stateObjs[statePos + 1] ?? stateObjs[stateObjs.length - 1]
scrollInto(objState, obj)
dispatch('row-focus', obj)
}
return
}
}
if (offset === 0) {
// scrollInto(objState, obj)
dispatch('row-focus', obj)
}
} else {
listCategory[objState]?.select(offset, of, dir)
}
}
function scrollInto (statePos: number, obj: Doc): void {
// listCategory[statePos]?.scrollIntoView({ behavior: 'auto', block: 'nearest' })
listListCategory[statePos]?.scroll(obj)
listCategory[statePos]?.scroll(obj)
}
const listCategory: SvelteComponentTyped[] = []
const listListCategory: ListCategory[] = []
</script>
{#each categories as category, i (typeof category === 'object' ? category.name : category)}
{@const items = groupByKey === noCategory ? docs : getGroupByValues(groupByDocs, category)}
<ListCategory
{elementByIndex}
{indexById}
bind:this={listListCategory[i]}
{extraHeaders}
{space}
{selectedObjectIds}
{headerComponent}
initIndex={getInitIndex(categories, i)}
{baseMenuClass}
{level}
{viewOptions}
{groupByKey}
{lookup}
{config}
{docByIndex}
{itemModels}
{_class}
singleCat={level === 0 && categories.length === 1}
@@ -175,8 +266,6 @@
>
<svelte:fragment
slot="category"
let:elementByIndex
let:indexById
let:docs
let:_class
let:space
@@ -192,16 +281,13 @@
let:flatHeaders
let:props
let:level
let:initIndex
let:docByIndex
let:viewOptionsConfig
let:listDiv
let:dragstart
>
<svelte:self
{elementByIndex}
{indexById}
{docs}
bind:this={listCategory[i]}
{_class}
{space}
{lookup}
@@ -217,7 +303,6 @@
{props}
{level}
{initIndex}
{docByIndex}
{viewOptionsConfig}
{listDiv}
on:dragItem
@@ -225,6 +310,9 @@
on:uncheckAll
on:row-focus
on:dragstart={dragstart}
on:select={(evt) => {
select(0, evt.detail)
}}
/>
</svelte:fragment>
</ListCategory>
@@ -16,17 +16,18 @@
import { Class, Doc, DocumentUpdate, Lookup, PrimitiveType, Ref, Space, StatusValue } from '@hcengineering/core'
import { IntlString } from '@hcengineering/platform'
import { getClient } from '@hcengineering/presentation'
import { calcRank, DocWithRank } from '@hcengineering/task'
import { DocWithRank, calcRank } from '@hcengineering/task'
import {
AnyComponent,
CheckBox,
ExpandCollapse,
Spinner,
getEventPositionElement,
showPopup,
Spinner
mouseAttractor,
showPopup
} from '@hcengineering/ui'
import { AttributeModel, BuildModelKey, ViewOptionModel, ViewOptions } from '@hcengineering/view'
import { createEventDispatcher } from 'svelte'
import { createEventDispatcher, tick } from 'svelte'
import { FocusSelection, focusStore } from '../../selection'
import Menu from '../Menu.svelte'
import ListHeader from './ListHeader.svelte'
@@ -39,7 +40,6 @@
export let space: Ref<Space> | undefined
export let baseMenuClass: Ref<Class<Doc>> | undefined
export let items: Doc[]
export let initIndex: number
export let createItemDialog: AnyComponent | undefined
export let createItemLabel: IntlString | undefined
export let loadingPropsLength: number | undefined
@@ -50,14 +50,11 @@
export let disableHeader = false
export let props: Record<string, any> = {}
export let level: number
export let elementByIndex: Map<number, HTMLDivElement>
export let indexById: Map<Ref<Doc>, number>
export let lookup: Lookup<Doc>
export let _class: Ref<Class<Doc>>
export let config: (string | BuildModelKey)[]
export let viewOptions: ViewOptions
export let newObjectProps: (doc: Doc) => Record<string, any> | undefined
export let docByIndex: Map<number, Doc>
export let viewOptionsConfig: ViewOptionModel[] | undefined
export let dragItem: {
doc?: Doc
@@ -92,7 +89,7 @@
dispatch('row-focus', object)
}
const handleMenuOpened = async (event: MouseEvent, object: Doc, rowIndex: number) => {
const handleMenuOpened = async (event: MouseEvent, object: Doc) => {
event.preventDefault()
handleRowFocused(object)
@@ -300,6 +297,24 @@
index: i
})
}
export function scroll (item: Doc): void {
const pos = items.findIndex((it) => it._id === item._id)
if (pos >= 0) {
if (collapsed) {
collapsed = false
tick().then(() => scroll(item))
return
}
if (pos >= limited.length) {
limit = (limit ?? 0) + 20
tick().then(() => scroll(item))
} else {
listItems[pos]?.scroll()
}
}
}
const listItems: ListItem[] = []
</script>
<div
@@ -337,8 +352,6 @@
<div class="p-2">
<slot
name="category"
{elementByIndex}
{indexById}
docs={items}
{_class}
{space}
@@ -354,8 +367,6 @@
{flatHeaders}
{props}
level={level + 1}
{initIndex}
{docByIndex}
{viewOptionsConfig}
{listDiv}
dragItem
@@ -366,12 +377,9 @@
{#if limited}
{#each limited as docObject, i (docObject._id)}
<ListItem
bind:this={listItems[i]}
{docObject}
{elementByIndex}
{docByIndex}
{indexById}
model={itemModels}
index={initIndex + i}
{groupByKey}
selected={isSelected(docObject, $focusStore)}
checked={selectedObjectIdsSet.has(docObject._id)}
@@ -386,9 +394,9 @@
on:dragover={(e) => dragover(e, i)}
on:drop={dropItemHandle}
on:check={(ev) => dispatch('check', { docs: ev.detail.docs, value: ev.detail.value })}
on:contextmenu={(event) => handleMenuOpened(event, docObject, initIndex + i)}
on:contextmenu={(event) => handleMenuOpened(event, docObject)}
on:focus={() => {}}
on:mouseover={() => handleRowFocused(docObject)}
on:mouseover={mouseAttractor(() => handleRowFocused(docObject))}
{props}
/>
{/each}
@@ -13,25 +13,25 @@
// limitations under the License.
-->
<script lang="ts">
import core, { AnyAttribute, Doc, getObjectValue, Ref } from '@hcengineering/core'
import core, { AnyAttribute, Doc, getObjectValue } from '@hcengineering/core'
import notification from '@hcengineering/notification'
import { getClient, updateAttribute } from '@hcengineering/presentation'
import { CheckBox, Component, deviceOptionsStore as deviceInfo, tooltip, IconCircles } from '@hcengineering/ui'
import { CheckBox, Component, deviceOptionsStore as deviceInfo, IconCircles, tooltip } from '@hcengineering/ui'
import { AttributeModel } from '@hcengineering/view'
import { createEventDispatcher } from 'svelte'
import { FixedColumn } from '../..'
import view from '../../plugin'
export let docObject: Doc
export let index: number
export let model: AttributeModel[]
export let groupByKey: string | undefined
export let checked: boolean
export let selected: boolean
export let props: Record<string, any> = {}
export let elementByIndex: Map<number, HTMLDivElement>
export let indexById: Map<Ref<Doc>, number>
export let docByIndex: Map<number, Doc>
export function scroll () {
elem?.scrollIntoView({ behavior: 'auto', block: 'nearest' })
}
let elem: HTMLDivElement
@@ -47,10 +47,6 @@
$: compactMode = $deviceInfo.twoRows
$: elem && elementByIndex.set(index, elem)
$: indexById.set(docObject._id, index)
$: docByIndex.set(index, docObject)
const client = getClient()
function onChange (value: any, doc: Doc, key: string, attribute: AnyAttribute) {
@@ -94,6 +90,7 @@
draggable={true}
on:contextmenu
on:focus
on:mouseenter
on:mouseover
on:dragover
on:dragenter
@@ -4,7 +4,14 @@
import { AnyComponent, issueSP, Scroller } from '@hcengineering/ui'
import { BuildModelKey, Viewlet, ViewOptions } from '@hcengineering/view'
import { onMount } from 'svelte'
import { ActionContext, ListSelectionProvider, LoadingProps, SelectDirection, selectionStore } from '../..'
import {
ActionContext,
ListSelectionProvider,
LoadingProps,
SelectDirection,
focusStore,
selectionStore
} from '../..'
import List from './List.svelte'
@@ -56,6 +63,7 @@
{props}
viewOptionsConfig={viewlet.viewOptions?.other}
selectedObjectIds={$selectionStore ?? []}
selection={listProvider.current($focusStore)}
on:row-focus={(event) => {
listProvider.updateFocus(event.detail ?? undefined)
}}