Refactor Issues (#2037)

Signed-off-by: Dvinyanin Alexandr <dvinyanin.alexandr@gmail.com>
This commit is contained in:
Alex
2022-06-08 21:03:26 +07:00
committed by GitHub
parent a9392e1921
commit 6a7fa08fbd
11 changed files with 398 additions and 11 deletions
@@ -0,0 +1,31 @@
<script lang="ts">
import type { Ref, WithLookup } from '@anticrm/core'
import { Component } from '@anticrm/ui'
import { BuildModelKey, Viewlet } from '@anticrm/view'
import { IssuesDateModificationPeriod, IssuesGrouping, IssuesOrdering, Team } from '@anticrm/tracker'
export let currentSpace: Ref<Team>
export let viewlet: WithLookup<Viewlet> | undefined
export let config: (string | BuildModelKey)[] | undefined = undefined
export let query = {}
export let viewOptions: {
groupBy: IssuesGrouping
orderBy: IssuesOrdering
completedIssuesPeriod: IssuesDateModificationPeriod
shouldShowEmptyGroups: boolean
}
</script>
{#if viewlet?.$lookup?.descriptor?.component}
<Component
is={viewlet.$lookup?.descriptor?.component}
props={{
currentSpace,
config: config ?? viewlet.config,
options: viewlet.options,
viewlet,
query,
viewOptions
}}
/>
{/if}
@@ -0,0 +1,59 @@
<script lang="ts">
import { Ref, WithLookup } from '@anticrm/core'
import { IssuesDateModificationPeriod, IssuesGrouping, IssuesOrdering, Team } from '@anticrm/tracker'
import { Button, Icon, Tooltip, IconOptions, showPopup, eventToHTMLElement } from '@anticrm/ui'
import { Filter, Viewlet } from '@anticrm/view'
import { FilterButton } from '@anticrm/view-resources'
import tracker from '../../plugin'
import ViewOptionsPopup from './ViewOptionsPopup.svelte'
export let currentSpace: Ref<Team>
export let viewlet: WithLookup<Viewlet> | undefined
export let viewlets: WithLookup<Viewlet>[] = []
export let label: string
export let filters: Filter[] = []
export let viewOptions: {
groupBy: IssuesGrouping
orderBy: IssuesOrdering
completedIssuesPeriod: IssuesDateModificationPeriod
shouldShowEmptyGroups: boolean
}
const handleOptionsEditorOpened = (event: MouseEvent) => {
if (!currentSpace) {
return
}
showPopup(ViewOptionsPopup, viewOptions, eventToHTMLElement(event), undefined, (result) => {
if (result) viewOptions = { ...result }
})
}
</script>
<div class="ac-header full">
<div class="ac-header__wrap-title">
<div class="ac-header__icon"><Icon icon={tracker.icon.Issues} size={'small'} /></div>
<span class="ac-header__title">{label}</span>
<div class="ml-4"><FilterButton _class={tracker.class.Issue} bind:filters /></div>
</div>
{#if viewlets.length > 1}
<div class="flex">
{#each viewlets as v}
<Tooltip label={v.$lookup?.descriptor?.label} direction={'top'}>
<button
class="ac-header__icon-button"
class:selected={viewlet?._id === v._id}
on:click={() => {
viewlet = v
}}
>
{#if v.$lookup?.descriptor?.icon}
<Icon icon={v.$lookup?.descriptor?.icon} size={'small'} />
{/if}
</button>
</Tooltip>
{/each}
</div>
{/if}
<Button icon={IconOptions} kind={'link'} on:click={handleOptionsEditorOpened} />
</div>
@@ -0,0 +1,68 @@
<script lang="ts">
import core, { Ref, Space, WithLookup } from '@anticrm/core'
import { getClient } from '@anticrm/presentation'
import view, { Filter, Viewlet } from '@anticrm/view'
import IssuesContent from './IssuesContent.svelte'
import IssuesHeader from './IssuesHeader.svelte'
import { IssuesDateModificationPeriod, IssuesGrouping, IssuesOrdering, Team } from '@anticrm/tracker'
import tracker from '../../plugin'
import { IntlString, translate } from '@anticrm/platform'
import { FilterBar } from '@anticrm/view-resources'
export let currentSpace: Ref<Team> | undefined
export let query = {}
export let title: IntlString | undefined = undefined
export let label: string = ''
let viewlet: WithLookup<Viewlet> | undefined = undefined
let filters: Filter[]
let viewOptions = {
groupBy: IssuesGrouping.Status,
orderBy: IssuesOrdering.Status,
completedIssuesPeriod: IssuesDateModificationPeriod.All,
shouldShowEmptyGroups: false
}
let resultQuery = {}
const client = getClient()
let viewlets: WithLookup<Viewlet>[] = []
$: update(currentSpace)
async function update (currentSpace?: Ref<Space>): Promise<void> {
const space = await client.findOne(core.class.Space, { _id: currentSpace })
if (space) {
viewlets = await client.findAll(
view.class.Viewlet,
{ attachTo: tracker.class.Issue },
{
lookup: {
descriptor: view.class.ViewletDescriptor
}
}
)
;[viewlet] = viewlets
}
}
$: if (!label && title) {
translate(title, {}).then((res) => {
label = res
})
}
</script>
{#if currentSpace}
<IssuesHeader {currentSpace} {viewlets} {label} bind:viewlet bind:viewOptions bind:filters />
<FilterBar _class={tracker.class.Issue} {query} bind:filters on:change={(e) => (resultQuery = e.detail)} />
<div class="flex h-full">
<div class="antiPanel-component">
<IssuesContent {currentSpace} {viewlet} query={resultQuery} {viewOptions} />
</div>
{#if $$slots.aside !== undefined}
<div class="antiPanel-component aside border-left">
<slot name="aside" />
</div>
{/if}
</div>
{/if}
@@ -0,0 +1,85 @@
<script lang="ts">
import { ScrollBox } from '@anticrm/ui'
import IssuesListBrowser from './IssuesListBrowser.svelte'
import tracker from '../../plugin'
import {
Issue,
IssuesDateModificationPeriod,
IssuesGrouping,
IssuesOrdering,
IssueStatus,
Team
} from '@anticrm/tracker'
import { Class, Doc, Ref, SortingOrder, WithLookup } from '@anticrm/core'
import {
getCategories,
groupBy as groupByFunc,
issuesGroupKeyMap,
issuesOrderKeyMap,
issuesSortOrderMap
} from '../../utils'
import { createQuery } from '@anticrm/presentation'
import contact, { Employee } from '@anticrm/contact'
import { BuildModelKey } from '@anticrm/view'
export let _class: Ref<Class<Doc>>
export let currentSpace: Ref<Team>
export let config: (string | BuildModelKey)[]
export let query = {}
export let viewOptions: {
groupBy: IssuesGrouping
orderBy: IssuesOrdering
completedIssuesPeriod: IssuesDateModificationPeriod
shouldShowEmptyGroups: boolean
}
$: ({ groupBy, orderBy, shouldShowEmptyGroups } = viewOptions)
$: groupByKey = issuesGroupKeyMap[groupBy]
$: orderByKey = issuesOrderKeyMap[orderBy]
const statusesQuery = createQuery()
let statuses: IssueStatus[] = []
$: statusesQuery.query(
tracker.class.IssueStatus,
{ attachedTo: currentSpace },
(result) => {
statuses = result
},
{
lookup: { category: tracker.class.IssueStatusCategory },
sort: { rank: SortingOrder.Ascending }
}
)
$: groupedIssues = groupByFunc(issues, groupBy)
$: categories = getCategories(groupByKey, issues, !!shouldShowEmptyGroups, statuses, employees)
$: employees = issues.map((x) => x.$lookup?.assignee).filter(Boolean) as Employee[]
const issuesQuery = createQuery()
let issues: WithLookup<Issue>[] = []
$: issuesQuery.query(
tracker.class.Issue,
query,
(result) => {
issues = result
},
{
sort: { [orderByKey]: issuesSortOrderMap[orderByKey] },
limit: 200,
lookup: { assignee: contact.class.Employee, status: tracker.class.IssueStatus }
}
)
</script>
<ScrollBox vertical stretch>
<IssuesListBrowser
{_class}
{currentSpace}
{groupByKey}
orderBy={orderByKey}
{statuses}
{employees}
{categories}
itemsConfig={config}
{groupedIssues}
/>
</ScrollBox>
@@ -14,7 +14,7 @@
-->
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import { AttachedData, Ref, WithLookup } from '@anticrm/core'
import { AttachedData, Ref, SortingOrder, WithLookup } from '@anticrm/core'
import { Issue, IssueStatus } from '@anticrm/tracker'
import { getClient } from '@anticrm/presentation'
import { Tooltip, TooltipAlignment } from '@anticrm/ui'
@@ -48,9 +48,18 @@
await client.update(value, { status: newStatus })
}
}
$: query = '_id' in value ? { atachedTo: value.space } : {}
client
.findAll(tracker.class.IssueStatus, query, {
lookup: { category: tracker.class.IssueStatusCategory },
sort: { order: SortingOrder.Ascending }
})
.then((result) => {
if (!statuses) statuses = result
})
</script>
{#if value}
{#if value && statuses}
{#if isEditable}
<Tooltip label={tracker.string.SetStatus} direction={tooltipAlignment} fill={tooltipFill}>
<StatusSelector