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

TSK-943:General Status support #2842

Merged
merged 11 commits into from
Apr 4, 2023
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
12 changes: 7 additions & 5 deletions dev/generator/src/kanban.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export async function createUpdateSpaceKanban (

await ctx.with('find-or-update', {}, (ctx) =>
findOrUpdate(ctx, client, spaceId, task.class.State, sid, {
title: st.name,
ofAttribute: task.attribute.State,
name: st.name,
color: st.color,
rank
})
Expand All @@ -37,8 +38,8 @@ export async function createUpdateSpaceKanban (
}

const doneStates = [
{ class: task.class.WonState, title: 'Won' },
{ class: task.class.LostState, title: 'Lost' }
{ class: task.class.WonState, name: 'Won' },
{ class: task.class.LostState, name: 'Lost' }
]
const doneStateRanks = genRanks(doneStates.length)
for (const st of doneStates) {
Expand All @@ -49,10 +50,11 @@ export async function createUpdateSpaceKanban (
break
}

const sid = ('generated-' + spaceId + '.done-state.' + st.title.toLowerCase().replace(' ', '_')) as Ref<DoneState>
const sid = `generated-${spaceId}.done-state.${st.name.toLowerCase().replace(' ', '_')}` as Ref<DoneState>
await ctx.with('gen-done-state', {}, (ctx) =>
findOrUpdate(ctx, client, spaceId, st.class, sid, {
title: st.title,
ofAttribute: task.attribute.DoneState,
name: st.name,
rank
})
)
Expand Down
3 changes: 2 additions & 1 deletion models/board/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,8 @@ export function createModel (builder: Builder): void {
task.class.WonState,
core.space.Model,
{
title: board.string.Completed,
ofAttribute: task.attribute.DoneState,
name: board.string.Completed,
rank: '0'
},
board.state.Completed
Expand Down
98 changes: 8 additions & 90 deletions models/board/src/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,11 @@
// limitations under the License.
//

import { Board, Card } from '@hcengineering/board'
import {
AttachedDoc,
Class,
Doc,
DOMAIN_TX,
generateId,
Ref,
TxCollectionCUD,
TxCreateDoc,
TxCUD,
TxOperations,
TxProcessor,
TxUpdateDoc
} from '@hcengineering/core'
import { Ref, TxOperations } from '@hcengineering/core'
import { createOrUpdate, MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model'
import core from '@hcengineering/model-core'
import { DOMAIN_TAGS } from '@hcengineering/model-tags'
import { createKanbanTemplate, createSequence, DOMAIN_TASK } from '@hcengineering/model-task'
import tags, { TagElement, TagReference } from '@hcengineering/tags'
import { createKanbanTemplate, createSequence } from '@hcengineering/model-task'
import tags from '@hcengineering/tags'
import task, { createKanban, KanbanTemplate } from '@hcengineering/task'
import board from './plugin'

Expand Down Expand Up @@ -77,12 +62,12 @@ async function createSpace (tx: TxOperations): Promise<void> {
async function createDefaultKanbanTemplate (tx: TxOperations): Promise<Ref<KanbanTemplate>> {
const defaultKanban = {
states: [
{ color: 9, title: 'To do' },
{ color: 9, title: 'Done' }
{ color: 9, name: 'To do' },
{ color: 9, name: 'Done' }
],
doneStates: [
{ isWon: true, title: 'Won' },
{ isWon: false, title: 'Lost' }
{ isWon: true, name: 'Won' },
{ isWon: false, name: 'Lost' }
]
}

Expand Down Expand Up @@ -123,74 +108,7 @@ async function createDefaults (tx: TxOperations): Promise<void> {
)
}

interface CardLabel extends AttachedDoc {
title: string
color: number
isHidden?: boolean
}
async function migrateLabels (client: MigrationClient): Promise<void> {
const objectClass = 'board:class:CardLabel' as Ref<Class<Doc>>
const txes = await client.find<TxCUD<CardLabel>>(DOMAIN_TX, { objectClass }, { sort: { modifiedOn: 1 } })
const collectionTxes = await client.find<TxCollectionCUD<Board, CardLabel>>(
DOMAIN_TX,
{ 'tx.objectClass': objectClass },
{ sort: { modifiedOn: 1 } }
)
await Promise.all([...txes, ...collectionTxes].map(({ _id }) => client.delete<Doc>(DOMAIN_TX, _id)))
const removed = txes.filter(({ _class }) => _class === core.class.TxRemoveDoc).map(({ objectId }) => objectId)
const createTxes = txes.filter(
({ _class, objectId }) => _class === core.class.TxCreateDoc && !removed.includes(objectId)
) as unknown as TxCreateDoc<CardLabel>[]
const cardLabels = createTxes.map((createTx) => {
const cardLabel = TxProcessor.createDoc2Doc(createTx)
const updateTxes = collectionTxes
.map(({ tx }) => tx)
.filter(
({ _class, objectId }) => _class === core.class.TxUpdateDoc && objectId === createTx.objectId
) as unknown as TxUpdateDoc<CardLabel>[]
return updateTxes.reduce((label, updateTx) => TxProcessor.updateDoc2Doc(label, updateTx), cardLabel)
})
await Promise.all(
cardLabels.map((cardLabel) =>
client.create<TagElement>(DOMAIN_TAGS, {
_class: tags.class.TagElement,
space: tags.space.Tags,
targetClass: board.class.Card,
category: board.category.Other,
_id: cardLabel._id as unknown as Ref<TagElement>,
modifiedBy: cardLabel.modifiedBy,
modifiedOn: cardLabel.modifiedOn,
title: cardLabel.title,
color: cardLabel.color,
description: ''
})
)
)
const cards = (await client.find<Card>(DOMAIN_TASK, { _class: board.class.Card })).filter((card) =>
Array.isArray(card.labels)
)
for (const card of cards) {
const labelRefs = card.labels as unknown as Array<Ref<CardLabel>>
await client.update<Card>(DOMAIN_TASK, { _id: card._id }, { labels: labelRefs.length })
for (const labelRef of labelRefs) {
const cardLabel = cardLabels.find(({ _id }) => _id === labelRef)
if (cardLabel === undefined) continue
await client.create<TagReference>(DOMAIN_TAGS, {
_class: tags.class.TagReference,
attachedToClass: board.class.Card,
_id: generateId(),
attachedTo: card._id,
space: card.space,
tag: cardLabel._id as unknown as Ref<TagElement>,
title: cardLabel.title,
color: cardLabel.color,
modifiedBy: cardLabel.modifiedBy,
modifiedOn: cardLabel.modifiedOn,
collection: 'labels'
})
}
}
}
async function migrateLabels (client: MigrationClient): Promise<void> {}
export const boardOperation: MigrateOperation = {
async migrate (client: MigrationClient): Promise<void> {
await Promise.all([migrateLabels(client)])
Expand Down
6 changes: 5 additions & 1 deletion models/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,15 @@ import {
TVersion
} from './core'
import { TAccount, TSpace } from './security'
import { TStatus, TStatusCategory } from './status'
import { TUserStatus } from './transient'
import { TTx, TTxApplyIf, TTxCollectionCUD, TTxCreateDoc, TTxCUD, TTxMixin, TTxRemoveDoc, TTxUpdateDoc } from './tx'

export * from './core'
export { coreOperation } from './migration'
export * from './security'
export * from './tx'
export * from './status'
export { core as default }

export function createModel (builder: Builder): void {
Expand Down Expand Up @@ -114,7 +116,9 @@ export function createModel (builder: Builder): void {
TFullTextSearchContext,
TConfiguration,
TConfigurationElement,
TIndexConfiguration
TIndexConfiguration,
TStatus,
TStatusCategory
)

builder.createDoc(
Expand Down
57 changes: 57 additions & 0 deletions models/core/src/status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// Copyright © 2023 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 { Attribute, DOMAIN_STATUS, DOMAIN_MODEL, Ref, Status, StatusCategory } from '@hcengineering/core'
import { Model, Prop, TypeRef, TypeString, UX } from '@hcengineering/model'
import { Asset, IntlString } from '@hcengineering/platform'
import core from './component'
import { TDoc } from './core'

// S T A T U S

@Model(core.class.Status, core.class.Doc, DOMAIN_STATUS)
@UX(core.string.Status)
export class TStatus extends TDoc implements Status {
// We attach to attribute, so we could distinguish between
ofAttribute!: Ref<Attribute<Status>>

@Prop(TypeRef(core.class.StatusCategory), core.string.StatusCategory)
category!: Ref<StatusCategory>

@Prop(TypeString(), core.string.Name)
name!: string

// @Prop(TypeNumber(), core.string.Color)
color!: number

@Prop(TypeString(), core.string.Description)
description!: string

// @Prop(TypeString(), core.string.Rank)
rank!: string
}

@Model(core.class.StatusCategory, core.class.Doc, DOMAIN_MODEL)
@UX(core.string.StatusCategory)
export class TStatusCategory extends TDoc implements StatusCategory {
// We attach to attribute, so we could distinguish between
ofAttribute!: Ref<Attribute<Status>>

icon!: Asset
label!: IntlString
color!: number
defaultStatusName!: string
order!: number
}
42 changes: 34 additions & 8 deletions models/lead/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

// To help typescript locate view plugin properly
import type { Employee } from '@hcengineering/contact'
import { Doc, FindOptions, IndexKind, Ref } from '@hcengineering/core'
import { FindOptions, IndexKind, Ref, SortingOrder } from '@hcengineering/core'
import { Customer, Funnel, Lead, leadId } from '@hcengineering/lead'
import {
Builder,
Expand All @@ -33,10 +33,11 @@ import attachment from '@hcengineering/model-attachment'
import chunter from '@hcengineering/model-chunter'
import contact, { TContact } from '@hcengineering/model-contact'
import core from '@hcengineering/model-core'
import task, { actionTemplates, TSpaceWithStates, TTask } from '@hcengineering/model-task'
import view, { actionTemplates as viewTemplates, createAction } from '@hcengineering/model-view'
import task, { TSpaceWithStates, TTask, actionTemplates } from '@hcengineering/model-task'
import view, { createAction, actionTemplates as viewTemplates } from '@hcengineering/model-view'
import workbench from '@hcengineering/model-workbench'
import setting from '@hcengineering/setting'
import { ViewOptionsModel } from '@hcengineering/view'
import lead from './plugin'

@Model(lead.class.Funnel, task.class.SpaceWithStates)
Expand Down Expand Up @@ -256,6 +257,31 @@ export function createModel (builder: Builder): void {
},
lead.viewlet.ListLead
)
const leadViewOptions: ViewOptionsModel = {
groupBy: ['state', 'assignee'],
orderBy: [
['state', SortingOrder.Ascending],
['modifiedOn', SortingOrder.Descending],
['dueDate', SortingOrder.Descending],
['rank', SortingOrder.Ascending]
],
other: [
{
key: 'shouldShowAll',
type: 'toggle',
defaultValue: false,
actionTarget: 'category',
action: view.function.ShowEmptyGroups,
label: view.string.ShowEmptyGroups
}
]
}

const lookupLeadOptions: FindOptions<Lead> = {
lookup: {
attachedTo: lead.mixin.Customer
}
}

builder.createDoc(
view.class.Viewlet,
Expand All @@ -264,11 +290,11 @@ export function createModel (builder: Builder): void {
attachTo: lead.class.Lead,
descriptor: task.viewlet.Kanban,
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
options: {
lookup: {
attachedTo: lead.mixin.Customer
}
} as FindOptions<Doc>, // TODO: fix
viewOptions: {
...leadViewOptions,
groupDepth: 1
},
options: lookupLeadOptions,
config: []
},
lead.viewlet.KanbanLead
Expand Down
16 changes: 8 additions & 8 deletions models/lead/src/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,16 @@ async function createSpace (tx: TxOperations): Promise<void> {
async function createDefaultKanbanTemplate (tx: TxOperations): Promise<Ref<KanbanTemplate>> {
const defaultKanban = {
states: [
{ color: 9, title: 'Incoming' },
{ color: 10, title: 'Negotation' },
{ color: 1, title: 'Offer preparing' },
{ color: 0, title: 'Make a decision' },
{ color: 11, title: 'Contract conclusion' },
{ color: 9, title: 'Done' }
{ color: 9, name: 'Incoming' },
{ color: 10, name: 'Negotation' },
{ color: 1, name: 'Offer preparing' },
{ color: 0, name: 'Make a decision' },
{ color: 11, name: 'Contract conclusion' },
{ color: 9, name: 'Done' }
],
doneStates: [
{ isWon: true, title: 'Won' },
{ isWon: false, title: 'Lost' }
{ isWon: true, name: 'Won' },
{ isWon: false, name: 'Lost' }
]
}

Expand Down
Loading