Skip to content

Commit

Permalink
Cards migration (#8164)
Browse files Browse the repository at this point in the history
  • Loading branch information
BykhovDenis authored Mar 7, 2025
1 parent 6636e0a commit 655c46e
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 9 deletions.
2 changes: 2 additions & 0 deletions models/all/src/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,13 @@ import { analyticsCollectorOperation } from '@hcengineering/model-analytics-coll
import { workbenchOperation } from '@hcengineering/model-workbench'
import { testManagementOperation } from '@hcengineering/model-test-management'
import { surveyOperation } from '@hcengineering/model-survey'
import { cardOperation } from '@hcengineering/model-card'
import { aiBotId, aiBotOperation } from '@hcengineering/model-ai-bot'

export const migrateOperations: [string, MigrateOperation][] = [
['core', coreOperation],
['activity', activityOperation],
['card', cardOperation],
['chunter', chunterOperation],
['calendar', calendarOperation],
['gmail', gmailOperation],
Expand Down
2 changes: 2 additions & 0 deletions models/card/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ export class MasterTagEditorSection extends TDoc implements MasterTagEditorSecti
component!: AnyComponent
}

export * from './migration'

export function createModel (builder: Builder): void {
builder.createModel(TMasterTag, TTag, TCard, MasterTagEditorSection)

Expand Down
95 changes: 95 additions & 0 deletions models/card/src/migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//
// Copyright © 2025 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//

import { DOMAIN_CARD } from '@hcengineering/card'
import { chunterId } from '@hcengineering/chunter'
import core, { type Client, type Data, type Doc, TxOperations } from '@hcengineering/core'
import {
tryMigrate,
tryUpgrade,
type MigrateOperation,
type MigrationClient,
type MigrationUpgradeClient
} from '@hcengineering/model'
import view from '@hcengineering/view'
import card from '.'

export const cardOperation: MigrateOperation = {
async migrate (client: MigrationClient): Promise<void> {
await tryMigrate(client, chunterId, [
{
state: 'set-parent-info',
func: setParentInfo
}
])
},
async upgrade (state: Map<string, Set<string>>, client: () => Promise<MigrationUpgradeClient>): Promise<void> {
await tryUpgrade(state, client, chunterId, [
{
state: 'migrateViewlets',
func: migrateViewlets
}
])
}
}

async function setParentInfo (client: MigrationClient): Promise<void> {
await client.update(
DOMAIN_CARD,
{
parentInfo: { $exists: false }
},
{
parentInfo: []
}
)
}

function extractObjectProps<T extends Doc> (doc: T): Data<T> {
const data: any = {}
for (const key in doc) {
if (key === '_id') {
continue
}
data[key] = doc[key]
}
return data as Data<T>
}

async function migrateViewlets (client: Client): Promise<void> {
const txOp = new TxOperations(client, core.account.System)
const viewlets = await client.findAll(view.class.Viewlet, { attachTo: card.class.Card })
const masterTags = await client.findAll(card.class.MasterTag, {})
const currentViewlets = await client.findAll(view.class.Viewlet, { attachTo: { $in: masterTags.map((p) => p._id) } })
for (const masterTag of masterTags) {
for (const viewlet of viewlets) {
const base = extractObjectProps(viewlet)
const current = currentViewlets.find(
(p) => p.attachTo === masterTag._id && p.variant === viewlet.variant && p.descriptor === viewlet.descriptor
)
if (current === undefined) {
await txOp.createDoc(view.class.Viewlet, core.space.Model, {
...base,
attachTo: masterTag._id
})
} else {
await txOp.diffUpdate(current, {
...base,
attachTo: masterTag._id
})
}
}
}
}
20 changes: 11 additions & 9 deletions server-plugins/card-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,17 @@ async function OnMasterTagCreate (ctx: TxCreateDoc<MasterTag | Tag>[], control:
res.push(
control.txFactory.createTxMixin(createTx.objectId, core.class.Mixin, core.space.Model, setting.mixin.UserMixin, {})
)
const viewlets = await control.findAll(control.ctx, view.class.Viewlet, { attachTo: tag.extends })
for (const viewlet of viewlets) {
const base = extractObjectProps(viewlet)
res.push(
control.txFactory.createTxCreateDoc(view.class.Viewlet, core.space.Model, {
...base,
attachTo: createTx.objectId
})
)
if (tag._class === card.class.MasterTag) {
const viewlets = await control.findAll(control.ctx, view.class.Viewlet, { attachTo: tag.extends })
for (const viewlet of viewlets) {
const base = extractObjectProps(viewlet)
res.push(
control.txFactory.createTxCreateDoc(view.class.Viewlet, core.space.Model, {
...base,
attachTo: createTx.objectId
})
)
}
}

return res
Expand Down

0 comments on commit 655c46e

Please sign in to comment.