List extract (#2505)

This commit is contained in:
Denis Bykhov
2023-01-14 17:54:54 +07:00
committed by GitHub
parent 1c01925ed4
commit 6a5f1ed479
124 changed files with 2382 additions and 1445 deletions
@@ -20,7 +20,7 @@
import { getResource } from '@hcengineering/platform'
import presentation, { createQuery, getClient, MessageViewer } from '@hcengineering/presentation'
import setting, { settingId } from '@hcengineering/setting'
import type { Issue, IssuesGrouping, IssuesOrdering, IssueStatus, Team } from '@hcengineering/tracker'
import type { Issue, IssueStatus, Team } from '@hcengineering/tracker'
import {
Button,
EditBox,
@@ -33,14 +33,7 @@
showPopup,
Spinner
} from '@hcengineering/ui'
import {
ContextMenu,
focusStore,
ListSelectionProvider,
SelectDirection,
UpDownNavigator,
viewOptionsStore
} from '@hcengineering/view-resources'
import { ContextMenu, UpDownNavigator } from '@hcengineering/view-resources'
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
import { generateIssueShortLink, getIssueId } from '../../../issues'
import tracker from '../../../plugin'
@@ -49,8 +42,6 @@
import CopyToClipboard from './CopyToClipboard.svelte'
import SubIssues from './SubIssues.svelte'
import SubIssueSelector from './SubIssueSelector.svelte'
import { groupBy as groupByFunc, issuesOrderKeyMap, issuesSortOrderMap } from '../../../utils'
import contact from '@hcengineering/contact'
export let _id: Ref<Issue>
export let _class: Ref<Class<Issue>>
@@ -71,14 +62,6 @@
let isEditing = false
let descriptionBox: AttachmentStyledBox
let groupBy: IssuesGrouping
let orderBy: IssuesOrdering
let shouldShowSubIssues: boolean
$: ({ groupBy, orderBy, shouldShowSubIssues } = $viewOptionsStore)
$: orderByKey = issuesOrderKeyMap[orderBy]
$: subIssuesQuery = shouldShowSubIssues ? {} : { attachedTo: tracker.ids.NoParent }
$: query = { space: issue?.space }
const notificationClient = getResource(notification.function.GetNotificationClient).then((res) => res())
$: read(_id)
@@ -126,72 +109,6 @@
$: isDescriptionEmpty = !new DOMParser().parseFromString(description, 'text/html').documentElement.innerText?.trim()
$: parentIssue = issue?.$lookup?.attachedTo
let issues: WithLookup<Issue>[] = []
let neighbourIssues: Issue[] = []
const issuesQuery = createQuery()
const subIssuesQueryClient = createQuery()
$: if (parentIssue) {
subIssuesQueryClient.query(
tracker.class.Issue,
{ attachedTo: parentIssue?._id },
async (result) => (neighbourIssues = result ?? []),
{
sort: { rank: SortingOrder.Descending }
}
)
} else {
issuesQuery.query(
tracker.class.Issue,
{ ...subIssuesQuery, ...query },
(result) => {
issues = result
},
{
sort: { [orderByKey]: issuesSortOrderMap[orderByKey] },
lookup: {
assignee: contact.class.Employee,
status: tracker.class.IssueStatus,
space: tracker.class.Team,
sprint: tracker.class.Sprint,
_id: {
subIssues: tracker.class.Issue
}
}
}
)
}
$: groupedIssues = groupByFunc(issues, groupBy)
$: flatGroupedIssues = Object.values(groupedIssues ?? {}).flat(1)
$: issuesToNavigate = parentIssue ? neighbourIssues : flatGroupedIssues
const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {
if (dir === 'vertical') {
if (groupedIssues) {
const selectedRowIndex = listProvider.current($focusStore)
let position =
(of !== undefined ? issuesToNavigate.findIndex((x) => x._id === of?._id) : selectedRowIndex) ?? -1
position -= offset
if (position < 0) {
position = 0
}
if (position >= issuesToNavigate.length) {
position = issuesToNavigate.length - 1
}
listProvider.updateFocus(issuesToNavigate[position])
}
}
})
$: if (issue) listProvider.updateFocus(issue)
$: listProvider.update(issuesToNavigate)
function edit (ev: MouseEvent) {
ev.preventDefault()
@@ -21,6 +21,7 @@
import { flip } from 'svelte/animate'
import { getIssueId } from '../../../issues'
import tracker from '../../../plugin'
import { subIssueListProvider } from '../../../utils'
import Circles from '../../icons/Circles.svelte'
import AssigneeEditor from '../AssigneeEditor.svelte'
import DueDateEditor from '../DueDateEditor.svelte'
@@ -41,6 +42,7 @@
function openIssue (target: Issue) {
dispatch('issue-focus', target)
subIssueListProvider(issues, target._id)
showPanel(tracker.component.EditIssue, target._id, target._class, 'content')
}
@@ -120,7 +122,7 @@
{issue.title}
</span>
{#if issue.subIssues > 0}
<SubIssuesSelector value={issue} {currentTeam} statuses={issueStatuses.get(issue.space)} />
<SubIssuesSelector value={issue} {currentTeam} />
{/if}
</div>
<div class="flex-center flex-no-shrink">
@@ -31,6 +31,7 @@
import tracker from '../../../plugin'
import { getIssueId } from '../../../issues'
import IssueStatusIcon from '../IssueStatusIcon.svelte'
import { ListSelectionProvider } from '@hcengineering/view-resources'
export let issue: WithLookup<Issue>
@@ -48,6 +49,7 @@
function openParentIssue () {
if (parentIssue) {
closeTooltip()
ListSelectionProvider.Pop()
openIssue(parentIssue._id)
}
}
@@ -138,7 +140,7 @@
bind:this={subIssuesElement}
class="flex-center sub-issues cursor-pointer"
use:tooltip={{ label: tracker.string.OpenSubIssues, direction: 'bottom' }}
on:click|preventDefault={areSubIssuesLoading ? undefined : showSubIssues}
on:click|preventDefault={showSubIssues}
>
<span class="overflow-label">{subIssues?.length}</span>
<div class="ml-2">
@@ -13,17 +13,26 @@
// limitations under the License.
-->
<script lang="ts">
import { Doc, Ref, WithLookup } from '@hcengineering/core'
import { Ref, SortingOrder, WithLookup } from '@hcengineering/core'
import { createQuery } from '@hcengineering/presentation'
import { Issue, IssueStatus, Team } from '@hcengineering/tracker'
import { ButtonKind, ButtonSize, getPlatformColor } from '@hcengineering/ui'
import { Button, closeTooltip, ProgressCircle, SelectPopup, showPanel, showPopup } from '@hcengineering/ui'
import { updateFocus } from '@hcengineering/view-resources'
import tracker from '../../../plugin'
import {
Button,
ButtonKind,
ButtonSize,
closeTooltip,
getPlatformColor,
ProgressCircle,
SelectPopup,
showPanel,
showPopup
} from '@hcengineering/ui'
import { getIssueId } from '../../../issues'
import tracker from '../../../plugin'
import { subIssueListProvider } from '../../../utils'
export let value: WithLookup<Issue>
export let currentTeam: Team | undefined
export let statuses: WithLookup<IssueStatus>[] | undefined
export let kind: ButtonKind = 'link-bordered'
export let size: ButtonSize = 'inline'
@@ -32,21 +41,35 @@
let btn: HTMLElement
let subIssues: Issue[] | undefined
let doneStatus: Ref<Doc> | undefined
let subIssues: Issue[] = []
let countComplate: number = 0
const query = createQuery()
const statusesQuery = createQuery()
let statuses: WithLookup<IssueStatus>[] = []
$: if (value.$lookup?.subIssues !== undefined) {
query.unsubscribe()
subIssues = value.$lookup.subIssues as Issue[]
subIssues.sort((a, b) => (a.rank ?? '').localeCompare(b.rank ?? ''))
} else {
query.query(tracker.class.Issue, { attachedTo: value._id }, (res) => (subIssues = res), {
sort: { rank: SortingOrder.Ascending }
})
}
statusesQuery.query(tracker.class.IssueStatus, {}, (res) => (statuses = res), {
lookup: { category: tracker.class.IssueStatusCategory }
})
$: if (statuses && subIssues) {
doneStatus = statuses.find((s) => s.category === tracker.issueStatusCategory.Completed)?._id ?? undefined
if (doneStatus) countComplate = subIssues.filter((si) => si.status === doneStatus).length
const doneStatuses = statuses.filter((s) => s.category === tracker.issueStatusCategory.Completed).map((p) => p._id)
countComplate = subIssues.filter((si) => doneStatuses.includes(si.status)).length
}
$: hasSubIssues = (subIssues?.length ?? 0) > 0
function getIssueStatusIcon (issue: Issue) {
function getIssueStatusIcon (issue: Issue, statuses: WithLookup<IssueStatus>[] | undefined) {
const status = statuses?.find((s) => issue.status === s._id)
const category = status?.$lookup?.category
const color = status?.color ?? category?.color
@@ -59,9 +82,11 @@
function openIssue (target: Ref<Issue>) {
if (target !== value._id) {
subIssueListProvider(subIssues, target)
showPanel(tracker.component.EditIssue, target, value._class, 'content')
}
}
function showSubIssues () {
if (subIssues) {
closeTooltip()
@@ -71,7 +96,7 @@
value: subIssues.map((iss) => {
const text = currentTeam ? `${getIssueId(currentTeam, iss)} ${iss.title}` : iss.title
return { id: iss._id, text, isSelected: iss._id === value._id, ...getIssueStatusIcon(iss) }
return { id: iss._id, text, isSelected: iss._id === value._id, ...getIssueStatusIcon(iss, statuses) }
}),
width: 'large'
},
@@ -86,12 +111,6 @@
},
(selectedIssue) => {
selectedIssue !== undefined && openIssue(selectedIssue)
},
(selectedIssue) => {
const focus = subIssues?.find((it) => it._id === selectedIssue.id)
if (focus !== undefined) {
updateFocus({ focus })
}
}
)
}