From 883393788b1b32e694c4f8712928c910936dc6b4 Mon Sep 17 00:00:00 2001 From: Sergei Ogorelkov Date: Thu, 2 Jun 2022 09:42:44 +0700 Subject: [PATCH] Tracker: change "Issue" type to "AttachedDoc" (#1875) Signed-off-by: Sergei Ogorelkov --- models/tracker/src/index.ts | 8 +- models/tracker/src/migration.ts | 53 ++++++++- .../src/components/CreateIssue.svelte | 35 +++--- .../components/SetDueDateActionPopup.svelte | 10 +- .../SetParentIssueActionPopup.svelte | 14 ++- .../components/issues/AssigneeEditor.svelte | 10 +- .../issues/AssigneePresenter.svelte | 10 +- .../components/issues/DueDateEditor.svelte | 10 +- .../components/issues/DueDatePresenter.svelte | 10 +- .../components/issues/PriorityEditor.svelte | 10 +- .../src/components/issues/StatusEditor.svelte | 10 +- .../components/issues/edit/EditIssue.svelte | 20 +++- .../issues/edit/SubIssueSelector.svelte | 106 ++++++++++++------ .../components/projects/ProjectEditor.svelte | 10 +- plugins/tracker-resources/src/plugin.ts | 2 +- plugins/tracker/src/index.ts | 7 +- server/core/src/storage.ts | 106 ++++++++++++++---- 17 files changed, 334 insertions(+), 97 deletions(-) diff --git a/models/tracker/src/index.ts b/models/tracker/src/index.ts index d13d4279ef..57542cdaa8 100644 --- a/models/tracker/src/index.ts +++ b/models/tracker/src/index.ts @@ -125,9 +125,9 @@ export class TTeam extends TSpace implements Team { /** * @public */ -@Model(tracker.class.Issue, core.class.Doc, DOMAIN_TRACKER) +@Model(tracker.class.Issue, core.class.AttachedDoc, DOMAIN_TRACKER) @UX(tracker.string.Issue, tracker.icon.Issue, tracker.string.Issue) -export class TIssue extends TDoc implements Issue { +export class TIssue extends TAttachedDoc implements Issue { @Prop(TypeString(), tracker.string.Title) @Index(IndexKind.FullText) title!: string @@ -151,8 +151,8 @@ export class TIssue extends TDoc implements Issue { @Prop(TypeRef(tracker.class.Project), tracker.string.Project) project!: Ref | null - @Prop(TypeRef(tracker.class.Issue), tracker.string.Parent) - parentIssue!: Ref + @Prop(Collection(tracker.class.Issue), tracker.string.SubIssues) + subIssues!: number @Prop(ArrOf(TypeRef(tracker.class.Issue)), tracker.string.BlockedBy) blockedBy!: Ref[] diff --git a/models/tracker/src/migration.ts b/models/tracker/src/migration.ts index 4744cf2d93..a0887f0d31 100644 --- a/models/tracker/src/migration.ts +++ b/models/tracker/src/migration.ts @@ -13,9 +13,9 @@ // limitations under the License. // -import core, { generateId, Ref, TxOperations } from '@anticrm/core' +import core, { Doc, generateId, Ref, TxOperations } from '@anticrm/core' import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@anticrm/model' -import { IssueStatus, IssueStatusCategory, Team, genRanks } from '@anticrm/tracker' +import { IssueStatus, IssueStatusCategory, Team, genRanks, Issue } from '@anticrm/tracker' import { DOMAIN_TRACKER } from '.' import tracker from './plugin' @@ -149,6 +149,53 @@ async function upgradeIssueStatuses (tx: TxOperations): Promise { } } +async function migrateParentIssues (client: MigrationClient): Promise { + let { updated } = await client.update( + DOMAIN_TRACKER, + { _class: tracker.class.Issue, attachedToClass: { $exists: false } }, + { + subIssues: 0, + collection: 'subIssues', + attachedToClass: tracker.class.Issue + } + ) + updated += ( + await client.update( + DOMAIN_TRACKER, + { _class: tracker.class.Issue, parentIssue: { $exists: true } }, + { $rename: { parentIssue: 'attachedTo' } } + ) + ).updated + updated += ( + await client.update( + DOMAIN_TRACKER, + { _class: tracker.class.Issue, attachedTo: { $in: [null, undefined] } }, + { attachedTo: tracker.ids.NoParent } + ) + ).updated + + if (updated === 0) { + return + } + + const childrenCountById = new Map, number>() + const parentIssueIds = ( + await client.find(DOMAIN_TRACKER, { + _class: tracker.class.Issue, + attachedTo: { $nin: [tracker.ids.NoParent] } + }) + ).map((issue) => issue.attachedTo) + + for (const issueId of parentIssueIds) { + const count = childrenCountById.get(issueId) ?? 0 + childrenCountById.set(issueId, count + 1) + } + + for (const [_id, childrenCount] of childrenCountById) { + await client.update(DOMAIN_TRACKER, { _id }, { subIssues: childrenCount }) + } +} + async function migrateIssueProjects (client: MigrationClient): Promise { const issues = await client.find(DOMAIN_TRACKER, { _class: tracker.class.Issue, project: { $exists: false } }) @@ -197,7 +244,7 @@ async function upgradeProjects (tx: TxOperations): Promise { export const trackerOperation: MigrateOperation = { async migrate (client: MigrationClient): Promise { - await Promise.all([migrateIssueProjects(client)]) + await Promise.all([migrateIssueProjects(client), migrateParentIssues(client)]) }, async upgrade (client: MigrationUpgradeClient): Promise { const tx = new TxOperations(client, core.account.System) diff --git a/plugins/tracker-resources/src/components/CreateIssue.svelte b/plugins/tracker-resources/src/components/CreateIssue.svelte index 649612875e..78280eb0c8 100644 --- a/plugins/tracker-resources/src/components/CreateIssue.svelte +++ b/plugins/tracker-resources/src/components/CreateIssue.svelte @@ -14,7 +14,7 @@ --> diff --git a/plugins/tracker-resources/src/components/issues/AssigneePresenter.svelte b/plugins/tracker-resources/src/components/issues/AssigneePresenter.svelte index c8b0b8c58f..bad9451977 100644 --- a/plugins/tracker-resources/src/components/issues/AssigneePresenter.svelte +++ b/plugins/tracker-resources/src/components/issues/AssigneePresenter.svelte @@ -60,7 +60,15 @@ const newAssignee = result === null ? null : result._id - await client.update(currentIssue, { assignee: newAssignee }) + await client.updateCollection( + currentIssue._class, + currentIssue.space, + currentIssue._id, + currentIssue.attachedTo, + currentIssue.attachedToClass, + currentIssue.collection, + { assignee: newAssignee } + ) } const handleAssigneeEditorOpened = async (event: MouseEvent) => { diff --git a/plugins/tracker-resources/src/components/issues/DueDateEditor.svelte b/plugins/tracker-resources/src/components/issues/DueDateEditor.svelte index 39fed67fd6..98652adbc2 100644 --- a/plugins/tracker-resources/src/components/issues/DueDateEditor.svelte +++ b/plugins/tracker-resources/src/components/issues/DueDateEditor.svelte @@ -27,7 +27,15 @@ return } - await client.update(value, { dueDate: newDueDate }) + await client.updateCollection( + value._class, + value.space, + value._id, + value.attachedTo, + value.attachedToClass, + value.collection, + { dueDate: newDueDate } + ) } $: today = new Date(new Date(Date.now()).setHours(0, 0, 0, 0)) diff --git a/plugins/tracker-resources/src/components/issues/DueDatePresenter.svelte b/plugins/tracker-resources/src/components/issues/DueDatePresenter.svelte index 63b7386898..f6e5a6d4b7 100644 --- a/plugins/tracker-resources/src/components/issues/DueDatePresenter.svelte +++ b/plugins/tracker-resources/src/components/issues/DueDatePresenter.svelte @@ -26,7 +26,15 @@ $: dueDateMs = value.dueDate const handleDueDateChanged = async (newDate: number | null) => { - await client.update(value, { dueDate: newDate }) + await client.updateCollection( + value._class, + value.space, + value._id, + value.attachedTo, + value.attachedToClass, + value.collection, + { dueDate: newDate } + ) } $: shouldRenderPresenter = diff --git a/plugins/tracker-resources/src/components/issues/PriorityEditor.svelte b/plugins/tracker-resources/src/components/issues/PriorityEditor.svelte index 361c648e6a..d18812c1a9 100644 --- a/plugins/tracker-resources/src/components/issues/PriorityEditor.svelte +++ b/plugins/tracker-resources/src/components/issues/PriorityEditor.svelte @@ -36,7 +36,15 @@ return } - await client.update(value, { priority: newPriority }) + await client.updateCollection( + value._class, + value.space, + value._id, + value.attachedTo, + value.attachedToClass, + value.collection, + { priority: newPriority } + ) } diff --git a/plugins/tracker-resources/src/components/issues/StatusEditor.svelte b/plugins/tracker-resources/src/components/issues/StatusEditor.svelte index dc0ffc0f27..e550c71f6d 100644 --- a/plugins/tracker-resources/src/components/issues/StatusEditor.svelte +++ b/plugins/tracker-resources/src/components/issues/StatusEditor.svelte @@ -38,7 +38,15 @@ return } - await client.update(value, { status: newStatus }) + await client.updateCollection( + value._class, + value.space, + value._id, + value.attachedTo, + value.attachedToClass, + value.collection, + { status: newStatus } + ) } diff --git a/plugins/tracker-resources/src/components/issues/edit/EditIssue.svelte b/plugins/tracker-resources/src/components/issues/edit/EditIssue.svelte index 57b2f4f345..5c09ab0c25 100644 --- a/plugins/tracker-resources/src/components/issues/edit/EditIssue.svelte +++ b/plugins/tracker-resources/src/components/issues/edit/EditIssue.svelte @@ -47,7 +47,7 @@ const dispatch = createEventDispatcher() const client = getClient() - let issue: Issue | undefined + let issue: WithLookup | undefined let currentTeam: Team | undefined let issueStatuses: WithLookup[] | undefined let title = '' @@ -65,7 +65,7 @@ title = issue.title description = issue.description }, - { lookup: { parentIssue: _class } } + { lookup: { attachedTo: tracker.class.Issue } } ) $: if (issue) { @@ -123,7 +123,15 @@ } if (Object.keys(updates).length > 0) { - await client.update(issue, updates) + await client.updateCollection( + issue._class, + issue.space, + issue._id, + issue.attachedTo, + issue.attachedToClass, + issue.collection, + updates + ) } isEditing = false @@ -152,6 +160,7 @@ on:fullsize on:close={() => dispatch('close')} > + {@const { attachedTo: parentIssue } = issue?.$lookup ?? {}}
@@ -184,7 +193,7 @@ {#if isEditing}
- {#if issue?.parentIssue} + {#if parentIssue}
{#if currentTeam && issueStatuses} @@ -211,7 +220,7 @@
{:else} - {#if issue?.parentIssue} + {#if parentIssue}
{#if currentTeam && issueStatuses} @@ -261,6 +270,7 @@ .description-preview { color: var(--theme-content-color); + line-height: 150%; .placeholder { color: var(--theme-content-trans-color); diff --git a/plugins/tracker-resources/src/components/issues/edit/SubIssueSelector.svelte b/plugins/tracker-resources/src/components/issues/edit/SubIssueSelector.svelte index 8333198f40..377a312a80 100644 --- a/plugins/tracker-resources/src/components/issues/edit/SubIssueSelector.svelte +++ b/plugins/tracker-resources/src/components/issues/edit/SubIssueSelector.svelte @@ -16,7 +16,17 @@ import { Ref, SortingOrder, WithLookup } from '@anticrm/core' import { createQuery } from '@anticrm/presentation' import { Team, Issue, IssueStatus } from '@anticrm/tracker' - import { Icon, Tooltip, showPanel, IconForward, IconDetails, showPopup, SelectPopup, closeTooltip } from '@anticrm/ui' + import { + Icon, + Tooltip, + showPanel, + IconForward, + IconDetails, + showPopup, + SelectPopup, + closeTooltip, + Spinner + } from '@anticrm/ui' import tracker from '../../../plugin' export let issue: WithLookup @@ -43,9 +53,9 @@ } function openParentIssue () { - if (issue.parentIssue) { + if (parentIssue) { closeTooltip() - openIssue(issue.parentIssue) + openIssue(parentIssue._id) } } @@ -77,21 +87,23 @@ } } - $: subIssuesQeury.query( - tracker.class.Issue, - { space: issue.space, parentIssue: issue.parentIssue }, - (res) => (subIssues = res), - { sort: { modifiedOn: SortingOrder.Descending } } - ) - $: parentIssue = issue.$lookup?.parentIssue ?? null + $: areSubIssuesLoading = !subIssues + $: parentIssue = issue.$lookup?.attachedTo ? (issue.$lookup?.attachedTo as Issue) : null + $: parentIssue && + subIssuesQeury.query( + tracker.class.Issue, + { space: issue.space, attachedTo: parentIssue._id }, + (res) => (subIssues = res), + { sort: { modifiedOn: SortingOrder.Descending } } + ) -
-
- {#if parentIssue} +{#if parentIssue} +
+
{@const icon = getIssueStatusIcon(issue)} -
+
{#if icon}
@@ -101,40 +113,65 @@ {parentIssue.title}
- {/if} -
- - -
- {#if subIssues?.length !== undefined} - {subIssues.length} - {/if} -
- - -
-
- -
-
-
+ +
+ {#if areSubIssuesLoading} +
+ +
+ {:else} + +
+ {subIssues?.length} +
+ + +
+
+ +
+
+
+ {/if} +
+
+{/if}