mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-16 05:13:06 +00:00
TSK-1309, TSK-1310, TSK-571 (#3048)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
7aa6ff437e
commit
f0a4edee49
@ -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
|
||||||
|
@ -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}
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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}
|
||||||
|
@ -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)
|
||||||
}}
|
}}
|
||||||
|
@ -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)
|
||||||
}}
|
}}
|
||||||
|
@ -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={() => {
|
||||||
|
@ -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) => {
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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}
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}}
|
}}
|
||||||
|
Loading…
Reference in New Issue
Block a user