From 84cfd93227cbae8e626c5d3ee2fd30f30a206d7c Mon Sep 17 00:00:00 2001 From: Alex <41288429+Dvinyanin@users.noreply.github.com> Date: Wed, 1 Jun 2022 23:08:22 +0700 Subject: [PATCH] Add project selector (#1973) Signed-off-by: Dvinyanin Alexandr <dvinyanin.alexandr@gmail.com> --- changelog.md | 1 + .../components/issues/IssuesFilterMenu.svelte | 25 +++++++ .../issues/ProjectFilterMenuSection.svelte | 66 +++++++++++++++++++ plugins/tracker-resources/src/utils.ts | 15 ++++- plugins/tracker/src/index.ts | 1 + 5 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 plugins/tracker-resources/src/components/issues/ProjectFilterMenuSection.svelte diff --git a/changelog.md b/changelog.md index 0d834e9eb5..b1d4d99a1d 100644 --- a/changelog.md +++ b/changelog.md @@ -9,6 +9,7 @@ Platform: - Allow to define table columns order - Fix skills/labels selection and show real usage counter - Fix skills/labels activity +- Project selector in issue list HR: diff --git a/plugins/tracker-resources/src/components/issues/IssuesFilterMenu.svelte b/plugins/tracker-resources/src/components/issues/IssuesFilterMenu.svelte index 636e11239c..3340137f33 100644 --- a/plugins/tracker-resources/src/components/issues/IssuesFilterMenu.svelte +++ b/plugins/tracker-resources/src/components/issues/IssuesFilterMenu.svelte @@ -18,6 +18,7 @@ import { showPopup } from '@anticrm/ui' import StatusFilterMenuSection from './StatusFilterMenuSection.svelte' import PriorityFilterMenuSection from './PriorityFilterMenuSection.svelte' + import ProjectFilterMenuSection from './ProjectFilterMenuSection.svelte' import FilterMenu from '../FilterMenu.svelte' import { defaultPriorities, @@ -40,6 +41,7 @@ $: defaultStatusIds = defaultStatuses.map((x) => x._id) $: groupedByStatus = getGroupedIssues('status', issues, defaultStatusIds) $: groupedByPriority = getGroupedIssues('priority', issues, defaultPriorities) + $: groupedByProject = getGroupedIssues('project', issues) const handleStatusFilterMenuSectionOpened = (event: MouseEvent | KeyboardEvent) => { const statusGroups: { [key: string]: number } = {} @@ -82,6 +84,25 @@ ) } + const handleProjectFilterMenuSectionOpened = (event: MouseEvent | KeyboardEvent) => { + const projectGroups: { [key: string]: number } = {} + + for (const [project, value] of Object.entries(groupedByProject)) { + projectGroups[project] = value?.length ?? 0 + } + showPopup( + ProjectFilterMenuSection, + { + groups: projectGroups, + selectedElements: currentFilterQuery?.project?.[currentFilterMode] ?? [], + index, + onUpdate, + onBack + }, + targetHtml + ) + } + const actions: FilterAction[] = [ { ...getIssueFilterAssetsByType('status'), @@ -90,6 +111,10 @@ { ...getIssueFilterAssetsByType('priority'), onSelect: handlePriorityFilterMenuSectionOpened + }, + { + ...getIssueFilterAssetsByType('project'), + onSelect: handleProjectFilterMenuSectionOpened } ] </script> diff --git a/plugins/tracker-resources/src/components/issues/ProjectFilterMenuSection.svelte b/plugins/tracker-resources/src/components/issues/ProjectFilterMenuSection.svelte new file mode 100644 index 0000000000..cf1036b639 --- /dev/null +++ b/plugins/tracker-resources/src/components/issues/ProjectFilterMenuSection.svelte @@ -0,0 +1,66 @@ +<!-- +// Copyright © 2022 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +--> +<script lang="ts"> + import { translate } from '@anticrm/platform' + import { IconNavPrev } from '@anticrm/ui' + import FilterMenuSection from '../FilterMenuSection.svelte' + import tracker from '../../plugin' + import { FilterSectionElement } from '../../utils' + import { getClient } from '@anticrm/presentation' + + export let selectedElements: any[] = [] + export let groups: { [key: string]: number } + export let index: number = 0 + export let onUpdate: (result: { [p: string]: any }, filterIndex?: number) => void + export let onBack: (() => void) | undefined = undefined + + const getFilterElements = async (groups: { [key: string]: number }, selected: any[]) => { + const elements: FilterSectionElement[] = [] + + const client = getClient() + const projects = await client.findAll(tracker.class.Project, {}) + for (const [key, value] of Object.entries(groups)) { + const project = key === 'null' ? null : key + const label = project + ? projects.find(({ _id }) => _id === project)?.label + : await translate(tracker.string.NoProject, {}) + + if (!label) { + continue + } + elements.splice(project ? 1 : 0, 0, { + icon: tracker.icon.Project, + title: label, + count: value, + isSelected: selected.includes(project), + onSelect: () => onUpdate({ project }, index) + }) + } + return onBack + ? [ + { + icon: IconNavPrev, + title: await translate(tracker.string.Back, {}), + onSelect: onBack + }, + ...elements + ] + : elements + } +</script> + +{#await getFilterElements(groups, selectedElements) then actions} + <FilterMenuSection {actions} {onBack} on:close /> +{/await} diff --git a/plugins/tracker-resources/src/utils.ts b/plugins/tracker-resources/src/utils.ts index 7869cc6d0e..0e749c6523 100644 --- a/plugins/tracker-resources/src/utils.ts +++ b/plugins/tracker-resources/src/utils.ts @@ -53,6 +53,7 @@ export const issuesGroupByOptions: Record<IssuesGrouping, IntlString> = { [IssuesGrouping.Status]: tracker.string.Status, [IssuesGrouping.Assignee]: tracker.string.Assignee, [IssuesGrouping.Priority]: tracker.string.Priority, + [IssuesGrouping.Project]: tracker.string.Project, [IssuesGrouping.NoGrouping]: tracker.string.NoGrouping } @@ -69,13 +70,14 @@ export const issuesDateModificationPeriodOptions: Record<IssuesDateModificationP [IssuesDateModificationPeriod.PastMonth]: tracker.string.PastMonth } -export type IssuesGroupByKeys = keyof Pick<Issue, 'status' | 'priority' | 'assignee'> +export type IssuesGroupByKeys = keyof Pick<Issue, 'status' | 'priority' | 'assignee' | 'project'> export type IssuesOrderByKeys = keyof Pick<Issue, 'status' | 'priority' | 'modifiedOn' | 'dueDate'> export const issuesGroupKeyMap: Record<IssuesGrouping, IssuesGroupByKeys | undefined> = { [IssuesGrouping.Status]: 'status', [IssuesGrouping.Priority]: 'priority', [IssuesGrouping.Assignee]: 'assignee', + [IssuesGrouping.Project]: 'project', [IssuesGrouping.NoGrouping]: undefined } @@ -93,9 +95,10 @@ export const issuesSortOrderMap: Record<IssuesOrderByKeys, SortingOrder> = { dueDate: SortingOrder.Descending } -export const issuesGroupEditorMap: Record<'status' | 'priority', AnyComponent | undefined> = { +export const issuesGroupEditorMap: Record<'status' | 'priority' | 'project', AnyComponent | undefined> = { status: tracker.component.StatusEditor, - priority: tracker.component.PriorityEditor + priority: tracker.component.PriorityEditor, + project: tracker.component.ProjectEditor } export const getIssuesModificationDatePeriodTime = (period: IssuesDateModificationPeriod | null): number => { @@ -206,6 +209,12 @@ export const getIssueFilterAssetsByType = (type: string): { icon: Asset, label: label: tracker.string.Priority } } + case 'project': { + return { + icon: tracker.icon.Project, + label: tracker.string.Project + } + } default: { return undefined } diff --git a/plugins/tracker/src/index.ts b/plugins/tracker/src/index.ts index efae016f48..3da950976d 100644 --- a/plugins/tracker/src/index.ts +++ b/plugins/tracker/src/index.ts @@ -71,6 +71,7 @@ export enum IssuesGrouping { Status = 'status', Assignee = 'assignee', Priority = 'priority', + Project = 'project', NoGrouping = 'noGrouping' }