From b1268d6c177c3f0e264753252ef923b6097a433d Mon Sep 17 00:00:00 2001 From: Denis Bykhov Date: Wed, 7 Feb 2024 21:27:24 +0600 Subject: [PATCH] UBERF-5339 (#4566) Signed-off-by: Denis Bykhov --- dev/generator/src/issues.ts | 8 +- dev/generator/src/recruit.ts | 6 +- models/board/src/index.ts | 2 +- models/board/src/migration.ts | 21 ++++- models/lead/src/index.ts | 2 +- models/lead/src/migration.ts | 21 ++++- models/recruit/src/migration.ts | 24 ++++- models/server-recruit/src/index.ts | 5 +- models/server-tracker/src/index.ts | 5 +- models/task/src/index.ts | 9 +- models/tracker/src/migration.ts | 22 ++++- .../src/components/CreateCard.svelte | 27 +++++- .../src/components/EditCard.svelte | 2 +- .../board-resources/src/utils/CardUtils.ts | 4 +- .../src/components/CreateLead.svelte | 15 +++- .../src/components/EditLead.svelte | 2 +- .../src/components/KanbanCard.svelte | 2 +- .../src/components/LeadPresenter.svelte | 4 +- .../src/components/CreateApplication.svelte | 6 +- .../src/components/EditApplication.svelte | 6 +- plugins/recruit-resources/src/utils.ts | 15 ++-- plugins/task-assets/lang/en.json | 3 +- plugins/task-assets/lang/ru.json | 3 +- plugins/task/src/index.ts | 4 +- .../src/components/CreateIssue.svelte | 13 +-- .../SetParentIssueActionPopup.svelte | 25 +++--- .../src/components/issues/IssueItem.svelte | 6 +- .../components/issues/IssuePresenter.svelte | 19 ++-- .../src/components/issues/IssuePreview.svelte | 7 +- .../issues/NotificationIssuePresenter.svelte | 4 +- .../src/components/issues/ParentIssue.svelte | 17 +--- .../issues/RelationEditorPart.svelte | 33 +++---- .../issues/edit/ControlPanel.svelte | 3 +- .../components/issues/edit/EditIssue.svelte | 17 ++-- .../issues/edit/SubIssueSelector.svelte | 9 +- .../issues/edit/SubIssuesSelector.svelte | 5 +- .../related/RelatedIssuePresenter.svelte | 6 +- .../timereport/EstimationSubIssueList.svelte | 5 +- .../timereport/TimeSpendReportsList.svelte | 15 ++-- .../components/projects/ChangeIdentity.svelte | 34 ------- .../components/projects/CreateProject.svelte | 23 +---- plugins/tracker-resources/src/index.ts | 89 ++++++++----------- plugins/tracker-resources/src/issues.ts | 48 +++------- plugins/tracker-resources/src/utils.ts | 4 +- server-plugins/tracker-resources/src/index.ts | 13 ++- server/core/src/indexer/types.ts | 4 +- .../tests/model/tracker/edit-project-page.ts | 5 -- tests/sanity/tests/tracker/projects.spec.ts | 1 - 48 files changed, 295 insertions(+), 328 deletions(-) delete mode 100644 plugins/tracker-resources/src/components/projects/ChangeIdentity.svelte diff --git a/dev/generator/src/issues.ts b/dev/generator/src/issues.ts index 01c29b9ba5..c8fd9916ec 100644 --- a/dev/generator/src/issues.ts +++ b/dev/generator/src/issues.ts @@ -11,7 +11,7 @@ import core, { TxOperations, WorkspaceId } from '@hcengineering/core' -import tracker, { Issue, IssuePriority, IssueStatus } from '@hcengineering/tracker' +import tracker, { Issue, IssuePriority, IssueStatus, Project } from '@hcengineering/tracker' import { connect } from './connect' import { calcRank } from '@hcengineering/task' @@ -38,6 +38,7 @@ const object: AttachedData = { estimation: 0, reports: 0, childInfo: [], + identifier: '', kind: tracker.taskTypes.Issue } @@ -82,13 +83,15 @@ async function genIssue (client: TxOperations, statuses: Ref[]): Pr }, true ) + const project = (incResult as any).object as Project + const number = project.sequence const value: AttachedData = { title: faker.commerce.productName(), description: faker.lorem.paragraphs(), assignee: object.assignee, component: object.component, milestone: object.milestone, - number: (incResult as any).object.sequence, + number, status: faker.random.arrayElement(statuses), priority: faker.random.arrayElement(Object.values(IssuePriority)) as IssuePriority, rank: calcRank(lastOne, undefined), @@ -102,6 +105,7 @@ async function genIssue (client: TxOperations, statuses: Ref[]): Pr reports: 0, relations: [], childInfo: [], + identifier: `${project.identifier}-${number}`, kind: tracker.taskTypes.Issue } await client.addCollection( diff --git a/dev/generator/src/recruit.ts b/dev/generator/src/recruit.ts index 900a669bb4..841cfb1df0 100644 --- a/dev/generator/src/recruit.ts +++ b/dev/generator/src/recruit.ts @@ -178,14 +178,16 @@ async function genApplicant ( ): Promise { const applicantId = `vacancy-${vacancyId}-${candidateId}` as Ref + const number = faker.datatype.number() const applicant: AttachedData = { - number: faker.datatype.number(), + number, assignee: faker.random.arrayElement(emoloyeeIds), status: faker.random.arrayElement(states), rank, startDate: null, dueDate: null, - kind: recruit.taskTypes.Applicant + kind: recruit.taskTypes.Applicant, + identifier: `APP-${number}` } // Update or create candidate diff --git a/models/board/src/index.ts b/models/board/src/index.ts index cbe821fb8e..e3e1e34ea3 100644 --- a/models/board/src/index.ts +++ b/models/board/src/index.ts @@ -85,7 +85,7 @@ export class TCommonBoardPreference extends TPreference implements CommonBoardPr } @Model(board.class.Card, task.class.Task) -@UX(board.string.Card, board.icon.Card, undefined, 'title') +@UX(board.string.Card, board.icon.Card, 'CARD', 'title') export class TCard extends TTask implements Card { @Prop(TypeString(), board.string.Title) @Index(IndexKind.FullText) diff --git a/models/board/src/migration.ts b/models/board/src/migration.ts index 84eb3807bb..d41cc9614b 100644 --- a/models/board/src/migration.ts +++ b/models/board/src/migration.ts @@ -13,7 +13,7 @@ // limitations under the License. // -import { boardId } from '@hcengineering/board' +import { type Card, boardId } from '@hcengineering/board' import { type Ref, TxOperations } from '@hcengineering/core' import { type MigrateOperation, @@ -23,7 +23,7 @@ import { tryMigrate } from '@hcengineering/model' import core, { DOMAIN_SPACE } from '@hcengineering/model-core' -import { createProjectType, createSequence, fixTaskTypes } from '@hcengineering/model-task' +import { DOMAIN_TASK, createProjectType, createSequence, fixTaskTypes } from '@hcengineering/model-task' import tags from '@hcengineering/tags' import task, { type ProjectType } from '@hcengineering/task' import { PaletteColorIndexes } from '@hcengineering/ui/src/colors' @@ -126,6 +126,19 @@ async function createDefaults (tx: TxOperations): Promise { ) } +async function migrateIdentifiers (client: MigrationClient): Promise { + const docs = await client.find(DOMAIN_TASK, { _class: board.class.Card, identifier: { $exists: false } }) + for (const doc of docs) { + await client.update( + DOMAIN_TASK, + { _id: doc._id }, + { + identifier: `CARD-${doc.number}` + } + ) + } +} + export const boardOperation: MigrateOperation = { async migrate (client: MigrationClient): Promise { await tryMigrate(client, boardId, [ @@ -162,6 +175,10 @@ export const boardOperation: MigrateOperation = { } ]) } + }, + { + state: 'identifier', + func: migrateIdentifiers } ]) }, diff --git a/models/lead/src/index.ts b/models/lead/src/index.ts index 49537dd150..2cb82dfea5 100644 --- a/models/lead/src/index.ts +++ b/models/lead/src/index.ts @@ -67,7 +67,7 @@ export class TFunnel extends TProject implements Funnel { } @Model(lead.class.Lead, task.class.Task) -@UX(lead.string.Lead, lead.icon.Lead, undefined, 'title') +@UX(lead.string.Lead, lead.icon.Lead, 'LEAD', 'title') export class TLead extends TTask implements Lead { @Prop(TypeRef(contact.class.Contact), lead.string.Customer) @ReadOnly() diff --git a/models/lead/src/migration.ts b/models/lead/src/migration.ts index d64102aebc..fa017940be 100644 --- a/models/lead/src/migration.ts +++ b/models/lead/src/migration.ts @@ -14,7 +14,7 @@ // import { TxOperations } from '@hcengineering/core' -import { leadId } from '@hcengineering/lead' +import { type Lead, leadId } from '@hcengineering/lead' import { tryMigrate, tryUpgrade, @@ -23,7 +23,7 @@ import { type MigrationUpgradeClient } from '@hcengineering/model' import core, { DOMAIN_SPACE } from '@hcengineering/model-core' -import task, { createProjectType, createSequence, fixTaskTypes } from '@hcengineering/model-task' +import task, { DOMAIN_TASK, createProjectType, createSequence, fixTaskTypes } from '@hcengineering/model-task' import { PaletteColorIndexes } from '@hcengineering/ui/src/colors' import lead from './plugin' @@ -121,6 +121,19 @@ async function createDefaults (tx: TxOperations): Promise { await createSequence(tx, lead.class.Lead) } +async function migrateIdentifiers (client: MigrationClient): Promise { + const docs = await client.find(DOMAIN_TASK, { _class: lead.class.Lead, identifier: { $exists: false } }) + for (const doc of docs) { + await client.update( + DOMAIN_TASK, + { _id: doc._id }, + { + identifier: `LEAD-${doc.number}` + } + ) + } +} + export const leadOperation: MigrateOperation = { async migrate (client: MigrationClient): Promise { await tryMigrate(client, leadId, [ @@ -157,6 +170,10 @@ export const leadOperation: MigrateOperation = { } ]) } + }, + { + state: 'identifier', + func: migrateIdentifiers } ]) }, diff --git a/models/recruit/src/migration.ts b/models/recruit/src/migration.ts index 078d55e421..5de527fe4c 100644 --- a/models/recruit/src/migration.ts +++ b/models/recruit/src/migration.ts @@ -24,8 +24,8 @@ import { type MigrationUpgradeClient } from '@hcengineering/model' import tags, { type TagCategory } from '@hcengineering/model-tags' -import { createProjectType, createSequence, fixTaskTypes } from '@hcengineering/model-task' -import { recruitId } from '@hcengineering/recruit' +import { DOMAIN_TASK, createProjectType, createSequence, fixTaskTypes } from '@hcengineering/model-task' +import { type Applicant, recruitId } from '@hcengineering/recruit' import task, { type ProjectType } from '@hcengineering/task' import { PaletteColorIndexes } from '@hcengineering/ui/src/colors' import recruit from './plugin' @@ -67,6 +67,10 @@ export const recruitOperation: MigrateOperation = { } ]) } + }, + { + state: 'identifier', + func: migrateIdentifiers } ]) }, @@ -89,6 +93,22 @@ export const recruitOperation: MigrateOperation = { } } +async function migrateIdentifiers (client: MigrationClient): Promise { + const docs = await client.find(DOMAIN_TASK, { + _class: recruit.class.Applicant, + identifier: { $exists: false } + }) + for (const doc of docs) { + await client.update( + DOMAIN_TASK, + { _id: doc._id }, + { + identifier: `APP-${doc.number}` + } + ) + } +} + async function createDefaults (tx: TxOperations): Promise { await createSpaces(tx) diff --git a/models/server-recruit/src/index.ts b/models/server-recruit/src/index.ts index 6b4f5ae7db..c265f344ec 100644 --- a/models/server-recruit/src/index.ts +++ b/models/server-recruit/src/index.ts @@ -60,10 +60,7 @@ export function createModel (builder: Builder): void { component: contact.component.Avatar, props: [{ avatar: ['attachedTo', 'avatar'] }, { name: ['attachedTo', 'name'] }] }, - shortTitle: { - tmpl: 'APP-{number}', - props: ['number'] - }, + shortTitle: 'identifier', title: { tmpl: '{name} - {vacName}', props: [{ _class: ['attachedTo', '_class'] }, { name: ['attachedTo', 'name'] }, { vacName: ['space', 'name'] }] diff --git a/models/server-tracker/src/index.ts b/models/server-tracker/src/index.ts index 13272b8866..2487ddfdfc 100644 --- a/models/server-tracker/src/index.ts +++ b/models/server-tracker/src/index.ts @@ -42,10 +42,7 @@ export function createModel (builder: Builder): void { component: tracker.component.IssueSearchIcon, props: ['status', 'space'] }, - shortTitle: { - tmpl: '{identifier}-{number}', - props: [{ identifier: ['space', 'identifier'] }, 'number'] - }, + shortTitle: 'identifier', title: 'title' } }) diff --git a/models/task/src/index.ts b/models/task/src/index.ts index 734e57f6f0..7f38c27629 100644 --- a/models/task/src/index.ts +++ b/models/task/src/index.ts @@ -133,7 +133,14 @@ export class TTask extends TAttachedDoc implements Task { @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) attachments?: number - isDone?: boolean + @Prop(TypeBoolean(), getEmbeddedLabel('isDone')) + @Hidden() + isDone?: boolean + + @Prop(TypeString(), task.string.Identifier) + @ReadOnly() + @Index(IndexKind.Indexed) + identifier!: string } @Mixin(task.mixin.KanbanCard, core.class.Class) diff --git a/models/tracker/src/migration.ts b/models/tracker/src/migration.ts index 9c118ff59c..eb0026fe94 100644 --- a/models/tracker/src/migration.ts +++ b/models/tracker/src/migration.ts @@ -42,7 +42,9 @@ import { baseIssueTaskStatuses, classicIssueTaskStatuses, createStatesData, - type IssueStatus + type IssueStatus, + type Issue, + type Project } from '@hcengineering/tracker' import { PaletteColorIndexes } from '@hcengineering/ui/src/colors' import tracker from './plugin' @@ -333,6 +335,20 @@ async function restoreToDoCategory (client: MigrationClient): Promise { } } +async function migrateIdentifiers (client: MigrationClient): Promise { + const classes = client.hierarchy.getDescendants(tracker.class.Issue) + const issues = await client.find(DOMAIN_TASK, { _class: { $in: classes }, identifier: { $exists: false } }) + if (issues.length === 0) return + const projects = await client.find(DOMAIN_SPACE, { _class: tracker.class.Project }) + const projectsMap = toIdMap(projects) + for (const issue of issues) { + const project = projectsMap.get(issue.space) + if (project === undefined) continue + const identifier = project.identifier + '-' + issue.number + await client.update(DOMAIN_TASK, { _id: issue._id }, { $set: { identifier } }) + } +} + export const trackerOperation: MigrateOperation = { async migrate (client: MigrationClient): Promise { await tryMigrate(client, 'tracker', [ @@ -464,6 +480,10 @@ export const trackerOperation: MigrateOperation = { { state: 'restoreToDoCategory', func: restoreToDoCategory + }, + { + state: 'identifier', + func: migrateIdentifiers } ]) }, diff --git a/plugins/board-resources/src/components/CreateCard.svelte b/plugins/board-resources/src/components/CreateCard.svelte index 91ce861e39..02a1f05604 100644 --- a/plugins/board-resources/src/components/CreateCard.svelte +++ b/plugins/board-resources/src/components/CreateCard.svelte @@ -17,11 +17,12 @@ import type { Board, Card as BoardCard } from '@hcengineering/board' import core, { AttachedData, Ref, SortingOrder, Space, generateId } from '@hcengineering/core' import { OK, Status } from '@hcengineering/platform' - import { Card, SpaceSelector, getClient } from '@hcengineering/presentation' - import task, { calcRank } from '@hcengineering/task' + import { Card, SpaceSelector, createQuery, getClient } from '@hcengineering/presentation' + import task, { TaskType, calcRank } from '@hcengineering/task' import { EditBox, Grid, Status as StatusControl } from '@hcengineering/ui' import { createEventDispatcher } from 'svelte' import board from '../plugin' + import { TaskKindSelector } from '@hcengineering/task-resources' export let space: Ref @@ -32,12 +33,14 @@ const dispatch = createEventDispatcher() const client = getClient() - const cardId = generateId() + const cardId = generateId() export function canClose (): boolean { return title !== '' } + let kind: Ref | undefined = undefined + async function createCard () { const sp = await client.findOne(board.class.Board, { _id: _space as Ref }) if (sp === undefined) { @@ -51,6 +54,9 @@ if (status === undefined) { throw new Error('Status not found') } + if (kind === undefined) { + throw new Error('kind is not specified') + } const sequence = await client.findOne(task.class.Sequence, { attachedTo: board.class.Card }) if (sequence === undefined) { throw new Error('sequence object not found') @@ -59,10 +65,14 @@ const lastOne = await client.findOne(board.class.Card, {}, { sort: { rank: SortingOrder.Descending } }) const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true) + const number = (incResult as any).object.sequence + const value: AttachedData = { status: status._id, - number: (incResult as any).object.sequence, + number, title, + kind, + identifier: `CARD-${number}`, rank: calcRank(lastOne, undefined), assignee: null, description: '', @@ -75,6 +85,14 @@ await client.addCollection(board.class.Card, _space, _space, board.class.Board, 'cards', value, cardId) dispatch('close') } + + let boards: Board[] = [] + const boardQuery = createQuery() + boardQuery.query(board.class.Board, {}, (res) => { + boards = res + }) + + $: currentBoard = boards.find((it) => it._id === _space) + diff --git a/plugins/board-resources/src/components/EditCard.svelte b/plugins/board-resources/src/components/EditCard.svelte index bf11e4f5b2..247a30a16e 100644 --- a/plugins/board-resources/src/components/EditCard.svelte +++ b/plugins/board-resources/src/components/EditCard.svelte @@ -52,7 +52,7 @@ const mixins: Mixin[] = [] const allowedCollections = ['labels'] - const ignoreKeys = ['isArchived', 'location', 'title', 'description', 'status', 'number', 'assignee'] + const ignoreKeys = ['isArchived', 'location', 'title', 'description', 'status', 'number', 'assignee', 'identifier'] function change (field: string, value: any) { if (object) { diff --git a/plugins/board-resources/src/utils/CardUtils.ts b/plugins/board-resources/src/utils/CardUtils.ts index a223517fc6..9012469d01 100644 --- a/plugins/board-resources/src/utils/CardUtils.ts +++ b/plugins/board-resources/src/utils/CardUtils.ts @@ -27,15 +27,17 @@ export async function createCard ( const lastOne = await client.findOne(board.class.Card, {}, { sort: { rank: SortingOrder.Descending } }) const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true) + const number = (incResult as any).object.sequence const value: AttachedData = { title: '', status, startDate: null, dueDate: null, - number: (incResult as any).object.sequence, + number, rank: calcRank(lastOne, undefined), assignee: null, + identifier: `CARD-${number}`, description: '', ...attribues } diff --git a/plugins/lead-resources/src/components/CreateLead.svelte b/plugins/lead-resources/src/components/CreateLead.svelte index 49cb48b73c..9a724d97aa 100644 --- a/plugins/lead-resources/src/components/CreateLead.svelte +++ b/plugins/lead-resources/src/components/CreateLead.svelte @@ -20,12 +20,12 @@ import type { Customer, Funnel, Lead } from '@hcengineering/lead' import { OK, Status } from '@hcengineering/platform' import { Card, createQuery, getClient, InlineAttributeBar, SpaceSelector } from '@hcengineering/presentation' - import task, { calcRank, getStates } from '@hcengineering/task' + import task, { calcRank, getStates, TaskType } from '@hcengineering/task' + import { TaskKindSelector, typeStore } from '@hcengineering/task-resources' import { Button, createFocusManager, EditBox, FocusHandler, Label, Status as StatusControl } from '@hcengineering/ui' import { statusStore } from '@hcengineering/view-resources' import { createEventDispatcher } from 'svelte' import lead from '../plugin' - import { typeStore } from '@hcengineering/task-resources' export let space: Ref export let customer: Ref | null = null @@ -71,19 +71,27 @@ $: funnel = funnels.find((it) => it._id === _space) + let kind: Ref | undefined = undefined + async function createLead () { const sequence = await client.findOne(task.class.Sequence, { attachedTo: lead.class.Lead }) if (sequence === undefined || customer == null) { throw new Error('Lead creation failed') } + if (kind === undefined) { + throw new Error('kind is not specified') + } const lastOne = await client.findOne(lead.class.Lead, {}, { sort: { rank: SortingOrder.Descending } }) const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true) + const number = (incResult as any).object.sequence const value: AttachedData = { status: state, - number: (incResult as any).object.sequence, + number, + identifier: `LEAD-${number}`, title, + kind, rank: calcRank(lastOne, undefined), assignee: null, startDate: null, @@ -137,6 +145,7 @@ label: lead.string.CreateFunnel }} /> +
diff --git a/plugins/lead-resources/src/components/EditLead.svelte b/plugins/lead-resources/src/components/EditLead.svelte index eedc76a1f9..5417bf306b 100644 --- a/plugins/lead-resources/src/components/EditLead.svelte +++ b/plugins/lead-resources/src/components/EditLead.svelte @@ -39,7 +39,7 @@ } onMount(() => { - dispatch('open', { ignoreKeys: ['comments', 'number', 'title', 'customer'] }) + dispatch('open', { ignoreKeys: ['comments', 'number', 'title', 'customer', 'identifier'] }) }) diff --git a/plugins/lead-resources/src/components/KanbanCard.svelte b/plugins/lead-resources/src/components/KanbanCard.svelte index 50b3c4e2cf..b7e6f397c0 100644 --- a/plugins/lead-resources/src/components/KanbanCard.svelte +++ b/plugins/lead-resources/src/components/KanbanCard.svelte @@ -25,7 +25,7 @@ import { ActionIcon, Component, DueDatePresenter, IconMoreH, showPopup } from '@hcengineering/ui' import { BuildModelKey } from '@hcengineering/view' import { ContextMenu, enabledConfig, openDoc, statusStore } from '@hcengineering/view-resources' - import { ChatMessagesPresenter } from '@hcengineering/notification-resources' + import { ChatMessagesPresenter } from '@hcengineering/chunter-resources' import task from '@hcengineering/task' import lead from '../plugin' diff --git a/plugins/lead-resources/src/components/LeadPresenter.svelte b/plugins/lead-resources/src/components/LeadPresenter.svelte index 2e168228cd..ddca22614b 100644 --- a/plugins/lead-resources/src/components/LeadPresenter.svelte +++ b/plugins/lead-resources/src/components/LeadPresenter.svelte @@ -31,14 +31,14 @@ {#if value} {#if inline} - @LEAD-{value.number} + @{value.identifier} {:else}
{#if shouldShowAvatar}
{/if} LEAD-{value.number}{value.identifier}
{/if} diff --git a/plugins/recruit-resources/src/components/CreateApplication.svelte b/plugins/recruit-resources/src/components/CreateApplication.svelte index 24f0271300..d5c007652e 100644 --- a/plugins/recruit-resources/src/components/CreateApplication.svelte +++ b/plugins/recruit-resources/src/components/CreateApplication.svelte @@ -89,6 +89,7 @@ attachedToClass: recruit.mixin.Candidate, _class: recruit.class.Applicant, space, + identifier: '', _id: generateId(), collection: 'applications', modifiedOn: Date.now(), @@ -137,6 +138,8 @@ ) } + const number = (incResult as any).object.sequence + await client.addCollection( recruit.class.Applicant, _space, @@ -146,7 +149,8 @@ { ...doc, status: selectedState._id, - number: (incResult as any).object.sequence, + number, + identifier: `APP-${number}`, assignee: doc.assignee, rank: calcRank(lastOne, undefined), startDate: null, diff --git a/plugins/recruit-resources/src/components/EditApplication.svelte b/plugins/recruit-resources/src/components/EditApplication.svelte index 3250e16a1d..649943f712 100644 --- a/plugins/recruit-resources/src/components/EditApplication.svelte +++ b/plugins/recruit-resources/src/components/EditApplication.svelte @@ -31,11 +31,11 @@ const dispatch = createEventDispatcher() const sendOpen = () => { - if (object?.number !== undefined) { + if (object !== undefined) { dispatch('open', { - ignoreKeys: ['comments', 'number'], + ignoreKeys: ['comments', 'number', 'identifier'], allowedCollections: ['labels'], - title: `APP-${object.number}` + title: object.identifier }) } } diff --git a/plugins/recruit-resources/src/utils.ts b/plugins/recruit-resources/src/utils.ts index fe40ada0bd..fea89b4ad2 100644 --- a/plugins/recruit-resources/src/utils.ts +++ b/plugins/recruit-resources/src/utils.ts @@ -1,16 +1,16 @@ import contact, { getName } from '@hcengineering/contact' -import { type Class, type Client, type Doc, Hierarchy, type Ref } from '@hcengineering/core' -import presentation, { getClient } from '@hcengineering/presentation' +import { Hierarchy, type Class, type Client, type Doc, type Ref } from '@hcengineering/core' import { getMetadata } from '@hcengineering/platform' +import presentation, { getClient } from '@hcengineering/presentation' import { + recruitId, type Applicant, type Candidate, type Review, type Vacancy, - type VacancyList, - recruitId + type VacancyList } from '@hcengineering/recruit' -import { type Location, type ResolvedLocation, getCurrentResolvedLocation, getPanelURI } from '@hcengineering/ui' +import { getCurrentResolvedLocation, getPanelURI, type Location, type ResolvedLocation } from '@hcengineering/ui' import view from '@hcengineering/view' import { workbenchId } from '@hcengineering/workbench' import recruit from './plugin' @@ -191,7 +191,7 @@ export async function getAppIdentifier (client: Client, ref: Ref, doc return '' } - return `APP-${applicant.number}` + return applicant.identifier } export async function getRevTitle (client: Client, ref: Ref): Promise { @@ -201,6 +201,9 @@ export async function getRevTitle (client: Client, ref: Ref): Promise { const client = getClient() const hierarchy = client.getHierarchy() + if (hierarchy.isDerived(doc._class, recruit.class.Applicant)) { + return (doc as Applicant).identifier + } let clazz = hierarchy.getClass(doc._class) let label = clazz.shortLabel while (label === undefined && clazz.extends !== undefined) { diff --git a/plugins/task-assets/lang/en.json b/plugins/task-assets/lang/en.json index cacef57986..4423290033 100644 --- a/plugins/task-assets/lang/en.json +++ b/plugins/task-assets/lang/en.json @@ -94,6 +94,7 @@ "ProcessStates": "Process states", "Type": "Type", "Group": "Group", - "Color": "Color" + "Color": "Color", + "Identifier": "Identifier" } } \ No newline at end of file diff --git a/plugins/task-assets/lang/ru.json b/plugins/task-assets/lang/ru.json index 411dbec864..c5d0fe28ca 100644 --- a/plugins/task-assets/lang/ru.json +++ b/plugins/task-assets/lang/ru.json @@ -94,6 +94,7 @@ "ProcessStates": "Состояния процесса", "Type": "Тип", "Group": "Группа", - "Color": "Цвет" + "Color": "Цвет", + "Identifier": "Идентификатор" } } \ No newline at end of file diff --git a/plugins/task/src/index.ts b/plugins/task/src/index.ts index 0091bc98bd..c6f15684ca 100644 --- a/plugins/task/src/index.ts +++ b/plugins/task/src/index.ts @@ -56,6 +56,7 @@ export interface Task extends AttachedDoc, DocWithRank { comments?: number attachments?: number labels?: number + identifier: string } /** @@ -244,7 +245,8 @@ const task = plugin(taskId, { Dashboard: '' as IntlString, ProjectTypes: '' as IntlString, TaskType: '' as IntlString, - ProjectType: '' as IntlString + ProjectType: '' as IntlString, + Identifier: '' as IntlString }, class: { Sequence: '' as Ref>, diff --git a/plugins/tracker-resources/src/components/CreateIssue.svelte b/plugins/tracker-resources/src/components/CreateIssue.svelte index b289897731..94485ed3e6 100644 --- a/plugins/tracker-resources/src/components/CreateIssue.svelte +++ b/plugins/tracker-resources/src/components/CreateIssue.svelte @@ -61,7 +61,7 @@ import view from '@hcengineering/view' import { ObjectBox } from '@hcengineering/view-resources' import { createEventDispatcher, onDestroy } from 'svelte' - import { activeComponent, activeMilestone, generateIssueShortLink, getIssueId, updateIssueRelation } from '../issues' + import { activeComponent, activeMilestone, generateIssueShortLink, updateIssueRelation } from '../issues' import tracker from '../plugin' import SetParentIssueActionPopup from './SetParentIssueActionPopup.svelte' import ComponentSelector from './components/ComponentSelector.svelte' @@ -300,7 +300,7 @@ $: spaceQuery.query(tracker.class.Project, { _id: _space }, (res) => { resetDefaultAssigneeId() - currentProject = res.shift() + currentProject = res[0] }) const docCreateManager = DocCreateExtensionManager.create(tracker.class.Issue) @@ -370,13 +370,15 @@ true ) + const number = (incResult as any).object.sequence + const value: DocData = { title: getTitle(object.title), description: object.description, assignee: object.assignee, component: object.component, milestone: object.milestone, - number: (incResult as any).object.sequence, + number, status: object.status, priority: object.priority, rank: calcRank(lastOne, undefined), @@ -396,7 +398,8 @@ reports: 0, relations: relatedTo !== undefined ? [{ _id: relatedTo._id, _class: relatedTo._class }] : [], childInfo: [], - kind + kind, + identifier: `${currentProject?.identifier}-${number}` } await docCreateManager.commit(operations, _id, _space, value) @@ -439,7 +442,7 @@ { issueId: _id, subTitlePostfix: (await translate(tracker.string.CreatedOne, {}, $themeStore.language)).toLowerCase(), - issueUrl: currentProject != null && generateIssueShortLink(getIssueId(currentProject, value as Issue)) + issueUrl: currentProject != null && generateIssueShortLink(value.identifier) } ) diff --git a/plugins/tracker-resources/src/components/SetParentIssueActionPopup.svelte b/plugins/tracker-resources/src/components/SetParentIssueActionPopup.svelte index 02fcb11e57..d3101371cb 100644 --- a/plugins/tracker-resources/src/components/SetParentIssueActionPopup.svelte +++ b/plugins/tracker-resources/src/components/SetParentIssueActionPopup.svelte @@ -15,12 +15,11 @@ @@ -33,6 +31,6 @@ {/if} - {title} - {value.title} + {value.identifier} - {value.title}
diff --git a/plugins/tracker-resources/src/components/issues/IssuePresenter.svelte b/plugins/tracker-resources/src/components/issues/IssuePresenter.svelte index 908a9187ef..98fdcfa960 100644 --- a/plugins/tracker-resources/src/components/issues/IssuePresenter.svelte +++ b/plugins/tracker-resources/src/components/issues/IssuePresenter.svelte @@ -16,14 +16,13 @@ import { WithLookup } from '@hcengineering/core' import { Asset } from '@hcengineering/platform' import { getClient } from '@hcengineering/presentation' - import type { Issue, Project } from '@hcengineering/tracker' + import { taskTypeStore } from '@hcengineering/task-resources' + import TaskTypeIcon from '@hcengineering/task-resources/src/components/taskTypes/TaskTypeIcon.svelte' + import type { Issue } from '@hcengineering/tracker' import { AnySvelteComponent, Component, Icon, tooltip } from '@hcengineering/ui' import view from '@hcengineering/view' import { DocNavLink } from '@hcengineering/view-resources' import tracker from '../../plugin' - import { activeProjects } from '../../utils' - import { taskTypeStore } from '@hcengineering/task-resources' - import TaskTypeIcon from '@hcengineering/task-resources/src/components/taskTypes/TaskTypeIcon.svelte' export let value: WithLookup | undefined export let disabled: boolean = false @@ -35,14 +34,6 @@ export let kind: 'list' | undefined = undefined export let icon: Asset | AnySvelteComponent | undefined = undefined - let currentProject: Project | undefined = value?.$lookup?.space - - $: if (value !== undefined) { - currentProject = $activeProjects.get(value?.space) as Project - } - - $: title = currentProject ? `${currentProject.identifier}-${value?.number}` : `${value?.number}` - $: presenters = value !== undefined ? getClient().getHierarchy().findMixinMixins(value, view.mixin.ObjectPresenter) : [] @@ -61,7 +52,7 @@ shrink={0} > {#if inline} - @{title} + @{value.identifier} {:else} {#if shouldShowAvatar} @@ -74,7 +65,7 @@ {/if} - {title} + {value.identifier} diff --git a/plugins/tracker-resources/src/components/issues/IssuePreview.svelte b/plugins/tracker-resources/src/components/issues/IssuePreview.svelte index dd9ff2c5a9..905567396e 100644 --- a/plugins/tracker-resources/src/components/issues/IssuePreview.svelte +++ b/plugins/tracker-resources/src/components/issues/IssuePreview.svelte @@ -45,11 +45,6 @@ { limit: 1 } ) - let currentProject: Project | undefined - - $: currentProject = $activeProjects.get(space) as Project - $: issueName = currentProject && issue && `${currentProject.identifier}-${issue.number}` - const limit: number = 350 let cHeight: number = 0 @@ -74,7 +69,7 @@ {parent.title} {/if} - {issueName} + {issue.identifier} {issue.title} diff --git a/plugins/tracker-resources/src/components/issues/NotificationIssuePresenter.svelte b/plugins/tracker-resources/src/components/issues/NotificationIssuePresenter.svelte index 7462e9b14f..02ec0777f0 100644 --- a/plugins/tracker-resources/src/components/issues/NotificationIssuePresenter.svelte +++ b/plugins/tracker-resources/src/components/issues/NotificationIssuePresenter.svelte @@ -21,14 +21,12 @@ let currentProject: Project | undefined = undefined $: currentProject = $activeProjects.get(value.space) as Project - - $: title = currentProject ? `${currentProject.identifier}-${value?.number}` : `${value?.number}` {#if value}
- {title} + {value.identifier} {currentProject?.name} diff --git a/plugins/tracker-resources/src/components/issues/ParentIssue.svelte b/plugins/tracker-resources/src/components/issues/ParentIssue.svelte index f1f03f2457..0a7561b20b 100644 --- a/plugins/tracker-resources/src/components/issues/ParentIssue.svelte +++ b/plugins/tracker-resources/src/components/issues/ParentIssue.svelte @@ -13,33 +13,22 @@ // limitations under the License. -->
- {#if issueId} - {issueId} - {:else} - - {/if} + {issue.identifier} {issue.title} -
-
- {/if} + +
{:else}
0 $: parentIssue = issue?.$lookup?.attachedTo @@ -195,12 +194,12 @@ {#if !embedded} {/if} - {#if embedded && issueId} + {#if embedded} -
{issueId}
+
{issue.identifier}
- {:else if issueId} -
{issueId}
+ {:else} +
{issue.identifier}
{/if} {#if (projectType?.tasks.length ?? 0) > 1 && taskType !== undefined} @@ -223,9 +222,7 @@
{/if} - {#if issue.$lookup?.space} - {getIssueId(issue.$lookup.space, parentIssue)} - {/if} + {parentIssue.identifier} {parentIssue.title} diff --git a/plugins/tracker-resources/src/components/issues/edit/SubIssuesSelector.svelte b/plugins/tracker-resources/src/components/issues/edit/SubIssuesSelector.svelte index 37c52c911f..f650fbf08b 100644 --- a/plugins/tracker-resources/src/components/issues/edit/SubIssuesSelector.svelte +++ b/plugins/tracker-resources/src/components/issues/edit/SubIssuesSelector.svelte @@ -16,14 +16,13 @@ import core, { IdMap, Ref, SortingOrder, StatusCategory, WithLookup, toIdMap } from '@hcengineering/core' import { createQuery, getClient } from '@hcengineering/presentation' import task, { getStates } from '@hcengineering/task' + import { typeStore } from '@hcengineering/task-resources' import { Issue, Project } from '@hcengineering/tracker' import { Button, ButtonKind, ButtonSize, ProgressCircle, SelectPopup, showPanel } from '@hcengineering/ui' import { statusStore } from '@hcengineering/view-resources' - import { getIssueId } from '../../../issues' import tracker from '../../../plugin' import { listIssueStatusOrder } from '../../../utils' import IssueStatusIcon from '../IssueStatusIcon.svelte' - import { typeStore } from '@hcengineering/task-resources' export let value: WithLookup export let currentProject: Project | undefined = undefined @@ -116,7 +115,7 @@ } $: subIssuesValue = _subIssues.map((iss) => { - const text = project != null ? `${getIssueId(project, iss)} ${iss.title}` : iss.title + const text = `${iss.identifier} ${iss.title}` const c = $statusStore.byId.get(iss.status)?.category const category = c !== undefined ? categories.get(c) : undefined return { diff --git a/plugins/tracker-resources/src/components/issues/related/RelatedIssuePresenter.svelte b/plugins/tracker-resources/src/components/issues/related/RelatedIssuePresenter.svelte index b2f9d78881..511f4965c2 100644 --- a/plugins/tracker-resources/src/components/issues/related/RelatedIssuePresenter.svelte +++ b/plugins/tracker-resources/src/components/issues/related/RelatedIssuePresenter.svelte @@ -13,19 +13,17 @@ // limitations under the License. -->
diff --git a/plugins/tracker-resources/src/components/issues/timereport/EstimationSubIssueList.svelte b/plugins/tracker-resources/src/components/issues/timereport/EstimationSubIssueList.svelte index 845a8626ea..7c6f7a303f 100644 --- a/plugins/tracker-resources/src/components/issues/timereport/EstimationSubIssueList.svelte +++ b/plugins/tracker-resources/src/components/issues/timereport/EstimationSubIssueList.svelte @@ -18,7 +18,6 @@ import { Issue } from '@hcengineering/tracker' import { ListView, deviceOptionsStore as deviceInfo, getEventPositionElement, showPopup } from '@hcengineering/ui' import { ContextMenu, FixedColumn, ListSelectionProvider } from '@hcengineering/view-resources' - import { getIssueId } from '../../../issues' import tracker from '../../../plugin' import { activeProjects } from '../../../utils' import EstimationEditor from './EstimationEditor.svelte' @@ -52,9 +51,7 @@ >
- {#if currentProject} - {getIssueId(currentProject, issue)} - {/if} + {issue.identifier} {issue.title} diff --git a/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReportsList.svelte b/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReportsList.svelte index 3de801fee8..4a5f5e2936 100644 --- a/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReportsList.svelte +++ b/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReportsList.svelte @@ -14,23 +14,22 @@ --> - - { - dispatch('close') - }} - on:changeContent -> -
-
- -
-
-
diff --git a/plugins/tracker-resources/src/components/projects/CreateProject.svelte b/plugins/tracker-resources/src/components/projects/CreateProject.svelte index 2aaaa0285d..9dcd1e5ae3 100644 --- a/plugins/tracker-resources/src/components/projects/CreateProject.svelte +++ b/plugins/tracker-resources/src/components/projects/CreateProject.svelte @@ -130,9 +130,6 @@ if (projectData.defaultTimeReportDay !== project?.defaultTimeReportDay) { update.defaultTimeReportDay = projectData.defaultTimeReportDay } - if (projectData.identifier.toUpperCase() !== project?.identifier) { - update.identifier = projectData.identifier.toUpperCase() - } if (projectData.members.length !== project?.members.length) { update.members = projectData.members } else { @@ -180,7 +177,6 @@ close(projectId) } else { isSaving = false - changeIdentity(changeIdentityRef) } } } @@ -196,13 +192,6 @@ } showPopup(IconPicker, { icon, color, icons }, 'top', update, update) } - function changeIdentity (element: HTMLElement): void { - showPopup(ChangeIdentity, { identifier, projectsIdentifiers }, element, (result) => { - if (result != null) { - identifier = result.toLocaleUpperCase() - } - }) - } function close (id?: Ref): void { dispatch('close', id) @@ -286,17 +275,7 @@ kind={'large-style'} uppercase /> - {#if !isNew} -
-
- {:else if !isSaving && projectsIdentifiers.has(identifier.toUpperCase())} + {#if !isSaving && projectsIdentifiers.has(identifier.toUpperCase())}
diff --git a/plugins/tracker-resources/src/index.ts b/plugins/tracker-resources/src/index.ts index 64f8cc0854..2e04bccead 100644 --- a/plugins/tracker-resources/src/index.ts +++ b/plugins/tracker-resources/src/index.ts @@ -14,21 +14,21 @@ // import core, { + ClassifierKind, + DOMAIN_CONFIGURATION, + DOMAIN_MODEL, + getCurrentAccount, + toIdMap, type AttachedDoc, type Class, - ClassifierKind, type Client, type Doc, type DocumentQuery, - DOMAIN_MODEL, - getCurrentAccount, type Ref, type RelatedDocument, - toIdMap, - type TxOperations, - DOMAIN_CONFIGURATION + type TxOperations } from '@hcengineering/core' -import { type Resources, translate } from '@hcengineering/platform' +import { translate, type Resources } from '@hcengineering/platform' import { getClient, MessageBox, type ObjectSearchResult } from '@hcengineering/presentation' import { type Issue, type Milestone, type Project } from '@hcengineering/tracker' import { getCurrentLocation, navigate, showPopup, themeStore } from '@hcengineering/ui' @@ -45,23 +45,22 @@ import ProjectComponents from './components/components/ProjectComponents.svelte' import CreateIssue from './components/CreateIssue.svelte' import EditRelatedTargets from './components/EditRelatedTargets.svelte' import EditRelatedTargetsPopup from './components/EditRelatedTargetsPopup.svelte' -import SettingsRelatedTargets from './components/SettingsRelatedTargets.svelte' import Inbox from './components/inbox/Inbox.svelte' import AssigneeEditor from './components/issues/AssigneeEditor.svelte' import DueDatePresenter from './components/issues/DueDatePresenter.svelte' import EditIssue from './components/issues/edit/EditIssue.svelte' import IssueItem from './components/issues/IssueItem.svelte' -import IssueSearchIcon from './components/issues/IssueSearchIcon.svelte' import IssuePresenter from './components/issues/IssuePresenter.svelte' import IssuePreview from './components/issues/IssuePreview.svelte' import Issues from './components/issues/Issues.svelte' +import IssueSearchIcon from './components/issues/IssueSearchIcon.svelte' import IssuesView from './components/issues/IssuesView.svelte' import KanbanView from './components/issues/KanbanView.svelte' import ModificationDatePresenter from './components/issues/ModificationDatePresenter.svelte' import NotificationIssuePresenter from './components/issues/NotificationIssuePresenter.svelte' import PriorityEditor from './components/issues/PriorityEditor.svelte' -import PriorityInlineEditor from './components/issues/PriorityInlineEditor.svelte' import PriorityFilterValuePresenter from './components/issues/PriorityFilterValuePresenter.svelte' +import PriorityInlineEditor from './components/issues/PriorityInlineEditor.svelte' import PriorityPresenter from './components/issues/PriorityPresenter.svelte' import PriorityRefPresenter from './components/issues/PriorityRefPresenter.svelte' import RelatedIssueSelector from './components/issues/related/RelatedIssueSelector.svelte' @@ -75,21 +74,21 @@ import MilestoneDatePresenter from './components/milestones/MilestoneDatePresent import MyIssues from './components/myissues/MyIssues.svelte' import NewIssueHeader from './components/NewIssueHeader.svelte' import NopeComponent from './components/NopeComponent.svelte' +import MembersArrayEditor from './components/projects/MembersArrayEditor.svelte' import ProjectFilterValuePresenter from './components/projects/ProjectFilterValuePresenter.svelte' import RelationsPopup from './components/RelationsPopup.svelte' 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 MembersArrayEditor from './components/projects/MembersArrayEditor.svelte' import { - getIssueId, + getIssueTitle, + getTitle, issueIdentifierProvider, - issueIdProvider, issueLinkFragmentProvider, issueLinkProvider, - getIssueTitle, - resolveLocation, - issueTitleProvider + issueTitleProvider, + resolveLocation } from './issues' import tracker from './plugin' @@ -98,9 +97,9 @@ import MilestonePresenter from './components/milestones/MilestonePresenter.svelt import Milestones from './components/milestones/Milestones.svelte' import MilestoneSelector from './components/milestones/MilestoneSelector.svelte' import MilestoneStatusEditor from './components/milestones/MilestoneStatusEditor.svelte' +import MilestoneStatusIcon from './components/milestones/MilestoneStatusIcon.svelte' import MilestoneStatusPresenter from './components/milestones/MilestoneStatusPresenter.svelte' import MilestoneTitlePresenter from './components/milestones/MilestoneTitlePresenter.svelte' -import MilestoneStatusIcon from './components/milestones/MilestoneStatusIcon.svelte' import SubIssuesSelector from './components/issues/edit/SubIssuesSelector.svelte' import EstimationEditor from './components/issues/timereport/EstimationEditor.svelte' @@ -125,9 +124,9 @@ import { getAllMilestones, getAllPriority, getComponentTitle, + getIssueChatTitle, getIssueStatusCategories, getMilestoneTitle, - getIssueChatTitle, getVisibleFilters, issuePrioritySort, issueStatusSort, @@ -141,7 +140,9 @@ import PriorityIcon from './components/activity/PriorityIcon.svelte' import StatusIcon from './components/activity/StatusIcon.svelte' import TxIssueCreated from './components/activity/TxIssueCreated.svelte' import DeleteComponentPresenter from './components/components/DeleteComponentPresenter.svelte' +import IssueStatusIcon from './components/issues/IssueStatusIcon.svelte' import MoveIssues from './components/issues/Move.svelte' +import PriorityIconPresenter from './components/issues/PriorityIconPresenter.svelte' import StatusRefPresenter from './components/issues/StatusRefPresenter.svelte' import TimeSpendReportPopup from './components/issues/timereport/TimeSpendReportPopup.svelte' import IssueStatistics from './components/milestones/IssueStatistics.svelte' @@ -150,21 +151,19 @@ import MilestoneRefPresenter from './components/milestones/MilestoneRefPresenter import CreateProject from './components/projects/CreateProject.svelte' import ProjectPresenter from './components/projects/ProjectPresenter.svelte' import ProjectSpacePresenter from './components/projects/ProjectSpacePresenter.svelte' -import IssueStatusIcon from './components/issues/IssueStatusIcon.svelte' -import PriorityIconPresenter from './components/issues/PriorityIconPresenter.svelte' import { get } from 'svelte/store' +import { settingId } from '@hcengineering/setting' import EstimationValueEditor from './components/issues/timereport/EstimationValueEditor.svelte' import TimePresenter from './components/issues/timereport/TimePresenter.svelte' -import { settingId } from '@hcengineering/setting' export { default as AssigneeEditor } from './components/issues/AssigneeEditor.svelte' export { default as SubIssueList } from './components/issues/edit/SubIssueList.svelte' export { default as IssueStatusIcon } from './components/issues/IssueStatusIcon.svelte' export { default as StatusPresenter } from './components/issues/StatusPresenter.svelte' -export { CreateProject, IssuePresenter, PriorityEditor, StatusEditor, TitlePresenter, activeProjects } +export { activeProjects, CreateProject, IssuePresenter, PriorityEditor, StatusEditor, TitlePresenter } export async function queryIssue ( _class: Ref>, @@ -172,9 +171,7 @@ export async function queryIssue ( search: string, filter?: { in?: RelatedDocument[], nin?: RelatedDocument[] } ): Promise { - const projects = await client.findAll(tracker.class.Project, {}) - - const q: DocumentQuery = { title: { $like: `%${search}%` } } + const q: DocumentQuery = { identifier: { $like: `%${search}%` } } if (filter?.in !== undefined || filter?.nin !== undefined) { q._id = {} if (filter.in !== undefined) { @@ -185,40 +182,28 @@ export async function queryIssue ( } } - const named = toIdMap( + const numbered = toIdMap( await client.findAll(_class, q, { - limit: 200, - lookup: { space: tracker.class.Project } + limit: 200 }) ) - for (const currentProject of projects) { - const nids: number[] = [] - for (let n = 0; n <= currentProject.sequence; n++) { - const v = `${currentProject.identifier}-${n}` - if (v.includes(search)) { - nids.push(n) - } - } - if (nids.length > 0) { - const q2: DocumentQuery = { number: { $in: nids } } - if (q._id !== undefined) { - q2._id = q._id - } - const numbered = await client.findAll(_class, q2, { limit: 200, lookup: { space: tracker.class.Project } }) - for (const d of numbered) { - const shortId = `${projects.find((it) => it._id === d.space)?.identifier ?? ''}-${d.number}` - if (shortId.includes(search) || d.title.includes(search)) { - if (!named.has(d._id)) { - named.set(d._id, d) - } - } + + const q2: DocumentQuery = { title: { $like: `%${search}%` } } + if (q._id !== undefined) { + q2._id = q._id + } + const named = await client.findAll(_class, q2, { limit: 200 }) + for (const d of named) { + if (d.identifier.includes(search) || d.title.includes(search)) { + if (!numbered.has(d._id)) { + numbered.set(d._id, d) } } } - return Array.from(named.values()).map((e) => ({ + return Array.from(numbered.values()).map((e) => ({ doc: e, - title: getIssueId(e.$lookup?.space as Project, e), + title: e.identifier, icon: tracker.icon.TrackerApplication, component: IssueItem })) @@ -533,7 +518,7 @@ export default async (): Promise => ({ IssueTitleProvider: issueTitleProvider, ComponentTitleProvider: getComponentTitle, MilestoneTitleProvider: getMilestoneTitle, - GetIssueId: issueIdProvider, + GetIssueId: getTitle, GetIssueLink: issueLinkProvider, GetIssueLinkFragment: issueLinkFragmentProvider, GetIssueTitle: getIssueTitle, diff --git a/plugins/tracker-resources/src/issues.ts b/plugins/tracker-resources/src/issues.ts index 78dccbc87b..49669b2ea8 100644 --- a/plugins/tracker-resources/src/issues.ts +++ b/plugins/tracker-resources/src/issues.ts @@ -1,8 +1,8 @@ import { type Doc, type DocumentUpdate, type Ref, type RelatedDocument, type TxOperations } from '@hcengineering/core' -import presentation, { getClient } from '@hcengineering/presentation' import { getMetadata } from '@hcengineering/platform' -import { type Component, type Issue, type Project, type Milestone, trackerId } from '@hcengineering/tracker' -import { type Location, type ResolvedLocation, getPanelURI, getCurrentResolvedLocation } from '@hcengineering/ui' +import presentation, { getClient } from '@hcengineering/presentation' +import { trackerId, type Component, type Issue, type Milestone } from '@hcengineering/tracker' +import { getCurrentResolvedLocation, getPanelURI, type Location, type ResolvedLocation } from '@hcengineering/ui' import { workbenchId } from '@hcengineering/workbench' import { writable } from 'svelte/store' import tracker from './plugin' @@ -10,22 +10,14 @@ import tracker from './plugin' export const activeComponent = writable | undefined>(undefined) export const activeMilestone = writable | undefined>(undefined) -export function getIssueId (project: Project, issue: Issue): string { - return `${project.identifier}-${issue.number}` -} - export function isIssueId (shortLink: string): boolean { return /^\S+-\d+$/.test(shortLink) } export async function issueIdentifierProvider (client: TxOperations, ref: Ref): Promise { - const object = await client.findOne( - tracker.class.Issue, - { _id: ref as Ref }, - { lookup: { space: tracker.class.Project } } - ) - if (object?.$lookup?.space === undefined) throw new Error(`Issue project not found, _id: ${ref}`) - return getIssueId(object.$lookup.space, object) + const object = await client.findOne(tracker.class.Issue, { _id: ref as Ref }) + if (object === undefined) throw new Error(`Issue project not found, _id: ${ref}`) + return object.identifier } export async function issueTitleProvider (client: TxOperations, ref: Ref): Promise { @@ -42,22 +34,15 @@ export async function issueTitleProvider (client: TxOperations, ref: Ref): return await getIssueTitle(object) } -async function getTitle (doc: Doc): Promise { - const client = getClient() +export async function getTitle (doc: Doc): Promise { const issue = doc as Issue - const object = await client.findOne(tracker.class.Project, { _id: issue.space }) - if (object === undefined) return `?-${issue.number}` - return getIssueId(object, issue) + return issue.identifier } export function generateIssuePanelUri (issue: Issue): string { return getPanelURI(tracker.component.EditIssue, issue._id, issue._class, 'content') } -export async function issueIdProvider (doc: Doc): Promise { - return await getTitle(doc) -} - export async function issueLinkFragmentProvider (doc: Doc): Promise { const loc = getCurrentResolvedLocation() loc.path.length = 2 @@ -85,21 +70,8 @@ export function generateIssueShortLink (issueId: string): string { } export async function generateIssueLocation (loc: Location, issueId: string): Promise { - const tokens = issueId.split('-') - if (tokens.length < 2) { - return undefined - } - const projectId = tokens[0] - const issueNumber = Number(tokens[1]) const client = getClient() - const project = await client.findOne(tracker.class.Project, { identifier: projectId }) - if (project === undefined) { - console.error( - `Could not find project ${projectId}. Make sure you are in correct workspace and the project was not deleted or renamed.` - ) - return undefined - } - const issue = await client.findOne(tracker.class.Issue, { number: issueNumber, space: project._id }) + const issue = await client.findOne(tracker.class.Issue, { identifier: issueId }) if (issue === undefined) { console.error(`Could not find issue ${issueId}.`) return undefined @@ -112,7 +84,7 @@ export async function generateIssueLocation (loc: Location, issueId: string): Pr fragment: generateIssuePanelUri(issue) }, defaultLocation: { - path: [appComponent, workspace, trackerId, project._id, 'issues'], + path: [appComponent, workspace, trackerId, issue.space, 'issues'], fragment: generateIssuePanelUri(issue) } } diff --git a/plugins/tracker-resources/src/utils.ts b/plugins/tracker-resources/src/utils.ts index 6a5281b271..47e0d36983 100644 --- a/plugins/tracker-resources/src/utils.ts +++ b/plugins/tracker-resources/src/utils.ts @@ -612,6 +612,7 @@ export async function moveIssueToSpace ( }, true ) + const number = (incResult as any).object.sequence await updateIssuesOnMove( client, applyOps, @@ -620,7 +621,8 @@ export async function moveIssueToSpace ( { ...updates.get(doc._id), rank: calcRank(lastOne, undefined), - number: (incResult as any).object.sequence + number, + identifier: `${space.identifier}-${number}` }, updates ) diff --git a/server-plugins/tracker-resources/src/index.ts b/server-plugins/tracker-resources/src/index.ts index d38edef8d9..6f2670f704 100644 --- a/server-plugins/tracker-resources/src/index.ts +++ b/server-plugins/tracker-resources/src/index.ts @@ -57,11 +57,10 @@ async function updateSubIssues ( */ export async function issueHTMLPresenter (doc: Doc, control: TriggerControl): Promise { const issue = doc as Issue - const issueId = await getIssueId(issue, control) const front = getMetadata(serverCore.metadata.FrontUrl) ?? '' - const path = `${workbenchId}/${control.workspace.workspaceUrl}/${trackerId}/${issueId}` + const path = `${workbenchId}/${control.workspace.workspaceUrl}/${trackerId}/${issue.identifier}` const link = concatLink(front, path) - return `${issueId} ${issue.title}` + return `${issue.identifier} ${issue.title}` } /** @@ -76,11 +75,9 @@ export async function getIssueId (doc: Issue, control: TriggerControl): Promise< /** * @public */ -export async function issueTextPresenter (doc: Doc, control: TriggerControl): Promise { +export async function issueTextPresenter (doc: Doc): Promise { const issue = doc as Issue - const issueId = await getIssueId(issue, control) - - return `${issueId} ${issue.title}` + return `${issue.identifier} ${issue.title}` } function isSamePerson (control: TriggerControl, assignee: Ref, target: Ref): boolean { @@ -100,7 +97,7 @@ export async function getIssueNotificationContent ( ): Promise { const issue = doc as Issue - const issueShortName = await issueTextPresenter(doc, control) + const issueShortName = await issueTextPresenter(doc) const issueTitle = `${issueShortName}: ${issue.title}` const title = tracker.string.IssueNotificationTitle diff --git a/server/core/src/indexer/types.ts b/server/core/src/indexer/types.ts index 5e4028621a..93769c3a5d 100644 --- a/server/core/src/indexer/types.ts +++ b/server/core/src/indexer/types.ts @@ -102,9 +102,9 @@ export const contentStageId = 'cnt-v2b' /** * @public */ -export const fieldStateId = 'fld-v11' +export const fieldStateId = 'fld-v12' /** * @public */ -export const fullTextPushStageId = 'fts-v9_2' +export const fullTextPushStageId = 'fts-v10b' diff --git a/tests/sanity/tests/model/tracker/edit-project-page.ts b/tests/sanity/tests/model/tracker/edit-project-page.ts index c1a14bbc52..33b525d9c3 100644 --- a/tests/sanity/tests/model/tracker/edit-project-page.ts +++ b/tests/sanity/tests/model/tracker/edit-project-page.ts @@ -90,11 +90,6 @@ export class EditProjectPage extends CommonTrackerPage { if (data.title != null) { await this.inputTitle.fill(data.title) } - if (data.identifier != null) { - await this.buttonEditIdentifier.click() - await this.inputEditProjectIdentifier.fill(data.identifier) - await this.buttonEditProjectIdentifier.click() - } if (data.description != null) { await this.inputDescription.fill(data.description) } diff --git a/tests/sanity/tests/tracker/projects.spec.ts b/tests/sanity/tests/tracker/projects.spec.ts index 3ab72b359f..39cc4a4d47 100644 --- a/tests/sanity/tests/tracker/projects.spec.ts +++ b/tests/sanity/tests/tracker/projects.spec.ts @@ -48,7 +48,6 @@ test.describe('Tracker Projects tests', () => { } const updateProjectData: NewProject = { title: 'UpdateProject', - identifier: 'UPDAT', description: 'Updated Project description', private: true, defaultAssigneeForIssues: 'Chen Rosamund',