UBERF-8580: Labels for Tracker (#7141)
Some checks are pending
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / formatting (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
CI / dist-build (push) Blocked by required conditions

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2024-11-11 12:06:30 +07:00 committed by GitHub
parent 6ea2be19b5
commit dafa5275cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 138 additions and 65 deletions

View File

@ -304,6 +304,7 @@ function defineApplication (
componentsId: string
milestonesId: string
templatesId: string
labelsId: string
}
): void {
builder.createDoc(
@ -365,6 +366,15 @@ function defineApplication (
icon: view.icon.List,
label: tracker.string.AllProjects
}
},
{
id: opt.labelsId,
component: tracker.component.LabelsView,
accessLevel: AccountRole.User,
icon: tracker.icon.Labels,
label: tracker.string.Labels,
// createItemLabel: task.string.TaskCreateLabel,
position: 'bottom'
}
],
spaces: [
@ -477,6 +487,7 @@ export function createModel (builder: Builder): void {
const templatesId = 'templates'
const myIssuesId = 'my-issues'
const allIssuesId = 'all-issues'
const labelsId = 'labels'
// const scrumsId = 'scrums'
definePresenters(builder)
@ -587,7 +598,7 @@ export function createModel (builder: Builder): void {
tracker.ids.IssueTemplateUpdatedActivityViewlet
)
defineApplication(builder, { myIssuesId, allIssuesId, issuesId, componentsId, milestonesId, templatesId })
defineApplication(builder, { myIssuesId, allIssuesId, issuesId, componentsId, milestonesId, templatesId, labelsId })
defineActions(builder, issuesId, componentsId, myIssuesId)

View File

@ -88,6 +88,8 @@
$: visibleCategories = categories.filter((it) => categoryKeys.includes(it._id))
$: dispatch('categories', visibleCategories)
const selectItem = (item: TagCategory): void => {
if (category === item._id) {
category = undefined
@ -129,7 +131,7 @@
}
</script>
{#if visibleCategories.length > 0}
{#if visibleCategories.length > 1}
<div class="hulyHeader-container clearPadding justify-between flex-gap-4">
<ModernButton
label={tags.string.AllCategories}

View File

@ -107,49 +107,43 @@
on:changeContent
>
<div class="flex-row-top clear-mins">
<div class="mr-3">
<Button size={'medium'} kind={'link-bordered'} on:click={showColorPopup}>
<svelte:fragment slot="content">
<div class="color pointer-events-none" style={getTagStyle(getPlatformColorDef(color, $themeStore.dark))} />
</svelte:fragment>
</Button>
</div>
<div class="flex-col mt-0-5 w-full">
<EditBox
bind:value={title}
placeholder={tags.string.TagName}
placeholderParam={{ word: keyTitle }}
kind={'large-style'}
autoFocus
/>
<div class="mt-2">
<EditBox bind:value={description} placeholder={tags.string.TagDescriptionPlaceholder} kind={'small-style'} />
<div class="mr-3 flex-grow">
<div class="fs-title flex-row-center">
<div
class="color"
style={getTagStyle(getPlatformColorDef(color, $themeStore.dark))}
on:click={showColorPopup}
/>
<EditBox bind:value={title} placeholder={tags.string.TagName} placeholderParam={{ word: keyTitle }} autoFocus />
</div>
<div class="fs-title mt-4 flex-grow">
<EditBox bind:value={description} placeholder={tags.string.TagDescriptionPlaceholder} />
</div>
{#if categories.length > 1}
<div class="text-sm mt-4">
<DropdownLabels
icon={IconFolder}
label={tags.string.CategoryLabel}
kind={'regular'}
bind:selected={category}
items={categoryItems}
on:selected={() => {
categoryWasSet = true
}}
/>
</div>
{/if}
</div>
</div>
<svelte:fragment slot="pool">
{#if categories.length > 1}
<div class="ml-12">
<DropdownLabels
icon={IconFolder}
label={tags.string.CategoryLabel}
kind={'regular'}
size={'large'}
bind:selected={category}
items={categoryItems}
on:selected={() => {
categoryWasSet = true
}}
/>
</div>
{/if}
</svelte:fragment>
</Card>
<style lang="scss">
.color {
margin-right: 0.75rem;
width: 1rem;
height: 1rem;
border-radius: 0.25rem;
cursor: pointer;
}
</style>

View File

@ -94,6 +94,18 @@
}
categoryItems = newItems
})
const showColorPopup = (evt: MouseEvent): void => {
showPopup(
ColorsPopup,
{ selected: getPlatformColorDef(data.color, $themeStore.dark).name },
eventToHTMLElement(evt),
(col) => {
if (col != null) {
data.color = col
}
}
)
}
</script>
<Card
@ -107,37 +119,31 @@
okLabel={tags.string.SaveLabel}
on:changeContent
>
<div class="flex-row-center">
<div class="flex-col">
<div class="flex-row-top clear-mins">
<div class="mr-3 flex-grow">
<div class="fs-title flex-row-center">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
class="color"
style={getTagStyle(getPlatformColorDef(data.color, $themeStore.dark))}
on:click={(evt) => {
showPopup(
ColorsPopup,
{ selected: getPlatformColorDef(data.color, $themeStore.dark).name },
eventToHTMLElement(evt),
(col) => {
if (col != null) {
data.color = col
}
}
)
}}
on:click={showColorPopup}
/>
<EditBox placeholder={tags.string.TagName} placeholderParam={{ word: keyTitle }} bind:value={data.title} />
</div>
<div class="fs-title mt-4">
<div class="fs-title mt-4 flex-grow">
<EditBox placeholder={tags.string.TagDescriptionPlaceholder} bind:value={data.description} />
</div>
<div class="text-sm mt-4">
<DropdownLabels label={tags.string.CategoryLabel} bind:selected={data.category} items={categoryItems} />
</div>
{#if categoryItems.length > 1}
<div class="text-sm mt-4">
<DropdownLabels
label={tags.string.CategoryLabel}
kind={'regular'}
bind:selected={data.category}
items={categoryItems}
/>
</div>
{/if}
</div>
</div>
</Card>

View File

@ -95,7 +95,7 @@
(tagElements?.get(b._id as Ref<TagElement>)?.count ?? 0) -
(tagElements?.get(a._id as Ref<TagElement>)?.count ?? 0) ?? 0
// $: twoRows = $deviceInfo.twoRows
let visibleCategories: TagCategory[] = []
</script>
<Header adaptive={'disabled'}>
@ -123,6 +123,9 @@
category = evt.detail.category ?? undefined
updateResultQuery(search, category)
}}
on:categories={(evt) => {
visibleCategories = evt.detail
}}
/>
<TableBrowser
_class={tags.class.TagElement}
@ -134,12 +137,16 @@
props: { edit: true, keyTitle },
sortingKey: 'title'
},
{
key: '$lookup.category',
presenter: tags.component.CategoryPresenter,
sortingKey: 'category',
label: tags.string.CategoryLabel
},
...(visibleCategories.length > 1
? [
{
key: '$lookup.category',
presenter: tags.component.CategoryPresenter,
sortingKey: 'category',
label: tags.string.CategoryLabel
}
]
: []),
{
key: '',
presenter: tags.component.TagElementCountPresenter,

View File

@ -61,6 +61,7 @@
"@hcengineering/query": "^0.6.12",
"@hcengineering/setting": "^0.6.17",
"@hcengineering/tags": "^0.6.16",
"@hcengineering/tags-resources": "^0.6.0",
"@hcengineering/task": "^0.6.20",
"@hcengineering/task-resources": "^0.6.0",
"@hcengineering/text-editor-resources": "^0.6.0",

View File

@ -0,0 +1,49 @@
<script lang="ts">
import { getClient } from '@hcengineering/presentation'
import tags, { TagElement } from '@hcengineering/tags'
import { selectedTagElements } from '@hcengineering/tags-resources'
import { Component, getCurrentResolvedLocation, navigate } from '@hcengineering/ui'
import { Filter } from '@hcengineering/view'
import { buildFilterKey, setFilters } from '@hcengineering/view-resources'
import tracker from '../plugin'
function setFilterTag (tag: TagElement) {
const client = getClient()
const hierarchy = client.getHierarchy()
const attribute = hierarchy.getAttribute(tracker.class.Issue, 'labels')
const key = buildFilterKey(hierarchy, tracker.class.Issue, '_class', attribute)
const filter = {
key,
value: [tag._id],
props: { level: 0 },
modes: [tags.filter.FilterTagsIn, tags.filter.FilterTagsNin],
mode: tags.filter.FilterTagsIn,
index: 1
} as unknown as Filter
setFilters([filter])
}
async function onTag (tag: TagElement): Promise<void> {
selectedTagElements.set([tag._id])
const loc = getCurrentResolvedLocation()
loc.path[2] = 'tracker'
loc.path[3] = 'all-issues'
loc.path.length = 4
navigate(loc)
setTimeout(() => {
setFilterTag(tag)
}, 200)
}
</script>
<Component
is={tags.component.TagsView}
props={{
targetClass: tracker.class.Issue,
title: tracker.string.Labels,
icon: tracker.icon.Labels,
item: tracker.string.Labels,
key: 'labels',
сreateItemLabel: tracker.string.AddLabel,
onTag
}}
></Component>

View File

@ -89,6 +89,7 @@ import SetDueDateActionPopup from './components/SetDueDateActionPopup.svelte'
import SetParentIssueActionPopup from './components/SetParentIssueActionPopup.svelte'
import SettingsRelatedTargets from './components/SettingsRelatedTargets.svelte'
import CreateIssueTemplate from './components/templates/CreateIssueTemplate.svelte'
import LabelsView from './components/LabelsView.svelte'
import {
getIssueIdByIdentifier,
getIssueTitle,
@ -660,7 +661,8 @@ export default async (): Promise<Resources> => ({
IssueSearchIcon,
MembersArrayEditor,
IssueExtra,
IssueStatusPresenter
IssueStatusPresenter,
LabelsView
},
completion: {
IssueQuery: async (client: Client, query: string, filter?: { in?: RelatedDocument[], nin?: RelatedDocument[] }) =>

View File

@ -407,7 +407,8 @@ const pluginState = plugin(trackerId, {
ProjectPresenter: '' as AnyComponent,
CreateIssueTemplate: '' as AnyComponent,
CreateProject: '' as AnyComponent,
IssueStatusPresenter: '' as AnyComponent
IssueStatusPresenter: '' as AnyComponent,
LabelsView: '' as AnyComponent
},
attribute: {
IssueStatus: '' as Ref<Attribute<Status>>