Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UBERF-6576: Move default space/project/task types into static model #5423

Merged
merged 19 commits into from
May 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions dev/tool/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"@hcengineering/attachment": "^0.6.9",
"@hcengineering/chunter": "^0.6.12",
"@hcengineering/client": "^0.6.14",
"@hcengineering/activity": "^0.6.0",
"@hcengineering/client-resources": "^0.6.23",
"@hcengineering/contact": "^0.6.20",
"@hcengineering/core": "^0.6.28",
Expand All @@ -70,6 +71,11 @@
"@hcengineering/model-contact": "^0.6.1",
"@hcengineering/model-recruit": "^0.6.0",
"@hcengineering/model-telegram": "^0.6.0",
"@hcengineering/model-tracker": "^0.6.0",
"@hcengineering/model-core": "^0.6.0",
"@hcengineering/model-task": "^0.6.0",
"@hcengineering/model-activity": "^0.6.0",
"@hcengineering/model-lead": "^0.6.0",
"@hcengineering/mongo": "^0.6.1",
"@hcengineering/openai": "^0.6.0",
"@hcengineering/platform": "^0.6.9",
Expand Down
3 changes: 1 addition & 2 deletions dev/tool/src/clean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ import task, { type ProjectType, type TaskType } from '@hcengineering/task'
import tracker from '@hcengineering/tracker'
import { deepEqual } from 'fast-equals'
import { MongoClient } from 'mongodb'

export const DOMAIN_ACTIVITY = 'activity' as Domain
import { DOMAIN_ACTIVITY } from '@hcengineering/model-activity'

export async function cleanWorkspace (
ctx: MeasureContext,
Expand Down
2 changes: 1 addition & 1 deletion dev/tool/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@ export function devTool (
program
.command('restore-ats-types <workspace>')
.description('Restore recruiting task types for workspace')
.action(async (workspace: string, step: string) => {
.action(async (workspace: string) => {
const { mongodbUri } = prepareTools()
console.log('Restoring recruiting task types in workspace ', workspace, '...')
await restoreRecruitingTaskTypes(mongodbUri, getWorkspaceId(workspace, productId), transactorUrl)
Expand Down
112 changes: 3 additions & 109 deletions models/board/src/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@ import {
tryMigrate,
tryUpgrade
} from '@hcengineering/model'
import core, { DOMAIN_SPACE } from '@hcengineering/model-core'
import { DOMAIN_TASK, createProjectType, createSequence, fixTaskTypes } from '@hcengineering/model-task'
import core from '@hcengineering/model-core'
import { DOMAIN_TASK, createSequence } from '@hcengineering/model-task'
import tags from '@hcengineering/tags'
import task from '@hcengineering/task'
import { PaletteColorIndexes } from '@hcengineering/ui/src/colors'
import board from './plugin'

async function createSpace (tx: TxOperations): Promise<void> {
Expand All @@ -52,73 +50,6 @@ async function createSpace (tx: TxOperations): Promise<void> {
}
}

async function createDefaultProjectType (tx: TxOperations): Promise<void> {
const existing = await tx.findOne(task.class.ProjectType, { _id: board.template.DefaultBoard })
const existingDeleted = await tx.findOne(core.class.TxRemoveDoc, {
objectId: board.template.DefaultBoard
})

if (existing !== undefined || existingDeleted !== undefined) {
return
}

await createProjectType(
tx,
{
name: 'Default board',
descriptor: board.descriptors.BoardType,
description: '',
tasks: [],
roles: 0,
classic: false
},
[
{
_id: board.taskType.Card,
descriptor: board.descriptors.Card,
name: 'Card',
ofClass: board.class.Card,
targetClass: board.class.Card,
statusClass: core.class.Status,
kind: 'task',
factory: [
{
color: PaletteColorIndexes.Coin,
name: 'Unstarted',
category: task.statusCategory.UnStarted,
ofAttribute: board.attribute.State
},
{
color: PaletteColorIndexes.Blueberry,
name: 'To do',
category: task.statusCategory.Active,
ofAttribute: board.attribute.State
},
{
color: PaletteColorIndexes.Arctic,
name: 'Done',
category: task.statusCategory.Active,
ofAttribute: board.attribute.State
},
{
color: PaletteColorIndexes.Grass,
name: 'Completed',
category: board.statusCategory.Completed,
ofAttribute: board.attribute.State
}
],
statusCategories: [
task.statusCategory.UnStarted,
task.statusCategory.Active,
task.statusCategory.Won,
task.statusCategory.Lost
]
}
],
board.template.DefaultBoard
)
}

async function createDefaults (tx: TxOperations): Promise<void> {
await createSpace(tx)
await createSequence(tx, board.class.Card)
Expand Down Expand Up @@ -153,55 +84,18 @@ async function migrateIdentifiers (client: MigrationClient): Promise<void> {
export const boardOperation: MigrateOperation = {
async migrate (client: MigrationClient): Promise<void> {
await tryMigrate(client, boardId, [
{
state: 'fix-category-descriptors',
func: async (client) => {
await client.update(
DOMAIN_SPACE,
{ _class: task.class.ProjectType, category: 'board:category:BoardType' },
{
$set: { descriptor: board.descriptors.BoardType },
$unset: { category: 1 }
}
)
}
},
{
state: 'fixTaskStatus',
func: async (client): Promise<void> => {
await fixTaskTypes(client, board.descriptors.BoardType, async () => [
{
name: 'Card',
descriptor: board.descriptors.Card,
ofClass: board.class.Card,
targetClass: board.class.Card,
statusCategories: [
task.statusCategory.UnStarted,
task.statusCategory.Active,
task.statusCategory.Won,
task.statusCategory.Lost
],
statusClass: core.class.Status,
kind: 'task'
}
])
}
},
{
state: 'identifier',
func: migrateIdentifiers
}
])
},
async upgrade (client: MigrationUpgradeClient): Promise<void> {
const ops = new TxOperations(client, core.account.System)
// For now need to be created every time as it's system model
await createDefaultProjectType(ops)

await tryUpgrade(client, boardId, [
{
state: 'board0001',
func: async () => {
const ops = new TxOperations(client, core.account.System)
await createDefaults(ops)
}
}
Expand Down
3 changes: 2 additions & 1 deletion models/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ import {
TSpaceTypeDescriptor,
TTypedSpace
} from './security'
import { TStatus, TStatusCategory } from './status'
import { TStatus, TStatusCategory, TDomainStatusPlaceholder } from './status'
import { TUserStatus } from './transient'
import {
TTx,
Expand Down Expand Up @@ -171,6 +171,7 @@ export function createModel (builder: Builder): void {
TConfigurationElement,
TIndexConfiguration,
TStatus,
TDomainStatusPlaceholder,
TStatusCategory,
TMigrationState,
TBlob,
Expand Down
62 changes: 61 additions & 1 deletion models/core/src/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,68 @@
// limitations under the License.
//

import core, { coreId, DOMAIN_DOC_INDEX_STATE, isClassIndexable, TxOperations } from '@hcengineering/core'
import core, {
coreId,
DOMAIN_DOC_INDEX_STATE,
DOMAIN_STATUS,
isClassIndexable,
type Status,
TxOperations,
generateId,
DOMAIN_TX,
type TxCreateDoc
} from '@hcengineering/core'
import {
tryMigrate,
tryUpgrade,
type MigrateOperation,
type MigrationClient,
type MigrationUpgradeClient
} from '@hcengineering/model'

async function migrateStatusesToModel (client: MigrationClient): Promise<void> {
// Move statuses to model:
// Migrate the default ones with well-known ids as system's model
// And the rest as user's model
// Skip __superseded statuses
const allStatuses = await client.find<Status>(DOMAIN_STATUS, {
_class: core.class.Status,
__superseded: { $exists: false }
})

for (const status of allStatuses) {
const isSystem = (status as any).__migratedFrom !== undefined
const modifiedBy =
status.modifiedBy === core.account.System
? isSystem
? core.account.System
: core.account.ConfigUser
: status.modifiedBy

const tx: TxCreateDoc<Status> = {
_id: generateId(),
_class: core.class.TxCreateDoc,
space: core.space.Tx,
objectId: status._id,
objectClass: status._class,
objectSpace: core.space.Model,
attributes: {
ofAttribute: status.ofAttribute,
category: status.category,
name: status.name,
color: status.color,
description: status.description
},
modifiedOn: status.modifiedOn,
createdBy: status.createdBy,
createdOn: status.createdOn,
modifiedBy
}

await client.create(DOMAIN_TX, tx)
}
}

export const coreOperation: MigrateOperation = {
async migrate (client: MigrationClient): Promise<void> {
// We need to delete all documents in doc index state for missing classes
Expand All @@ -37,6 +91,12 @@ export const coreOperation: MigrateOperation = {
}
}
)
await tryMigrate(client, coreId, [
{
state: 'statuses-to-model',
func: migrateStatusesToModel
}
])
},
async upgrade (client: MigrationUpgradeClient): Promise<void> {
await tryUpgrade(client, coreId, [
Expand Down
12 changes: 10 additions & 2 deletions models/core/src/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import {
DOMAIN_STATUS,
type Ref,
type Status,
type StatusCategory
type StatusCategory,
type Doc,
type Class
} from '@hcengineering/core'
import { Model, Prop, TypeRef, TypeString, UX } from '@hcengineering/model'
import { type Asset, type IntlString } from '@hcengineering/platform'
Expand All @@ -28,7 +30,13 @@ import { TDoc } from './core'

// S T A T U S

@Model(core.class.Status, core.class.Doc, DOMAIN_STATUS)
// Note: domain is removed if there's no model for that domain
// We want to keep status domain for the migration period to make sure we don't lose
// any data. After the migration period, we can remove this model along with the domain.
@Model('domain:status:placeholder' as Ref<Class<Doc>>, core.class.Doc, DOMAIN_STATUS)
export class TDomainStatusPlaceholder extends TDoc {}

@Model(core.class.Status, core.class.Doc, DOMAIN_MODEL)
@UX(core.string.Status, undefined, undefined, undefined, 'name')
export class TStatus extends TDoc implements Status {
// We attach to attribute, so we could distinguish between
Expand Down
29 changes: 24 additions & 5 deletions models/document/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
//

import activity from '@hcengineering/activity'
import type { Class, CollaborativeDoc, CollectionSize, Domain, Ref } from '@hcengineering/core'
import { IndexKind } from '@hcengineering/core'
import type { Class, CollaborativeDoc, CollectionSize, Domain, Role, RolesAssignment } from '@hcengineering/core'
import { IndexKind, Account, Ref } from '@hcengineering/core'
import {
type Document,
type DocumentEmbedding,
Expand All @@ -36,7 +36,8 @@ import {
TypeString,
UX,
TypeCollaborativeDoc,
TypeCollaborativeDocVersion
TypeCollaborativeDocVersion,
Mixin
} from '@hcengineering/model'
import attachment, { TAttachment } from '@hcengineering/model-attachment'
import chunter from '@hcengineering/model-chunter'
Expand All @@ -49,7 +50,7 @@ import tracker from '@hcengineering/model-tracker'
import view, { actionTemplates, createAction } from '@hcengineering/model-view'
import workbench from '@hcengineering/model-workbench'
import notification from '@hcengineering/notification'
import { type Asset } from '@hcengineering/platform'
import { getEmbeddedLabel, type Asset } from '@hcengineering/platform'
import tags from '@hcengineering/tags'
import time from '@hcengineering/time'
import document from './plugin'
Expand Down Expand Up @@ -162,6 +163,12 @@ export class TSavedDocument extends TPreference implements SavedDocument {
@UX(document.string.Teamspace, document.icon.Teamspace, 'Teamspace', 'name')
export class TTeamspace extends TTypedSpace implements Teamspace {}

@Mixin(document.mixin.DefaultTeamspaceTypeData, document.class.Teamspace)
@UX(getEmbeddedLabel('Default teamspace type'), document.icon.Document)
export class TDefaultTeamspaceTypeData extends TTeamspace implements RolesAssignment {
[key: Ref<Role>]: Ref<Account>[]
}

function defineTeamspace (builder: Builder): void {
builder.createModel(TTeamspace)

Expand All @@ -178,6 +185,18 @@ function defineTeamspace (builder: Builder): void {
document.descriptor.TeamspaceType
)

builder.createDoc(
core.class.SpaceType,
core.space.Model,
{
name: 'Default teamspace type',
descriptor: document.descriptor.TeamspaceType,
roles: 0,
targetClass: document.mixin.DefaultTeamspaceTypeData
},
document.spaceType.DefaultTeamspaceType
)

// Navigator

builder.mixin(document.class.Teamspace, core.class.Class, view.mixin.SpacePresenter, {
Expand Down Expand Up @@ -231,7 +250,7 @@ function defineTeamspace (builder: Builder): void {
}

function defineDocument (builder: Builder): void {
builder.createModel(TDocument, TDocumentSnapshot, TDocumentEmbedding, TSavedDocument)
builder.createModel(TDocument, TDocumentSnapshot, TDocumentEmbedding, TSavedDocument, TDefaultTeamspaceTypeData)

builder.mixin(document.class.Document, core.class.Class, time.mixin.ItemPresenter, {
presenter: document.component.DocumentToDoPresenter
Expand Down
Loading
Loading