mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-14 12:25:17 +00:00
Improve TagsPopup (#4879)
Signed-off-by: Stepan Grigorovich <gsdstr@gmail.com>
This commit is contained in:
parent
9ebdb9a985
commit
768d57348b
@ -16,6 +16,7 @@
|
||||
"TagCreateLabel": "Tag",
|
||||
"CancelLabel": "Cancel",
|
||||
"SearchCreate": "Search/Name ...",
|
||||
"QuickAddItems": "Quick Add {word} \"{title}\"",
|
||||
"NoItems": "There is no {word} added ...",
|
||||
"TagDescriptionLabel": "Description",
|
||||
"TagDescriptionPlaceholder": "Please type description here",
|
||||
|
@ -16,6 +16,7 @@
|
||||
"TagCreateLabel": "Etiqueta",
|
||||
"CancelLabel": "Cancelar",
|
||||
"SearchCreate": "Buscar/Nombre...",
|
||||
"QuickAddItems": "Agregar {word} rápidamente \"{title}\"",
|
||||
"NoItems": "No hay ninguna {word} añadida...",
|
||||
"TagDescriptionLabel": "Descripción",
|
||||
"TagDescriptionPlaceholder": "Escriba la descripción aquí",
|
||||
|
@ -16,6 +16,7 @@
|
||||
"TagCreateLabel": "Etiqueta",
|
||||
"CancelLabel": "Cancelar",
|
||||
"SearchCreate": "Pesquisar/Nome...",
|
||||
"QuickAddItems": "{word} de adição rápida \"{title}\"",
|
||||
"NoItems": "Não há nenhuma {word} adicionada...",
|
||||
"TagDescriptionLabel": "Descrição",
|
||||
"TagDescriptionPlaceholder": "Escreva a descrição aqui",
|
||||
|
@ -16,6 +16,7 @@
|
||||
"TagCreateLabel": "Тег",
|
||||
"CancelLabel": "Отмена",
|
||||
"SearchCreate": "Название...",
|
||||
"QuickAddItems": "Быстрое добавление {word} \"{title}\"",
|
||||
"NoItems": "Отсутствует добавленный {word}",
|
||||
"TagDescriptionLabel": "Описание",
|
||||
"TagDescriptionPlaceholder": "Пожалуйста, введите описание",
|
||||
|
@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Class, Data, Doc, generateId, Ref } from '@hcengineering/core'
|
||||
import { Card, createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { findTagCategory, TagCategory, TagElement } from '@hcengineering/tags'
|
||||
import { Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { Card, createQuery } from '@hcengineering/presentation'
|
||||
import { findTagCategory, TagCategory } from '@hcengineering/tags'
|
||||
import {
|
||||
Button,
|
||||
DropdownLabels,
|
||||
@ -31,14 +31,14 @@
|
||||
import { ColorsPopup } from '@hcengineering/view-resources'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import tags from '../plugin'
|
||||
import { getTagStyle } from '../utils'
|
||||
import { createTagElement, getTagStyle } from '../utils'
|
||||
|
||||
export let targetClass: Ref<Class<Doc>>
|
||||
export let keyTitle: string = ''
|
||||
export let title: string = ''
|
||||
|
||||
let title = ''
|
||||
let description = ''
|
||||
let color: number = 0
|
||||
let color: number = getColorNumberByText(title)
|
||||
|
||||
let categoryWasSet = false
|
||||
let category: Ref<TagCategory> | undefined
|
||||
@ -61,8 +61,6 @@
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
const tagElementId = generateId()
|
||||
|
||||
const query = createQuery()
|
||||
|
||||
@ -78,19 +76,12 @@
|
||||
categoryItems = newItems
|
||||
})
|
||||
|
||||
async function createTagElenent () {
|
||||
const tagElement: Data<TagElement> = {
|
||||
title,
|
||||
description,
|
||||
targetClass,
|
||||
color,
|
||||
category: category ?? tags.category.NoCategory
|
||||
}
|
||||
|
||||
await client.createDoc(tags.class.TagElement, tags.space.Tags, tagElement, tagElementId)
|
||||
dispatch('close')
|
||||
async function createTagElementFnc (): Promise<void> {
|
||||
const res = await createTagElement(title, targetClass, category, description, color)
|
||||
dispatch('close', res)
|
||||
}
|
||||
const showColorPopup = (evt: MouseEvent) => {
|
||||
|
||||
const showColorPopup = (evt: MouseEvent): void => {
|
||||
showPopup(
|
||||
ColorsPopup,
|
||||
{ selected: getPlatformColorDef(color, $themeStore.dark).name },
|
||||
@ -108,7 +99,7 @@
|
||||
<Card
|
||||
label={tags.string.AddTag}
|
||||
labelProps={{ word: keyTitle }}
|
||||
okAction={createTagElenent}
|
||||
okAction={createTagElementFnc}
|
||||
canSave={title.length > 0}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
|
@ -16,7 +16,7 @@
|
||||
import { Class, Doc, Ref } from '@hcengineering/core'
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { TagCategory, TagElement } from '@hcengineering/tags'
|
||||
import { findTagCategory, TagCategory, TagElement } from '@hcengineering/tags'
|
||||
import {
|
||||
Button,
|
||||
EditWithIcon,
|
||||
@ -36,6 +36,7 @@
|
||||
import CreateTagElement from './CreateTagElement.svelte'
|
||||
import IconView from './icons/View.svelte'
|
||||
import IconViewHide from './icons/ViewHide.svelte'
|
||||
import { createTagElement } from '../utils'
|
||||
|
||||
export let newElements: TagElement[] = []
|
||||
export let targetClass: Ref<Class<Doc>>
|
||||
@ -52,12 +53,13 @@
|
||||
let objects: TagElement[] = []
|
||||
let categories: TagCategory[] = []
|
||||
let isSingleCategory = true
|
||||
let inProcess = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const query = createQuery()
|
||||
|
||||
const client = getClient()
|
||||
client.findAll(tags.class.TagCategory, { targetClass }).then((res) => {
|
||||
void client.findAll(tags.class.TagCategory, { targetClass }).then((res) => {
|
||||
categories = res
|
||||
isSingleCategory = categories.length <= 1
|
||||
})
|
||||
@ -67,8 +69,24 @@
|
||||
objects = newElements.concat(result)
|
||||
})
|
||||
|
||||
async function createTagElement (): Promise<void> {
|
||||
showPopup(CreateTagElement, { targetClass }, 'top')
|
||||
async function onCreateTagElement (res: any): Promise<void> {
|
||||
if (res === null) return
|
||||
setTimeout(() => {
|
||||
const tag = objects.findLast((e) => e._id === res)
|
||||
if (tag === undefined) return
|
||||
selected = [...selected, tag._id]
|
||||
dispatch('update', { action: 'add', tag })
|
||||
inProcess = false
|
||||
}, 1)
|
||||
}
|
||||
|
||||
async function createTagElementPopup (): Promise<void> {
|
||||
showPopup(CreateTagElement, { targetClass, title: search }, 'top', onCreateTagElement)
|
||||
}
|
||||
|
||||
async function createTagElementQuick (): Promise<void> {
|
||||
const res = await createTagElement(search, targetClass, findTagCategory(search, categories))
|
||||
await onCreateTagElement(res)
|
||||
}
|
||||
|
||||
const isSelected = (selected: Ref<TagElement>[], element: TagElement): boolean => {
|
||||
@ -94,13 +112,23 @@
|
||||
if (count > 0) return count.toString()
|
||||
return ''
|
||||
}
|
||||
const tagSort = (a: TagElement, b: TagElement) => {
|
||||
const tagSort = (a: TagElement, b: TagElement): number => {
|
||||
const r = (b.refCount ?? 0) - (a.refCount ?? 0)
|
||||
if (r === 0) {
|
||||
return b.title.localeCompare(a.title)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
async function onSearchKeydown (ev: KeyboardEvent): Promise<void> {
|
||||
if (ev.code !== 'Enter') return
|
||||
if (!inProcess && objects.length < 1) {
|
||||
inProcess = true
|
||||
await createTagElementQuick()
|
||||
ev.preventDefault()
|
||||
}
|
||||
// TODO add first element or group?
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="selectPopup maxHeight" use:resizeObserver={() => dispatch('changeContent')}>
|
||||
@ -114,6 +142,7 @@
|
||||
{placeholder}
|
||||
{placeholderParam}
|
||||
on:change
|
||||
on:keydown={onSearchKeydown}
|
||||
/>
|
||||
{#if !isSingleCategory}
|
||||
<Button
|
||||
@ -125,7 +154,7 @@
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
{#if !hideAdd}<Button kind={'ghost'} size={'large'} icon={IconAdd} on:click={createTagElement} />{/if}
|
||||
{#if !hideAdd}<Button kind={'ghost'} size={'large'} icon={IconAdd} on:click={createTagElementPopup} />{/if}
|
||||
</div>
|
||||
<div class="scroll">
|
||||
<div class="box">
|
||||
@ -190,6 +219,11 @@
|
||||
{/if}
|
||||
{/each}
|
||||
{#if objects.length === 0}
|
||||
{#if !hideAdd}
|
||||
<button class="menu-item focus flex-row-center" on:click={createTagElementQuick}>
|
||||
<Label label={tags.string.QuickAddItems} params={{ word: keyLabel, title: search }} />
|
||||
</button>
|
||||
{/if}
|
||||
<div class="empty">
|
||||
<Label label={tags.string.NoItems} params={{ word: keyLabel }} />
|
||||
</div>
|
||||
|
@ -29,6 +29,7 @@ export default mergeIds(tagsId, tags, {
|
||||
AddNowTooltip: '' as IntlString,
|
||||
CancelLabel: '' as IntlString,
|
||||
SearchCreate: '' as IntlString,
|
||||
QuickAddItems: '' as IntlString,
|
||||
NoItems: '' as IntlString,
|
||||
TagDescriptionLabel: '' as IntlString,
|
||||
TagDescriptionPlaceholder: '' as IntlString,
|
||||
|
@ -1,13 +1,22 @@
|
||||
// Copyright © 2022 Hardcore Engineering Inc.
|
||||
|
||||
import { type Doc, type DocumentQuery, type FindResult, type Ref } from '@hcengineering/core'
|
||||
import {
|
||||
type Class,
|
||||
type Data,
|
||||
type Doc,
|
||||
type DocumentQuery,
|
||||
type FindResult,
|
||||
generateId,
|
||||
type Ref
|
||||
} from '@hcengineering/core'
|
||||
import { type Asset } from '@hcengineering/platform'
|
||||
import { type TagElement, type InitialKnowledge, type TagReference } from '@hcengineering/tags'
|
||||
import { type ColorDefinition } from '@hcengineering/ui'
|
||||
import { type TagElement, type InitialKnowledge, type TagReference, type TagCategory } from '@hcengineering/tags'
|
||||
import { type ColorDefinition, getColorNumberByText } from '@hcengineering/ui'
|
||||
import { type Filter } from '@hcengineering/view'
|
||||
import { FilterQuery } from '@hcengineering/view-resources'
|
||||
import tags from './plugin'
|
||||
import { writable } from 'svelte/store'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
|
||||
export function getTagStyle (color: ColorDefinition, selected = false): string {
|
||||
return `
|
||||
@ -60,3 +69,26 @@ export interface TagElementInfo {
|
||||
* @public
|
||||
*/
|
||||
export const selectedTagElements = writable<Array<Ref<TagElement>>>([])
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function createTagElement (
|
||||
title: string,
|
||||
targetClass: Ref<Class<Doc>>,
|
||||
category?: Ref<TagCategory> | null,
|
||||
description?: string | null,
|
||||
color?: number | null
|
||||
): Promise<any> {
|
||||
const tagElement: Data<TagElement> = {
|
||||
title,
|
||||
description: description ?? '',
|
||||
targetClass,
|
||||
color: color ?? getColorNumberByText(title),
|
||||
category: category ?? tags.category.NoCategory
|
||||
}
|
||||
|
||||
const client = getClient()
|
||||
const tagElementId = generateId()
|
||||
return await client.createDoc(tags.class.TagElement, tags.space.Tags, tagElement, tagElementId)
|
||||
}
|
||||
|
@ -39,7 +39,6 @@ export class TalentDetailsPage extends CommonRecruitingPage {
|
||||
await this.addNewTagPopup(this.page, skillTag, skillDescription)
|
||||
|
||||
await this.pressShowAllButtonSelectPopup(this.page)
|
||||
await this.checkFromDropdown(this.page, skillTag)
|
||||
|
||||
await this.page.keyboard.press('Escape')
|
||||
}
|
||||
|
@ -72,9 +72,10 @@ export class IssuesDetailsPage extends CommonTrackerPage {
|
||||
await this.buttonAddLabel.click()
|
||||
await this.pressCreateButtonSelectPopup(this.page)
|
||||
await this.addNewTagPopup(this.page, data.labels, 'Tag from editIssue')
|
||||
} else {
|
||||
await this.checkFromDropdownWithSearch(this.page, data.labels)
|
||||
}
|
||||
await this.checkFromDropdownWithSearch(this.page, data.labels)
|
||||
await this.inputTitle.click({ force: true })
|
||||
await this.inputTitle.press('Escape')
|
||||
}
|
||||
if (data.component != null) {
|
||||
await this.buttonComponent.click()
|
||||
|
@ -110,8 +110,10 @@ export class IssuesPage extends CommonTrackerPage {
|
||||
if (data.createLabel) {
|
||||
await this.pressCreateButtonSelectPopup(this.page)
|
||||
await this.addNewTagPopup(this.page, data.labels, 'Tag from createNewIssue')
|
||||
} else {
|
||||
await this.checkFromDropdown(this.page, data.labels)
|
||||
}
|
||||
await this.checkFromDropdown(this.page, data.labels)
|
||||
await this.inputPopupCreateNewIssueTitle.press('Escape')
|
||||
await this.inputPopupCreateNewIssueTitle.click({ force: true })
|
||||
}
|
||||
if (data.component != null) {
|
||||
|
Loading…
Reference in New Issue
Block a user