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 10:50:41 +07:00 committed by GitHub
parent 7aa6ff437e
commit f0a4edee49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 199 additions and 101 deletions

View File

@ -210,7 +210,7 @@
} }
export function select (offset: 1 | -1 | 0, of?: Doc, dir?: 'vertical' | 'horizontal'): void { export function select (offset: 1 | -1 | 0, of?: Doc, dir?: 'vertical' | 'horizontal'): void {
let pos = (of !== undefined ? objects.findIndex((it) => it._id === of._id) : selection) ?? -1 let pos = (of != null ? objects.findIndex((it) => it._id === of._id) : selection) ?? -1
if (pos === -1) { if (pos === -1) {
for (const st of categories) { for (const st of categories) {
const stateObjs = getGroupByValues(groupByDocs, st) ?? [] const stateObjs = getGroupByValues(groupByDocs, st) ?? []
@ -237,7 +237,7 @@
if (objState === -1) { if (objState === -1) {
return return
} }
const stateObjs = getGroupByValues(groupByDocs, categories.indexOf(objState)) ?? [] const stateObjs = getGroupByValues(groupByDocs, categories[objState]) ?? []
const statePos = stateObjs.findIndex((it) => it._id === obj._id) const statePos = stateObjs.findIndex((it) => it._id === obj._id)
if (statePos === undefined) { if (statePos === undefined) {
return return

View File

@ -14,7 +14,7 @@
--> -->
<script lang="ts"> <script lang="ts">
import { CategoryType, Doc, Ref } from '@hcengineering/core' import { CategoryType, Doc, Ref } from '@hcengineering/core'
import ui, { Button, IconMoreH } from '@hcengineering/ui' import ui, { Button, IconMoreH, mouseAttractor } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import { slide } from 'svelte/transition' import { slide } from 'svelte/transition'
import { CardDragEvent, Item } from '../types' import { CardDragEvent, Item } from '../types'
@ -69,7 +69,7 @@
class="card-container" class="card-container"
class:selection={selection !== undefined ? objects[selection]?._id === object._id : false} class:selection={selection !== undefined ? objects[selection]?._id === object._id : false}
class:checked={checkedSet.has(object._id)} class:checked={checkedSet.has(object._id)}
on:mouseover={() => dispatch('obj-focus', object)} on:mouseover={mouseAttractor(() => dispatch('obj-focus', object))}
on:focus={() => {}} on:focus={() => {}}
on:contextmenu={(evt) => showMenu(evt, object)} on:contextmenu={(evt) => showMenu(evt, object)}
draggable={true} draggable={true}

View File

@ -50,15 +50,18 @@
closePanel() closePanel()
} }
$: props = $panelstore.panel $: if ($panelstore.panel !== undefined) {
if ($panelstore.panel.component === undefined) {
$: if (props !== undefined) { props = $panelstore.panel
component = undefined } else {
getResource($panelstore.panel.component).then((r) => {
getResource(props.component).then((r) => {
component = r component = r
props = $panelstore.panel
}) })
} }
} else {
props = undefined
}
function escapeClose () { function escapeClose () {
// Check if there is popup visible, then ignore // Check if there is popup visible, then ignore

View File

@ -105,3 +105,21 @@ export function tableToCSV (tableId: string, separator = ','): string {
* @public * @public
*/ */
export const networkStatus = writable<number>(0) export const networkStatus = writable<number>(0)
let attractorMx = 0
let attractorMy = 0
/**
* perform mouse movement checks and call method if they was
*/
export function mouseAttractor (op: () => void, diff = 5): (evt: MouseEvent) => void {
return (evt: MouseEvent) => {
const dx = evt.clientX - attractorMx
const dy = evt.clientY - attractorMy
attractorMx = evt.clientX
attractorMy = evt.clientY
if (Math.sqrt(dx * dx + dy * dy) > diff) {
op()
}
}
}

View File

@ -95,7 +95,7 @@
let kanbanUI: KanbanUI let kanbanUI: KanbanUI
const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => { const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {
kanbanUI.select(offset, of, dir) kanbanUI?.select(offset, of, dir)
}) })
onMount(() => { onMount(() => {
;(document.activeElement as HTMLElement)?.blur() ;(document.activeElement as HTMLElement)?.blur()
@ -125,6 +125,7 @@
...options ...options
} }
) )
$: listProvider.update(cards)
$: groupByDocs = groupBy(cards, 'state') $: groupByDocs = groupBy(cards, 'state')
const getUpdateProps = (doc: Doc, category: CategoryType): DocumentUpdate<DocWithRank> | undefined => { const getUpdateProps = (doc: Doc, category: CategoryType): DocumentUpdate<DocWithRank> | undefined => {
@ -151,11 +152,8 @@
getGroupByValues={(groupByDocs, category) => getGroupByValues(groupByDocs, category)} getGroupByValues={(groupByDocs, category) => getGroupByValues(groupByDocs, category)}
{setGroupByValues} {setGroupByValues}
categories={states.map((it) => it._id)} categories={states.map((it) => it._id)}
on:content={(evt) => {
listProvider.update(evt.detail)
}}
on:obj-focus={(evt) => { on:obj-focus={(evt) => {
listProvider.updateFocus(evt.detail) listProvider.updateFocus(evt.detail.object)
}} }}
{groupByDocs} {groupByDocs}
{getUpdateProps} {getUpdateProps}

View File

@ -106,7 +106,7 @@
let kanbanUI: KanbanUI let kanbanUI: KanbanUI
const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => { const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {
kanbanUI.select(offset, of, dir) kanbanUI?.select(offset, of, dir)
}) })
onMount(() => { onMount(() => {
;(document.activeElement as HTMLElement)?.blur() ;(document.activeElement as HTMLElement)?.blur()
@ -144,6 +144,7 @@
} }
} }
) )
$: listProvider.update(tasks)
let categories: CategoryType[] = [] let categories: CategoryType[] = []
@ -247,9 +248,6 @@
{setGroupByValues} {setGroupByValues}
{getUpdateProps} {getUpdateProps}
{groupByDocs} {groupByDocs}
on:content={(evt) => {
listProvider.update(evt.detail)
}}
on:obj-focus={(evt) => { on:obj-focus={(evt) => {
listProvider.updateFocus(evt.detail) listProvider.updateFocus(evt.detail)
}} }}

View File

@ -143,7 +143,7 @@
let kanbanUI: Kanban let kanbanUI: Kanban
const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => { const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {
kanbanUI.select(offset, of, dir) kanbanUI?.select(offset, of, dir)
}) })
onMount(() => { onMount(() => {
;(document.activeElement as HTMLElement)?.blur() ;(document.activeElement as HTMLElement)?.blur()
@ -172,6 +172,8 @@
} }
) )
$: listProvider.update(issues)
let categories: CategoryType[] = [] let categories: CategoryType[] = []
const queryId = generateId() const queryId = generateId()
@ -265,9 +267,6 @@
{setGroupByValues} {setGroupByValues}
{getUpdateProps} {getUpdateProps}
{groupByDocs} {groupByDocs}
on:content={(evt) => {
listProvider.update(evt.detail)
}}
on:obj-focus={(evt) => { on:obj-focus={(evt) => {
listProvider.updateFocus(evt.detail) listProvider.updateFocus(evt.detail)
}} }}

View File

@ -72,7 +72,7 @@
<div <div
class="{twoRows ? 'flex-col' : 'flex-between'} p-text-2" class="{twoRows ? 'flex-col' : 'flex-between'} p-text-2"
on:contextmenu|preventDefault={(ev) => showContextMenu(ev, report)} on:contextmenu|preventDefault={(ev) => showContextMenu(ev, report)}
on:mouseover={() => { on:mouseenter={() => {
listProvider.updateFocus(report) listProvider.updateFocus(report)
}} }}
on:focus={() => { on:focus={() => {

View File

@ -282,7 +282,7 @@
class:checking={checkedSet.has(object._id)} class:checking={checkedSet.has(object._id)}
class:fixed={row === selection} class:fixed={row === selection}
class:selected={row === selection} class:selected={row === selection}
on:mouseover={() => onRow(object)} on:mouseenter={() => onRow(object)}
on:focus={() => {}} on:focus={() => {}}
bind:this={refs[row]} bind:this={refs[row]}
on:contextmenu|preventDefault={(ev) => { on:contextmenu|preventDefault={(ev) => {

View File

@ -37,13 +37,10 @@
export let flatHeaders = false export let flatHeaders = false
export let disableHeader = false export let disableHeader = false
export let props: Record<string, any> = {} export let props: Record<string, any> = {}
export let selection: number | undefined = undefined
export let documents: Doc[] | 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[] = [] let docs: Doc[] = []
$: orderBy = viewOptions.orderBy $: orderBy = viewOptions.orderBy
@ -63,16 +60,16 @@
resultQuery, resultQuery,
(res) => { (res) => {
docs = res docs = res
dispatch('content', docs)
}, },
resultOptions resultOptions
) )
} else { } else {
docsQuery.unsubscribe() docsQuery.unsubscribe()
docs = documents docs = documents
dispatch('content', docs)
} }
$: dispatch('content', docs)
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
const client = getClient() const client = getClient()
@ -100,26 +97,7 @@
} }
export function select (offset: 1 | -1 | 0, of?: Doc): void { export function select (offset: 1 | -1 | 0, of?: Doc): void {
let pos = (of !== undefined ? indexById.get(of._id) : -1) ?? -1 listCategories?.select(offset, of)
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)
} }
const getLoadingElementsLength = (props: LoadingProps | undefined, options?: FindOptions<Doc>) => { const getLoadingElementsLength = (props: LoadingProps | undefined, options?: FindOptions<Doc>) => {
@ -137,23 +115,23 @@
} = {} } = {}
let listDiv: HTMLDivElement let listDiv: HTMLDivElement
let listCategories: ListCategories
</script> </script>
<div class="list-container" bind:this={listDiv}> <div class="list-container" bind:this={listDiv}>
<ListCategories <ListCategories
bind:this={listCategories}
newObjectProps={() => (space ? { space } : {})} newObjectProps={() => (space ? { space } : {})}
{elementByIndex}
{indexById}
{docs} {docs}
{_class} {_class}
{space} {space}
{selection}
query={resultQuery} query={resultQuery}
{lookup} {lookup}
loadingPropsLength={getLoadingElementsLength(loadingProps, options)} loadingPropsLength={getLoadingElementsLength(loadingProps, options)}
{baseMenuClass} {baseMenuClass}
{config} {config}
{viewOptions} {viewOptions}
{docByIndex}
{viewOptionsConfig} {viewOptionsConfig}
{selectedObjectIds} {selectedObjectIds}
level={0} level={0}
@ -167,6 +145,9 @@
{props} {props}
{listDiv} {listDiv}
bind:dragItem bind:dragItem
on:select={(evt) => {
select(0, evt.detail)
}}
/> />
</div> </div>

View File

@ -18,7 +18,7 @@
import { getClient, statusStore } from '@hcengineering/presentation' import { getClient, statusStore } from '@hcengineering/presentation'
import { AnyComponent } from '@hcengineering/ui' import { AnyComponent } from '@hcengineering/ui'
import { AttributeModel, BuildModelKey, CategoryOption, ViewOptionModel, ViewOptions } from '@hcengineering/view' import { AttributeModel, BuildModelKey, CategoryOption, ViewOptionModel, ViewOptions } from '@hcengineering/view'
import { createEventDispatcher, onDestroy } from 'svelte' import { createEventDispatcher, onDestroy, SvelteComponentTyped } from 'svelte'
import { import {
buildModel, buildModel,
concatCategories, concatCategories,
@ -31,8 +31,6 @@
import { CategoryQuery, noCategory } from '../../viewOptions' import { CategoryQuery, noCategory } from '../../viewOptions'
import ListCategory from './ListCategory.svelte' import ListCategory from './ListCategory.svelte'
export let elementByIndex: Map<number, HTMLDivElement>
export let indexById: Map<Ref<Doc>, number>
export let docs: Doc[] export let docs: Doc[]
export let _class: Ref<Class<Doc>> export let _class: Ref<Class<Doc>>
export let space: Ref<Space> | undefined export let space: Ref<Space> | undefined
@ -51,13 +49,13 @@
export let level: number export let level: number
export let initIndex = 0 export let initIndex = 0
export let newObjectProps: (doc: Doc) => Record<string, any> | undefined export let newObjectProps: (doc: Doc) => Record<string, any> | undefined
export let docByIndex: Map<number, Doc>
export let viewOptionsConfig: ViewOptionModel[] | undefined export let viewOptionsConfig: ViewOptionModel[] | undefined
export let dragItem: { export let dragItem: {
doc?: Doc doc?: Doc
revert?: () => void revert?: () => void
} }
export let listDiv: HTMLDivElement export let listDiv: HTMLDivElement
export let selection: number | undefined = undefined
$: groupByKey = viewOptions.groupBy[level] ?? noCategory $: groupByKey = viewOptions.groupBy[level] ?? noCategory
let categories: CategoryType[] = [] let categories: CategoryType[] = []
@ -129,25 +127,118 @@
$: extraHeaders = getAdditionalHeader(client, _class) $: extraHeaders = getAdditionalHeader(client, _class)
const dispatch = createEventDispatcher() 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> </script>
{#each categories as category, i (typeof category === 'object' ? category.name : category)} {#each categories as category, i (typeof category === 'object' ? category.name : category)}
{@const items = groupByKey === noCategory ? docs : getGroupByValues(groupByDocs, category)} {@const items = groupByKey === noCategory ? docs : getGroupByValues(groupByDocs, category)}
<ListCategory <ListCategory
{elementByIndex} bind:this={listListCategory[i]}
{indexById}
{extraHeaders} {extraHeaders}
{space} {space}
{selectedObjectIds} {selectedObjectIds}
{headerComponent} {headerComponent}
initIndex={getInitIndex(categories, i)}
{baseMenuClass} {baseMenuClass}
{level} {level}
{viewOptions} {viewOptions}
{groupByKey} {groupByKey}
{lookup} {lookup}
{config} {config}
{docByIndex}
{itemModels} {itemModels}
{_class} {_class}
singleCat={level === 0 && categories.length === 1} singleCat={level === 0 && categories.length === 1}
@ -175,8 +266,6 @@
> >
<svelte:fragment <svelte:fragment
slot="category" slot="category"
let:elementByIndex
let:indexById
let:docs let:docs
let:_class let:_class
let:space let:space
@ -192,16 +281,13 @@
let:flatHeaders let:flatHeaders
let:props let:props
let:level let:level
let:initIndex
let:docByIndex
let:viewOptionsConfig let:viewOptionsConfig
let:listDiv let:listDiv
let:dragstart let:dragstart
> >
<svelte:self <svelte:self
{elementByIndex}
{indexById}
{docs} {docs}
bind:this={listCategory[i]}
{_class} {_class}
{space} {space}
{lookup} {lookup}
@ -217,7 +303,6 @@
{props} {props}
{level} {level}
{initIndex} {initIndex}
{docByIndex}
{viewOptionsConfig} {viewOptionsConfig}
{listDiv} {listDiv}
on:dragItem on:dragItem
@ -225,6 +310,9 @@
on:uncheckAll on:uncheckAll
on:row-focus on:row-focus
on:dragstart={dragstart} on:dragstart={dragstart}
on:select={(evt) => {
select(0, evt.detail)
}}
/> />
</svelte:fragment> </svelte:fragment>
</ListCategory> </ListCategory>

View File

@ -16,17 +16,18 @@
import { Class, Doc, DocumentUpdate, Lookup, PrimitiveType, Ref, Space, StatusValue } from '@hcengineering/core' import { Class, Doc, DocumentUpdate, Lookup, PrimitiveType, Ref, Space, StatusValue } from '@hcengineering/core'
import { IntlString } from '@hcengineering/platform' import { IntlString } from '@hcengineering/platform'
import { getClient } from '@hcengineering/presentation' import { getClient } from '@hcengineering/presentation'
import { calcRank, DocWithRank } from '@hcengineering/task' import { DocWithRank, calcRank } from '@hcengineering/task'
import { import {
AnyComponent, AnyComponent,
CheckBox, CheckBox,
ExpandCollapse, ExpandCollapse,
Spinner,
getEventPositionElement, getEventPositionElement,
showPopup, mouseAttractor,
Spinner showPopup
} from '@hcengineering/ui' } from '@hcengineering/ui'
import { AttributeModel, BuildModelKey, ViewOptionModel, ViewOptions } from '@hcengineering/view' import { AttributeModel, BuildModelKey, ViewOptionModel, ViewOptions } from '@hcengineering/view'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher, tick } from 'svelte'
import { FocusSelection, focusStore } from '../../selection' import { FocusSelection, focusStore } from '../../selection'
import Menu from '../Menu.svelte' import Menu from '../Menu.svelte'
import ListHeader from './ListHeader.svelte' import ListHeader from './ListHeader.svelte'
@ -39,7 +40,6 @@
export let space: Ref<Space> | undefined export let space: Ref<Space> | undefined
export let baseMenuClass: Ref<Class<Doc>> | undefined export let baseMenuClass: Ref<Class<Doc>> | undefined
export let items: Doc[] export let items: Doc[]
export let initIndex: number
export let createItemDialog: AnyComponent | undefined export let createItemDialog: AnyComponent | undefined
export let createItemLabel: IntlString | undefined export let createItemLabel: IntlString | undefined
export let loadingPropsLength: number | undefined export let loadingPropsLength: number | undefined
@ -50,14 +50,11 @@
export let disableHeader = false export let disableHeader = false
export let props: Record<string, any> = {} export let props: Record<string, any> = {}
export let level: number export let level: number
export let elementByIndex: Map<number, HTMLDivElement>
export let indexById: Map<Ref<Doc>, number>
export let lookup: Lookup<Doc> export let lookup: Lookup<Doc>
export let _class: Ref<Class<Doc>> export let _class: Ref<Class<Doc>>
export let config: (string | BuildModelKey)[] export let config: (string | BuildModelKey)[]
export let viewOptions: ViewOptions export let viewOptions: ViewOptions
export let newObjectProps: (doc: Doc) => Record<string, any> | undefined export let newObjectProps: (doc: Doc) => Record<string, any> | undefined
export let docByIndex: Map<number, Doc>
export let viewOptionsConfig: ViewOptionModel[] | undefined export let viewOptionsConfig: ViewOptionModel[] | undefined
export let dragItem: { export let dragItem: {
doc?: Doc doc?: Doc
@ -92,7 +89,7 @@
dispatch('row-focus', object) dispatch('row-focus', object)
} }
const handleMenuOpened = async (event: MouseEvent, object: Doc, rowIndex: number) => { const handleMenuOpened = async (event: MouseEvent, object: Doc) => {
event.preventDefault() event.preventDefault()
handleRowFocused(object) handleRowFocused(object)
@ -300,6 +297,24 @@
index: i 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> </script>
<div <div
@ -337,8 +352,6 @@
<div class="p-2"> <div class="p-2">
<slot <slot
name="category" name="category"
{elementByIndex}
{indexById}
docs={items} docs={items}
{_class} {_class}
{space} {space}
@ -354,8 +367,6 @@
{flatHeaders} {flatHeaders}
{props} {props}
level={level + 1} level={level + 1}
{initIndex}
{docByIndex}
{viewOptionsConfig} {viewOptionsConfig}
{listDiv} {listDiv}
dragItem dragItem
@ -366,12 +377,9 @@
{#if limited} {#if limited}
{#each limited as docObject, i (docObject._id)} {#each limited as docObject, i (docObject._id)}
<ListItem <ListItem
bind:this={listItems[i]}
{docObject} {docObject}
{elementByIndex}
{docByIndex}
{indexById}
model={itemModels} model={itemModels}
index={initIndex + i}
{groupByKey} {groupByKey}
selected={isSelected(docObject, $focusStore)} selected={isSelected(docObject, $focusStore)}
checked={selectedObjectIdsSet.has(docObject._id)} checked={selectedObjectIdsSet.has(docObject._id)}
@ -386,9 +394,9 @@
on:dragover={(e) => dragover(e, i)} on:dragover={(e) => dragover(e, i)}
on:drop={dropItemHandle} on:drop={dropItemHandle}
on:check={(ev) => dispatch('check', { docs: ev.detail.docs, value: ev.detail.value })} 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:focus={() => {}}
on:mouseover={() => handleRowFocused(docObject)} on:mouseover={mouseAttractor(() => handleRowFocused(docObject))}
{props} {props}
/> />
{/each} {/each}

View File

@ -13,25 +13,25 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <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 notification from '@hcengineering/notification'
import { getClient, updateAttribute } from '@hcengineering/presentation' 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 { AttributeModel } from '@hcengineering/view'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import { FixedColumn } from '../..' import { FixedColumn } from '../..'
import view from '../../plugin' import view from '../../plugin'
export let docObject: Doc export let docObject: Doc
export let index: number
export let model: AttributeModel[] export let model: AttributeModel[]
export let groupByKey: string | undefined export let groupByKey: string | undefined
export let checked: boolean export let checked: boolean
export let selected: boolean export let selected: boolean
export let props: Record<string, any> = {} export let props: Record<string, any> = {}
export let elementByIndex: Map<number, HTMLDivElement>
export let indexById: Map<Ref<Doc>, number> export function scroll () {
export let docByIndex: Map<number, Doc> elem?.scrollIntoView({ behavior: 'auto', block: 'nearest' })
}
let elem: HTMLDivElement let elem: HTMLDivElement
@ -47,10 +47,6 @@
$: compactMode = $deviceInfo.twoRows $: compactMode = $deviceInfo.twoRows
$: elem && elementByIndex.set(index, elem)
$: indexById.set(docObject._id, index)
$: docByIndex.set(index, docObject)
const client = getClient() const client = getClient()
function onChange (value: any, doc: Doc, key: string, attribute: AnyAttribute) { function onChange (value: any, doc: Doc, key: string, attribute: AnyAttribute) {
@ -94,6 +90,7 @@
draggable={true} draggable={true}
on:contextmenu on:contextmenu
on:focus on:focus
on:mouseenter
on:mouseover on:mouseover
on:dragover on:dragover
on:dragenter on:dragenter

View File

@ -4,7 +4,14 @@
import { AnyComponent, issueSP, Scroller } from '@hcengineering/ui' import { AnyComponent, issueSP, Scroller } from '@hcengineering/ui'
import { BuildModelKey, Viewlet, ViewOptions } from '@hcengineering/view' import { BuildModelKey, Viewlet, ViewOptions } from '@hcengineering/view'
import { onMount } from 'svelte' import { onMount } from 'svelte'
import { ActionContext, ListSelectionProvider, LoadingProps, SelectDirection, selectionStore } from '../..' import {
ActionContext,
ListSelectionProvider,
LoadingProps,
SelectDirection,
focusStore,
selectionStore
} from '../..'
import List from './List.svelte' import List from './List.svelte'
@ -56,6 +63,7 @@
{props} {props}
viewOptionsConfig={viewlet.viewOptions?.other} viewOptionsConfig={viewlet.viewOptions?.other}
selectedObjectIds={$selectionStore ?? []} selectedObjectIds={$selectionStore ?? []}
selection={listProvider.current($focusStore)}
on:row-focus={(event) => { on:row-focus={(event) => {
listProvider.updateFocus(event.detail ?? undefined) listProvider.updateFocus(event.detail ?? undefined)
}} }}