From 9a4fa752de12991d8044b43435e0d36d0cb55173 Mon Sep 17 00:00:00 2001 From: Denis Bykhov Date: Wed, 4 Oct 2023 01:31:07 +0600 Subject: [PATCH] UBER-972 (#3782) --- models/core/src/core.ts | 10 ++- models/tracker/src/migration.ts | 76 +++++++++++++++++-- packages/core/src/classes.ts | 13 ++++ packages/core/src/component.ts | 4 +- packages/model/src/migration.ts | 71 ++++++++++++++++- .../issues/timereport/TimePresenter.svelte | 8 +- .../timereport/TimeSpendReportPopup.svelte | 12 +-- .../issues/timereport/TimeSpendReports.svelte | 2 +- plugins/tracker/src/index.ts | 2 +- .../src/components/Workbench.svelte | 1 + server/core/src/indexer/indexer.ts | 2 +- tests/sanity/tests/tracker.spec.ts | 10 +-- 12 files changed, 184 insertions(+), 27 deletions(-) diff --git a/models/core/src/core.ts b/models/core/src/core.ts index b77aa69d48..eafe5da0d3 100644 --- a/models/core/src/core.ts +++ b/models/core/src/core.ts @@ -29,6 +29,7 @@ import { Domain, DOMAIN_BLOB, DOMAIN_CONFIGURATION, + DOMAIN_MIGRATION, DOMAIN_DOC_INDEX_STATE, DOMAIN_FULLTEXT_BLOB, DOMAIN_MODEL, @@ -49,7 +50,8 @@ import { Space, Timestamp, Type, - Version + Version, + MigrationState } from '@hcengineering/core' import { Hidden, @@ -244,6 +246,12 @@ export class TVersion extends TDoc implements Version { patch!: number } +@Model(core.class.MigrationState, core.class.Doc, DOMAIN_MIGRATION) +export class TMigrationState extends TDoc implements MigrationState { + plugin!: string + state!: string +} + @Model(core.class.PluginConfiguration, core.class.Doc, DOMAIN_MODEL) export class TPluginConfiguration extends TDoc implements PluginConfiguration { pluginId!: Plugin diff --git a/models/tracker/src/migration.ts b/models/tracker/src/migration.ts index d13876c3b1..faed6df9fb 100644 --- a/models/tracker/src/migration.ts +++ b/models/tracker/src/migration.ts @@ -13,11 +13,27 @@ // limitations under the License. // -import core, { DOMAIN_STATUS, DOMAIN_TX, Status, TxCUD, TxOperations, TxProcessor } from '@hcengineering/core' -import { MigrateOperation, MigrationClient, MigrationUpgradeClient, createOrUpdate } from '@hcengineering/model' +import core, { + DOMAIN_STATUS, + DOMAIN_TX, + Status, + TxCUD, + TxCollectionCUD, + TxCreateDoc, + TxOperations, + TxProcessor, + TxUpdateDoc +} from '@hcengineering/core' +import { + MigrateOperation, + MigrationClient, + MigrationUpgradeClient, + createOrUpdate, + tryMigrate +} from '@hcengineering/model' import { DOMAIN_TASK } from '@hcengineering/model-task' import tags from '@hcengineering/tags' -import { Project, TimeReportDayType, createStatuses } from '@hcengineering/tracker' +import { Issue, Project, TimeReportDayType, TimeSpendReport, createStatuses } from '@hcengineering/tracker' import { DOMAIN_TRACKER } from '.' import tracker from './plugin' import { DOMAIN_SPACE } from '@hcengineering/model-core' @@ -83,6 +99,44 @@ async function fixIconsWithEmojis (tx: TxOperations): Promise { await Promise.all(promises) } +async function fixSpentTime (client: MigrationClient): Promise { + const issues = await client.find(DOMAIN_TASK, { reportedTime: { $gt: 0 } }) + for (const issue of issues) { + const childInfo = issue.childInfo + for (const child of childInfo) { + child.reportedTime = child.reportedTime * 8 + } + await client.update(DOMAIN_TASK, { _id: issue._id }, { reportedTime: issue.reportedTime * 8, childInfo }) + } + const reports = await client.find(DOMAIN_TRACKER, {}) + for (const report of reports) { + await client.update(DOMAIN_TRACKER, { _id: report._id }, { value: report.value * 8 }) + } + const createTxes = await client.find>(DOMAIN_TX, { + 'tx.objectClass': tracker.class.TimeSpendReport, + 'tx._class': core.class.TxCreateDoc, + 'tx.attributes.value': { $exists: true } + }) + for (const tx of createTxes) { + await client.update( + DOMAIN_TX, + { _id: tx._id }, + { 'tx.attributes.value': (tx.tx as TxCreateDoc).attributes.value * 8 } + ) + } + const updateTxes = await client.find>(DOMAIN_TX, { + 'tx.objectClass': tracker.class.TimeSpendReport, + 'tx._class': core.class.TxUpdateDoc, + 'tx.operations.value': { $exists: true } + }) + for (const tx of updateTxes) { + const val = (tx.tx as TxUpdateDoc).operations.value + if (val !== undefined) { + await client.update(DOMAIN_TX, { _id: tx._id }, { 'tx.operations.value': val * 8 }) + } + } +} + async function moveIssues (client: MigrationClient): Promise { const docs = await client.find(DOMAIN_TRACKER, { _class: tracker.class.Issue }) if (docs.length > 0) { @@ -114,8 +168,20 @@ async function fixProjectDefaultStatuses (client: MigrationClient): Promise { - await moveIssues(client) - await fixProjectDefaultStatuses(client) + await tryMigrate(client, 'tracker', [ + { + state: 'moveIssues', + func: moveIssues + }, + { + state: 'fixProjectDefaultStatuses', + func: fixProjectDefaultStatuses + }, + { + state: 'reportTimeDayToHour', + func: fixSpentTime + } + ]) }, async upgrade (client: MigrationUpgradeClient): Promise { const tx = new TxOperations(client, core.account.System) diff --git a/packages/core/src/classes.ts b/packages/core/src/classes.ts index ac01ee2237..6c0706fa10 100644 --- a/packages/core/src/classes.ts +++ b/packages/core/src/classes.ts @@ -289,6 +289,11 @@ export const DOMAIN_MODEL = 'model' as Domain */ export const DOMAIN_CONFIGURATION = '_configuration' as Domain +/** + * @public + */ +export const DOMAIN_MIGRATION = '_migrations' as Domain + /** * @public */ @@ -358,6 +363,14 @@ export interface Version extends Doc { patch: number } +/** + * @public + */ +export interface MigrationState extends Doc { + plugin: string + state: string +} + /** * @public */ diff --git a/packages/core/src/component.ts b/packages/core/src/component.ts index dfaa9c62b3..2634c36ebe 100644 --- a/packages/core/src/component.ts +++ b/packages/core/src/component.ts @@ -35,6 +35,7 @@ import type { IndexStageState, IndexingConfiguration, Interface, + MigrationState, Obj, PluginConfiguration, Ref, @@ -118,7 +119,8 @@ export default plugin(coreId, { Configuration: '' as Ref>, Status: '' as Ref>, - StatusCategory: '' as Ref> + StatusCategory: '' as Ref>, + MigrationState: '' as Ref> }, mixin: { FullTextSearchContext: '' as Ref>, diff --git a/packages/model/src/migration.ts b/packages/model/src/migration.ts index 3c99b2fa76..9720f3be9d 100644 --- a/packages/model/src/migration.ts +++ b/packages/model/src/migration.ts @@ -1,6 +1,7 @@ -import { +import core, { Client, Doc, + DOMAIN_MIGRATION, DocumentQuery, Domain, FindOptions, @@ -10,7 +11,11 @@ import { ObjQueryType, PushOptions, Ref, - UnsetOptions + UnsetOptions, + MigrationState, + generateId, + TxOperations, + Data } from '@hcengineering/core' /** @@ -94,3 +99,65 @@ export interface MigrateOperation { // Perform high level upgrade operations. upgrade: (client: MigrationUpgradeClient) => Promise } + +/** + * @public + */ +export interface Migrations { + state: string + func: (client: MigrationClient) => Promise +} + +/** + * @public + */ +export interface UpgradeOperations { + state: string + func: (client: MigrationUpgradeClient) => Promise +} + +/** + * @public + */ +export async function tryMigrate (client: MigrationClient, plugin: string, migrations: Migrations[]): Promise { + const states = new Set( + (await client.find(DOMAIN_MIGRATION, { _class: core.class.MigrationState, plugin })).map( + (p) => p.state + ) + ) + for (const migration of migrations) { + if (states.has(migration.state)) continue + await migration.func(client) + const st: MigrationState = { + plugin, + state: migration.state, + space: core.space.Configuration, + modifiedBy: core.account.System, + modifiedOn: Date.now(), + _class: core.class.MigrationState, + _id: generateId() + } + await client.create(DOMAIN_MIGRATION, st) + } +} + +/** + * @public + */ +export async function tryUpgrade ( + client: MigrationUpgradeClient, + plugin: string, + migrations: UpgradeOperations[] +): Promise { + const states = new Set((await client.findAll(core.class.MigrationState, { plugin })).map((p) => p.state)) + for (const migration of migrations) { + if (states.has(migration.state)) continue + await migration.func(client) + const st: Data = { + plugin, + state: migration.state + } + const tx = new TxOperations(client, core.account.System) + await tx.createDoc(core.class.MigrationState, core.space.Configuration, st) + } +} diff --git a/plugins/tracker-resources/src/components/issues/timereport/TimePresenter.svelte b/plugins/tracker-resources/src/components/issues/timereport/TimePresenter.svelte index 25a8b27ed3..421feb17e1 100644 --- a/plugins/tracker-resources/src/components/issues/timereport/TimePresenter.svelte +++ b/plugins/tracker-resources/src/components/issues/timereport/TimePresenter.svelte @@ -29,15 +29,15 @@ on:click use:tooltip={{ component: Label, - props: { label: tracker.string.TimeSpendHours, params: { value: floorFractionDigits(value * 8, 3) } } + props: { label: tracker.string.TimeSpendHours, params: { value: floorFractionDigits(value, 1) } } }} > {#if noSymbol} {floorFractionDigits(value, 1)} - {:else if value > 0 && value < 1} -