diff --git a/models/tracker/src/index.ts b/models/tracker/src/index.ts index f7ad3320a3..e203d8b7c1 100644 --- a/models/tracker/src/index.ts +++ b/models/tracker/src/index.ts @@ -523,7 +523,7 @@ export function createModel (builder: Builder): void { key: 'shouldShowSubIssues', type: 'toggle', defaultValue: false, - actionTartget: 'query', + actionTarget: 'query', action: tracker.function.SubIssueQuery, label: tracker.string.SubIssues }, @@ -531,7 +531,7 @@ export function createModel (builder: Builder): void { key: 'shouldShowAll', type: 'toggle', defaultValue: false, - actionTartget: 'category', + actionTarget: 'category', action: view.function.ShowEmptyGroups, label: view.string.ShowEmptyGroups } diff --git a/models/tracker/src/plugin.ts b/models/tracker/src/plugin.ts index 1a7d5a6754..f1ca65f082 100644 --- a/models/tracker/src/plugin.ts +++ b/models/tracker/src/plugin.ts @@ -20,7 +20,7 @@ import { IntlString, mergeIds, Resource } from '@hcengineering/platform' import { trackerId } from '@hcengineering/tracker' import tracker from '@hcengineering/tracker-resources/src/plugin' import type { AnyComponent } from '@hcengineering/ui/src/types' -import { Action, ViewAction, Viewlet, ViewletDescriptor } from '@hcengineering/view' +import { Action, ViewAction, Viewlet } from '@hcengineering/view' import { Application } from '@hcengineering/workbench' export default mergeIds(trackerId, tracker, { @@ -51,9 +51,7 @@ export default mergeIds(trackerId, tracker, { IssueList: '' as Ref, IssueTemplateList: '' as Ref, IssueKanban: '' as Ref, - SprintList: '' as Ref, - List: '' as Ref, - Kanban: '' as Ref + SprintList: '' as Ref }, completion: { IssueQuery: '' as Resource, diff --git a/plugins/tracker-resources/src/components/issues/KanbanView.svelte b/plugins/tracker-resources/src/components/issues/KanbanView.svelte index bd3c204fa6..872cadb15a 100644 --- a/plugins/tracker-resources/src/components/issues/KanbanView.svelte +++ b/plugins/tracker-resources/src/components/issues/KanbanView.svelte @@ -41,7 +41,7 @@ showPopup, tooltip } from '@hcengineering/ui' - import { CategoryOption, ViewOptionModel, ViewOptions, ViewQueryOption } from '@hcengineering/view' + import { CategoryOption, Viewlet, ViewOptionModel, ViewOptions, ViewQueryOption } from '@hcengineering/view' import { ActionContext, focusStore, @@ -52,6 +52,7 @@ SelectDirection, selectionStore } from '@hcengineering/view-resources' + import { sortCategories } from '@hcengineering/view-resources/src/utils' import { onMount } from 'svelte' import tracker from '../../plugin' import { issuesGroupBySorting, mapKanbanCategories } from '../../utils' @@ -71,6 +72,7 @@ export let query: DocumentQuery = {} export let viewOptionsConfig: ViewOptionModel[] | undefined export let viewOptions: ViewOptions + export let viewlet: Viewlet $: currentSpace = space || tracker.project.DefaultProject $: groupBy = (viewOptions.groupBy[0] ?? noCategory) as IssuesGrouping @@ -99,7 +101,7 @@ if (viewOptions === undefined) return query let result = hierarchy.clone(query) for (const viewOption of viewOptions) { - if (viewOption.actionTartget !== 'query') continue + if (viewOption.actionTarget !== 'query') continue const queryOption = viewOption as ViewQueryOption const f = await getResource(queryOption.action) result = f(viewOptionsStore[queryOption.key] ?? queryOption.defaultValue, query) @@ -234,9 +236,9 @@ sprints: Sprint[], assignee: Employee[] ) { - let categories = await getCategories(client, _class, docs, groupByKey) + let categories = await getCategories(client, _class, docs, groupByKey, viewlet.descriptor) for (const viewOption of viewOptionsModel ?? []) { - if (viewOption.actionTartget !== 'category') continue + if (viewOption.actionTarget !== 'category') continue const categoryFunc = viewOption as CategoryOption if (viewOptions[viewOption.key] ?? viewOption.defaultValue) { const f = await getResource(categoryFunc.action) @@ -247,7 +249,8 @@ res.push(category) } } - categories = res + + categories = await sortCategories(client, _class, res, groupByKey, viewlet.descriptor) break } } diff --git a/plugins/tracker-resources/src/plugin.ts b/plugins/tracker-resources/src/plugin.ts index 1192cd6d8b..9ddd72d27e 100644 --- a/plugins/tracker-resources/src/plugin.ts +++ b/plugins/tracker-resources/src/plugin.ts @@ -17,12 +17,14 @@ import type { IntlString, Metadata, Resource } from '@hcengineering/platform' import { mergeIds } from '@hcengineering/platform' import { IssueDraft } from '@hcengineering/tracker' import { AnyComponent, Location } from '@hcengineering/ui' -import { SortFunc, Viewlet, ViewQueryAction } from '@hcengineering/view' +import { SortFunc, Viewlet, ViewletDescriptor, ViewQueryAction } from '@hcengineering/view' import tracker, { trackerId } from '../../tracker/lib' export default mergeIds(trackerId, tracker, { viewlet: { - SubIssues: '' as Ref + SubIssues: '' as Ref, + List: '' as Ref, + Kanban: '' as Ref }, string: { More: '' as IntlString, diff --git a/plugins/tracker-resources/src/utils.ts b/plugins/tracker-resources/src/utils.ts index 1abdd5a633..ae4dd5b4b2 100644 --- a/plugins/tracker-resources/src/utils.ts +++ b/plugins/tracker-resources/src/utils.ts @@ -33,6 +33,8 @@ import { TypeState } from '@hcengineering/kanban' import { Asset, IntlString, translate } from '@hcengineering/platform' import { createQuery, getClient } from '@hcengineering/presentation' import { + Component, + ComponentStatus, Issue, IssuePriority, IssuesDateModificationPeriod, @@ -40,11 +42,9 @@ import { IssuesOrdering, IssueStatus, IssueTemplateData, - Component, - ComponentStatus, + Project, Sprint, SprintStatus, - Project, TimeReportDayType } from '@hcengineering/tracker' import { @@ -55,10 +55,11 @@ import { isWeekend, MILLISECONDS_IN_WEEK } from '@hcengineering/ui' +import { ViewletDescriptor } from '@hcengineering/view' import { CategoryQuery, ListSelectionProvider, SelectDirection } from '@hcengineering/view-resources' import { writable } from 'svelte/store' import tracker from './plugin' -import { defaultPriorities, defaultComponentStatuses, defaultSprintStatuses, issuePriorities } from './types' +import { defaultComponentStatuses, defaultPriorities, defaultSprintStatuses, issuePriorities } from './types' export * from './types' @@ -331,11 +332,33 @@ const listIssueStatusOrder = [ tracker.issueStatusCategory.Canceled ] as const -export async function issueStatusSort (value: Array>): Promise>> { +const listIssueKanbanStatusOrder = [ + tracker.issueStatusCategory.Backlog, + tracker.issueStatusCategory.Unstarted, + tracker.issueStatusCategory.Started, + tracker.issueStatusCategory.Completed, + tracker.issueStatusCategory.Canceled +] as const + +export async function issueStatusSort ( + value: Array>, + viewletDescriptorId?: Ref +): Promise>> { return await new Promise((resolve) => { + // TODO: How we track category updates. const query = createQuery(true) query.query(tracker.class.IssueStatus, { _id: { $in: value } }, (res) => { - res.sort((a, b) => listIssueStatusOrder.indexOf(a.category) - listIssueStatusOrder.indexOf(b.category)) + if (viewletDescriptorId === tracker.viewlet.Kanban) { + res.sort((a, b) => { + const res = listIssueKanbanStatusOrder.indexOf(a.category) - listIssueKanbanStatusOrder.indexOf(b.category) + if (res === 0) { + return a.rank.localeCompare(b.rank) + } + return res + }) + } else { + res.sort((a, b) => listIssueStatusOrder.indexOf(a.category) - listIssueStatusOrder.indexOf(b.category)) + } resolve(res.map((p) => p._id)) query.unsubscribe() }) diff --git a/plugins/view-resources/src/components/list/List.svelte b/plugins/view-resources/src/components/list/List.svelte index 68e5dc699c..cd617fd654 100644 --- a/plugins/view-resources/src/components/list/List.svelte +++ b/plugins/view-resources/src/components/list/List.svelte @@ -86,7 +86,7 @@ if (viewOptions === undefined) return query let result = hierarchy.clone(query) for (const viewOption of viewOptions) { - if (viewOption.actionTartget !== 'query') continue + if (viewOption.actionTarget !== 'query') continue const queryOption = viewOption as ViewQueryOption const f = await getResource(queryOption.action) result = f(viewOptionsStore[queryOption.key] ?? queryOption.defaultValue, query) diff --git a/plugins/view-resources/src/components/list/ListCategories.svelte b/plugins/view-resources/src/components/list/ListCategories.svelte index 0e9098d2fc..9576b70ed3 100644 --- a/plugins/view-resources/src/components/list/ListCategories.svelte +++ b/plugins/view-resources/src/components/list/ListCategories.svelte @@ -74,7 +74,7 @@ categories = await getCategories(client, _class, docs, groupByKey) if (level === 0) { for (const viewOption of viewOptionsModel ?? []) { - if (viewOption.actionTartget !== 'category') continue + if (viewOption.actionTarget !== 'category') continue const categoryFunc = viewOption as CategoryOption if (viewOptions[viewOption.key] ?? viewOption.defaultValue) { const f = await getResource(categoryFunc.action) diff --git a/plugins/view-resources/src/utils.ts b/plugins/view-resources/src/utils.ts index 1bc62a8398..5721d41d28 100644 --- a/plugins/view-resources/src/utils.ts +++ b/plugins/view-resources/src/utils.ts @@ -43,7 +43,7 @@ import { Location, locationToUrl } from '@hcengineering/ui' -import type { BuildModelOptions, Viewlet } from '@hcengineering/view' +import type { BuildModelOptions, Viewlet, ViewletDescriptor } from '@hcengineering/view' import view, { AttributeModel, BuildModelKey } from '@hcengineering/view' import { writable } from 'svelte/store' import plugin from './plugin' @@ -528,11 +528,24 @@ export async function getCategories ( client: TxOperations, _class: Ref>, docs: Doc[], - key: string + key: string, + viewletDescriptorId?: Ref +): Promise { + if (key === noCategory) return [undefined] + const existingCategories = Array.from(new Set(docs.map((x: any) => x[key] ?? undefined))) + + return await sortCategories(client, _class, existingCategories, key, viewletDescriptorId) +} + +export async function sortCategories ( + client: TxOperations, + _class: Ref>, + existingCategories: any[], + key: string, + viewletDescriptorId?: Ref ): Promise { if (key === noCategory) return [undefined] const hierarchy = client.getHierarchy() - const existingCategories = Array.from(new Set(docs.map((x: any) => x[key] ?? undefined))) const attr = hierarchy.getAttribute(_class, key) if (attr === undefined) return existingCategories const attrClass = getAttributePresenterClass(hierarchy, attr).attrClass @@ -541,7 +554,7 @@ export async function getCategories ( if (sortFunc?.func === undefined) return existingCategories const f = await getResource(sortFunc.func) - return await f(existingCategories) + return await f(existingCategories, viewletDescriptorId) } export function getKeyLabel ( diff --git a/plugins/view/src/index.ts b/plugins/view/src/index.ts index 5981597631..be880e56a9 100644 --- a/plugins/view/src/index.ts +++ b/plugins/view/src/index.ts @@ -236,7 +236,7 @@ export interface ListHeaderExtra extends Class { /** * @public */ -export type SortFunc = Resource<(values: any[]) => Promise> +export type SortFunc = Resource<(values: any[], viewletDescriptorId?: Ref) => Promise> /** * @public @@ -483,7 +483,7 @@ export interface ViewOption { defaultValue: any label: IntlString hidden?: (viewOptions: ViewOptions) => boolean - actionTartget?: 'query' | 'category' + actionTarget?: 'query' | 'category' action?: Resource<(value: any, ...params: any) => any> } @@ -504,7 +504,7 @@ export type ViewCategoryAction = Resource< * @public */ export interface CategoryOption extends ViewOption { - actionTartget: 'category' + actionTarget: 'category' action: ViewCategoryAction } @@ -517,7 +517,7 @@ export type ViewQueryAction = Resource<(value: any, query: DocumentQuery) = * @public */ export interface ViewQueryOption extends ViewOption { - actionTartget: 'query' + actionTarget: 'query' action: ViewQueryAction }