mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 11:01:54 +03:00
Fix statuses (#3666)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
47e39eae75
commit
f3c3541964
@ -35,12 +35,13 @@ import contact from '@hcengineering/model-contact'
|
||||
import core, { TDoc, TType } from '@hcengineering/model-core'
|
||||
import preference, { TPreference } from '@hcengineering/model-preference'
|
||||
import tags from '@hcengineering/model-tags'
|
||||
import task, { TSpaceWithStates, TTask } from '@hcengineering/model-task'
|
||||
import task, { TSpaceWithStates, TTask, actionTemplates as taskActionTemplates } from '@hcengineering/model-task'
|
||||
import view, { actionTemplates, createAction, actionTemplates as viewTemplates } from '@hcengineering/model-view'
|
||||
import workbench, { Application } from '@hcengineering/model-workbench'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import type { AnyComponent } from '@hcengineering/ui'
|
||||
import board from './plugin'
|
||||
import { State } from '@hcengineering/task'
|
||||
|
||||
export { boardId } from '@hcengineering/board'
|
||||
export { boardOperation } from './migration'
|
||||
@ -99,6 +100,9 @@ export class TCard extends TTask implements Card {
|
||||
|
||||
@Prop(TypeDate(), task.string.StartDate)
|
||||
startDate!: Timestamp | null
|
||||
|
||||
@Prop(TypeRef(task.class.State), task.string.TaskState, { _id: board.attribute.State })
|
||||
declare status: Ref<State>
|
||||
}
|
||||
|
||||
@Model(board.class.MenuPage, core.class.Doc, DOMAIN_MODEL)
|
||||
@ -167,6 +171,27 @@ export function createModel (builder: Builder): void {
|
||||
board.app.Board
|
||||
)
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
...taskActionTemplates.editStatus,
|
||||
target: board.class.Board,
|
||||
actionProps: {
|
||||
ofAttribute: board.attribute.State,
|
||||
doneOfAttribute: board.attribute.DoneState
|
||||
},
|
||||
query: {
|
||||
archived: false
|
||||
},
|
||||
context: {
|
||||
mode: ['context', 'browser'],
|
||||
group: 'edit'
|
||||
},
|
||||
override: [task.action.EditStatuses]
|
||||
},
|
||||
board.action.EditStatuses
|
||||
)
|
||||
|
||||
// const leadLookup: Lookup<Card> =
|
||||
// {
|
||||
// state: task.class.State,
|
||||
|
@ -22,7 +22,7 @@ import task, { KanbanTemplate, createStates } from '@hcengineering/task'
|
||||
import board from './plugin'
|
||||
|
||||
async function createSpace (tx: TxOperations): Promise<void> {
|
||||
const currentTemplate = await tx.findOne(core.class.Space, {
|
||||
const currentTemplate = await tx.findOne(task.class.KanbanTemplateSpace, {
|
||||
_id: board.space.BoardTemplates
|
||||
})
|
||||
if (currentTemplate === undefined) {
|
||||
@ -36,10 +36,17 @@ async function createSpace (tx: TxOperations): Promise<void> {
|
||||
private: false,
|
||||
archived: false,
|
||||
members: [],
|
||||
attachedToClass: board.class.Board
|
||||
attachedToClass: board.class.Board,
|
||||
ofAttribute: board.attribute.State,
|
||||
doneAttribute: board.attribute.DoneState
|
||||
},
|
||||
board.space.BoardTemplates
|
||||
)
|
||||
} else if (currentTemplate.ofAttribute === undefined) {
|
||||
await tx.update(currentTemplate, {
|
||||
ofAttribute: board.attribute.State,
|
||||
doneAttribute: board.attribute.DoneState
|
||||
})
|
||||
}
|
||||
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
@ -47,7 +54,7 @@ async function createSpace (tx: TxOperations): Promise<void> {
|
||||
})
|
||||
if (current === undefined) {
|
||||
const defaultTmpl = await createDefaultKanbanTemplate(tx)
|
||||
const [states, doneStates] = await createStates(tx, defaultTmpl)
|
||||
const [states, doneStates] = await createStates(tx, board.attribute.State, board.attribute.DoneState, defaultTmpl)
|
||||
await tx.createDoc(
|
||||
board.class.Board,
|
||||
core.space.Space,
|
||||
@ -77,13 +84,18 @@ async function createDefaultKanbanTemplate (tx: TxOperations): Promise<Ref<Kanba
|
||||
]
|
||||
}
|
||||
|
||||
return await createKanbanTemplate(tx, {
|
||||
kanbanId: board.template.DefaultBoard,
|
||||
space: board.space.BoardTemplates,
|
||||
title: 'Default board',
|
||||
states: defaultKanban.states,
|
||||
doneStates: defaultKanban.doneStates
|
||||
})
|
||||
return await createKanbanTemplate(
|
||||
tx,
|
||||
{
|
||||
kanbanId: board.template.DefaultBoard,
|
||||
space: board.space.BoardTemplates,
|
||||
title: 'Default board',
|
||||
states: defaultKanban.states,
|
||||
doneStates: defaultKanban.doneStates
|
||||
},
|
||||
board.attribute.State,
|
||||
board.attribute.DoneState
|
||||
)
|
||||
}
|
||||
async function createDefaults (tx: TxOperations): Promise<void> {
|
||||
await createSpace(tx)
|
||||
|
@ -62,6 +62,7 @@ export default mergeIds(boardId, board, {
|
||||
ConfigDescription: '' as IntlString
|
||||
},
|
||||
action: {
|
||||
EditStatuses: '' as Ref<Action>,
|
||||
ConvertToCard: '' as Ref<Action>
|
||||
},
|
||||
actionImpl: {
|
||||
|
@ -81,7 +81,7 @@ export class TLead extends TTask implements Lead {
|
||||
@Prop(TypeRef(contact.mixin.Employee), lead.string.Assignee)
|
||||
declare assignee: Ref<Employee> | null
|
||||
|
||||
@Prop(TypeRef(task.class.State), task.string.TaskState, { _id: task.attribute.State })
|
||||
@Prop(TypeRef(task.class.State), task.string.TaskState, { _id: lead.attribute.State })
|
||||
declare status: Ref<State>
|
||||
|
||||
declare space: Ref<Funnel>
|
||||
@ -365,6 +365,27 @@ export function createModel (builder: Builder): void {
|
||||
}
|
||||
}
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
...actionTemplates.editStatus,
|
||||
target: lead.class.Funnel,
|
||||
actionProps: {
|
||||
ofAttribute: lead.attribute.State,
|
||||
doneOfAttribute: lead.attribute.DoneState
|
||||
},
|
||||
query: {
|
||||
archived: false
|
||||
},
|
||||
context: {
|
||||
mode: ['context', 'browser'],
|
||||
group: 'edit'
|
||||
},
|
||||
override: [task.action.EditStatuses]
|
||||
},
|
||||
lead.action.EditStatuses
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationGroup,
|
||||
core.space.Model,
|
||||
|
@ -22,7 +22,7 @@ import { PaletteColorIndexes } from '@hcengineering/ui/src/colors'
|
||||
import lead from './plugin'
|
||||
|
||||
async function createSpace (tx: TxOperations): Promise<void> {
|
||||
const currentTemplate = await tx.findOne(core.class.Space, {
|
||||
const currentTemplate = await tx.findOne(task.class.KanbanTemplateSpace, {
|
||||
_id: lead.space.FunnelTemplates
|
||||
})
|
||||
if (currentTemplate === undefined) {
|
||||
@ -36,10 +36,17 @@ async function createSpace (tx: TxOperations): Promise<void> {
|
||||
private: false,
|
||||
members: [],
|
||||
archived: false,
|
||||
attachedToClass: lead.class.Funnel
|
||||
attachedToClass: lead.class.Funnel,
|
||||
ofAttribute: lead.attribute.State,
|
||||
doneAttribute: lead.attribute.DoneState
|
||||
},
|
||||
lead.space.FunnelTemplates
|
||||
)
|
||||
} else if (currentTemplate.ofAttribute === undefined) {
|
||||
await tx.update(currentTemplate, {
|
||||
ofAttribute: lead.attribute.State,
|
||||
doneAttribute: lead.attribute.DoneState
|
||||
})
|
||||
}
|
||||
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
@ -47,7 +54,7 @@ async function createSpace (tx: TxOperations): Promise<void> {
|
||||
})
|
||||
if (current === undefined) {
|
||||
const defaultTmpl = await createDefaultKanbanTemplate(tx)
|
||||
const [states, doneStates] = await createStates(tx, defaultTmpl)
|
||||
const [states, doneStates] = await createStates(tx, lead.attribute.State, lead.attribute.DoneState, defaultTmpl)
|
||||
await tx.createDoc(
|
||||
lead.class.Funnel,
|
||||
core.space.Space,
|
||||
@ -81,13 +88,18 @@ async function createDefaultKanbanTemplate (tx: TxOperations): Promise<Ref<Kanba
|
||||
]
|
||||
}
|
||||
|
||||
return await createKanbanTemplate(tx, {
|
||||
kanbanId: lead.template.DefaultFunnel,
|
||||
space: lead.space.FunnelTemplates,
|
||||
title: 'Default funnel',
|
||||
states: defaultKanban.states,
|
||||
doneStates: defaultKanban.doneStates
|
||||
})
|
||||
return await createKanbanTemplate(
|
||||
tx,
|
||||
{
|
||||
kanbanId: lead.template.DefaultFunnel,
|
||||
space: lead.space.FunnelTemplates,
|
||||
title: 'Default funnel',
|
||||
states: defaultKanban.states,
|
||||
doneStates: defaultKanban.doneStates
|
||||
},
|
||||
lead.attribute.State,
|
||||
lead.attribute.DoneState
|
||||
)
|
||||
}
|
||||
|
||||
async function fixTemplateSpace (tx: TxOperations): Promise<void> {
|
||||
|
@ -60,6 +60,7 @@ export default mergeIds(leadId, lead, {
|
||||
Lead: '' as Ref<ActionCategory>
|
||||
},
|
||||
action: {
|
||||
EditStatuses: '' as Ref<Action>,
|
||||
CreateGlobalLead: '' as Ref<Action>
|
||||
},
|
||||
ids: {
|
||||
|
@ -165,7 +165,7 @@ export class TApplicant extends TTask implements Applicant {
|
||||
@Prop(TypeRef(contact.mixin.Employee), recruit.string.AssignedRecruiter)
|
||||
declare assignee: Ref<Employee> | null
|
||||
|
||||
@Prop(TypeRef(task.class.State), task.string.TaskState, { _id: task.attribute.State })
|
||||
@Prop(TypeRef(task.class.State), task.string.TaskState, { _id: recruit.attribute.State })
|
||||
declare status: Ref<State>
|
||||
}
|
||||
|
||||
@ -368,6 +368,27 @@ export function createModel (builder: Builder): void {
|
||||
recruit.app.Recruit
|
||||
)
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
...actionTemplates.editStatus,
|
||||
target: recruit.class.Vacancy,
|
||||
actionProps: {
|
||||
ofAttribute: recruit.attribute.State,
|
||||
doneOfAttribute: recruit.attribute.DoneState
|
||||
},
|
||||
query: {
|
||||
archived: false
|
||||
},
|
||||
context: {
|
||||
mode: ['context', 'browser'],
|
||||
group: 'edit'
|
||||
},
|
||||
override: [task.action.EditStatuses]
|
||||
},
|
||||
recruit.action.EditStatuses
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
view.class.Viewlet,
|
||||
core.space.Model,
|
||||
|
@ -92,15 +92,20 @@ async function createDefaultKanbanTemplate (tx: TxOperations): Promise<Ref<Kanba
|
||||
]
|
||||
}
|
||||
|
||||
return await createKanbanTemplate(tx, {
|
||||
kanbanId: recruit.template.DefaultVacancy,
|
||||
space: recruit.space.VacancyTemplates as Ref<Doc> as Ref<Space>,
|
||||
title: 'Default vacancy',
|
||||
description: '',
|
||||
shortDescription: '',
|
||||
states: defaultKanban.states,
|
||||
doneStates: defaultKanban.doneStates
|
||||
})
|
||||
return await createKanbanTemplate(
|
||||
tx,
|
||||
{
|
||||
kanbanId: recruit.template.DefaultVacancy,
|
||||
space: recruit.space.VacancyTemplates as Ref<Doc> as Ref<Space>,
|
||||
title: 'Default vacancy',
|
||||
description: '',
|
||||
shortDescription: '',
|
||||
states: defaultKanban.states,
|
||||
doneStates: defaultKanban.doneStates
|
||||
},
|
||||
recruit.attribute.State,
|
||||
recruit.attribute.DoneState
|
||||
)
|
||||
}
|
||||
|
||||
async function createSpaces (tx: TxOperations): Promise<void> {
|
||||
@ -142,7 +147,7 @@ async function createSpaces (tx: TxOperations): Promise<void> {
|
||||
await tx.update(currentReviews, { private: false })
|
||||
}
|
||||
|
||||
const currentTemplate = await tx.findOne(core.class.Space, {
|
||||
const currentTemplate = await tx.findOne(task.class.KanbanTemplateSpace, {
|
||||
_id: recruit.space.VacancyTemplates
|
||||
})
|
||||
if (currentTemplate === undefined) {
|
||||
@ -157,9 +162,16 @@ async function createSpaces (tx: TxOperations): Promise<void> {
|
||||
private: false,
|
||||
members: [],
|
||||
archived: false,
|
||||
attachedToClass: recruit.class.Vacancy
|
||||
attachedToClass: recruit.class.Vacancy,
|
||||
ofAttribute: recruit.attribute.State,
|
||||
doneAttribute: recruit.attribute.DoneState
|
||||
},
|
||||
recruit.space.VacancyTemplates
|
||||
)
|
||||
} else if (currentTemplate.ofAttribute === undefined) {
|
||||
await tx.update(currentTemplate, {
|
||||
ofAttribute: recruit.attribute.State,
|
||||
doneAttribute: recruit.attribute.DoneState
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,8 @@ export default mergeIds(recruitId, recruit, {
|
||||
CopyApplicationLink: '' as Ref<Action>,
|
||||
CopyCandidateLink: '' as Ref<Action>,
|
||||
MoveApplicant: '' as Ref<Action>,
|
||||
GetTalentIds: '' as Ref<Action>
|
||||
GetTalentIds: '' as Ref<Action>,
|
||||
EditStatuses: '' as Ref<Action>
|
||||
},
|
||||
actionImpl: {
|
||||
CreateOpinion: '' as ViewAction,
|
||||
|
@ -158,6 +158,8 @@ export class TKanbanTemplateSpace extends TSpace implements KanbanTemplateSpace
|
||||
description!: IntlString
|
||||
icon!: AnyComponent
|
||||
editor!: AnyComponent
|
||||
ofAttribute!: Ref<Attribute<State>>
|
||||
doneAttribute!: Ref<Attribute<DoneState>>
|
||||
attachedToClass!: Ref<Class<Doc>>
|
||||
}
|
||||
|
||||
@ -337,6 +339,10 @@ export function createModel (builder: Builder): void {
|
||||
{
|
||||
...actionTemplates.editStatus,
|
||||
target: task.class.SpaceWithStates,
|
||||
actionProps: {
|
||||
ofAttribute: task.attribute.State,
|
||||
doneOfAttribute: task.attribute.DoneState
|
||||
},
|
||||
query: {
|
||||
archived: false
|
||||
},
|
||||
|
@ -14,6 +14,7 @@
|
||||
//
|
||||
|
||||
import {
|
||||
Attribute,
|
||||
Class,
|
||||
DOMAIN_STATUS,
|
||||
DOMAIN_TX,
|
||||
@ -25,13 +26,14 @@ import {
|
||||
TxCollectionCUD,
|
||||
TxCreateDoc,
|
||||
TxOperations,
|
||||
TxUpdateDoc
|
||||
TxUpdateDoc,
|
||||
toIdMap
|
||||
} from '@hcengineering/core'
|
||||
import { MigrateOperation, MigrationClient, MigrationUpgradeClient, createOrUpdate } from '@hcengineering/model'
|
||||
import core, { DOMAIN_SPACE } from '@hcengineering/model-core'
|
||||
import tags from '@hcengineering/model-tags'
|
||||
import { DOMAIN_VIEW } from '@hcengineering/model-view'
|
||||
import { DoneStateTemplate, KanbanTemplate, StateTemplate, Task, genRanks } from '@hcengineering/task'
|
||||
import { DoneState, DoneStateTemplate, KanbanTemplate, State, StateTemplate, Task, genRanks } from '@hcengineering/task'
|
||||
import view, { Filter, FilteredView } from '@hcengineering/view'
|
||||
import { DOMAIN_TASK } from '.'
|
||||
import task from './plugin'
|
||||
@ -73,7 +75,9 @@ export async function createSequence (tx: TxOperations, _class: Ref<Class<Doc>>)
|
||||
*/
|
||||
export async function createKanbanTemplate (
|
||||
client: TxOperations,
|
||||
data: KanbanTemplateData
|
||||
data: KanbanTemplateData,
|
||||
ofAttribute: Ref<Attribute<Status>>,
|
||||
doneAtrtribute?: Ref<Attribute<DoneState>>
|
||||
): Promise<Ref<KanbanTemplate>> {
|
||||
const current = await client.findOne(task.class.KanbanTemplate, { _id: data.kanbanId })
|
||||
if (current !== undefined) {
|
||||
@ -96,7 +100,7 @@ export async function createKanbanTemplate (
|
||||
data.doneStates.map((st, i) =>
|
||||
client.createDoc(st.isWon ? task.class.WonStateTemplate : task.class.LostStateTemplate, data.space, {
|
||||
rank: doneStateRanks[i],
|
||||
ofAttribute: task.attribute.DoneState,
|
||||
ofAttribute: doneAtrtribute ?? ofAttribute,
|
||||
name: st.name,
|
||||
attachedTo: data.kanbanId
|
||||
})
|
||||
@ -108,7 +112,7 @@ export async function createKanbanTemplate (
|
||||
data.states.map((st, i) =>
|
||||
client.createDoc(task.class.StateTemplate, data.space, {
|
||||
attachedTo: data.kanbanId,
|
||||
ofAttribute: task.attribute.State,
|
||||
ofAttribute,
|
||||
rank: stateRanks[i],
|
||||
name: st.name,
|
||||
color: st.color
|
||||
@ -226,7 +230,46 @@ async function renameStatePrefs (client: MigrationUpgradeClient): Promise<void>
|
||||
}
|
||||
}
|
||||
|
||||
async function fixStatusAttributes (client: MigrationClient): Promise<void> {
|
||||
const spaces = await client.find<Space>(DOMAIN_SPACE, {})
|
||||
const map = toIdMap(spaces)
|
||||
const oldStatuses = await client.find<OldStatus>(DOMAIN_STATUS, { space: { $ne: task.space.Statuses } })
|
||||
for (const oldStatus of oldStatuses) {
|
||||
const space = map.get(oldStatus.space)
|
||||
if (space !== undefined) {
|
||||
try {
|
||||
const isDone = oldStatus._class === task.class.DoneState
|
||||
let ofAttribute = task.attribute.State
|
||||
if (space._class === ('recruit:class:Vacancy' as Ref<Class<Space>>)) {
|
||||
ofAttribute = isDone
|
||||
? ('recruit.attribute.DoneState' as Ref<Attribute<State>>)
|
||||
: ('recruit:attribute:State' as Ref<Attribute<State>>)
|
||||
}
|
||||
if (space._class === ('lead:class:Funnel' as Ref<Class<Space>>)) {
|
||||
ofAttribute = isDone
|
||||
? ('lead.attribute.DoneState' as Ref<Attribute<State>>)
|
||||
: ('lead:attribute:State' as Ref<Attribute<State>>)
|
||||
}
|
||||
if (space._class === ('board:class:Board' as Ref<Class<Space>>)) {
|
||||
ofAttribute = isDone
|
||||
? ('board.attribute.DoneState' as Ref<Attribute<State>>)
|
||||
: ('board:attribute:State' as Ref<Attribute<State>>)
|
||||
}
|
||||
if (space._class === ('tracker:class:Project' as Ref<Class<Space>>)) {
|
||||
ofAttribute = 'tracker:attribute:IssueStatus' as Ref<Attribute<State>>
|
||||
}
|
||||
if (ofAttribute !== oldStatus.ofAttribute) {
|
||||
await client.update(DOMAIN_STATUS, { _id: oldStatus._id }, { ofAttribute })
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function migrateStatuses (client: MigrationClient): Promise<void> {
|
||||
await fixStatusAttributes(client)
|
||||
const oldStatuses = await client.find<OldStatus>(DOMAIN_STATUS, { space: { $ne: task.space.Statuses } })
|
||||
const newStatuses: Map<string, Status> = new Map()
|
||||
const oldStatusesMap = new Map<Ref<Status>, Ref<Status>>()
|
||||
|
@ -23,7 +23,12 @@ export async function createVacancy (
|
||||
|
||||
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
|
||||
|
||||
const [states, doneStates] = await createStates(client, templateId)
|
||||
const [states, doneStates] = await createStates(
|
||||
client,
|
||||
recruit.attribute.State,
|
||||
recruit.attribute.DoneState,
|
||||
templateId
|
||||
)
|
||||
|
||||
const id = await client.createDoc(recruit.class.Vacancy, core.space.Space, {
|
||||
name,
|
||||
|
@ -25,7 +25,7 @@ export async function createBoard (
|
||||
description: string,
|
||||
templateId?: Ref<KanbanTemplate>
|
||||
): Promise<Ref<Board>> {
|
||||
const [states, doneStates] = await createStates(client, templateId)
|
||||
const [states, doneStates] = await createStates(client, board.attribute.State, board.attribute.DoneState, templateId)
|
||||
|
||||
const boardRef = await client.createDoc(board.class.Board, core.space.Space, {
|
||||
name,
|
||||
|
@ -15,7 +15,7 @@
|
||||
//
|
||||
|
||||
import { Employee } from '@hcengineering/contact'
|
||||
import type { Class, Doc, Markup, Ref, Timestamp, Type } from '@hcengineering/core'
|
||||
import type { Attribute, Class, Doc, Markup, Ref, Timestamp, Type } from '@hcengineering/core'
|
||||
import type { Asset, IntlString, Plugin } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import type { Preference } from '@hcengineering/preference'
|
||||
@ -120,6 +120,10 @@ const boards = plugin(boardId, {
|
||||
string: {
|
||||
ConfigLabel: '' as IntlString
|
||||
},
|
||||
attribute: {
|
||||
State: '' as Ref<Attribute<State>>,
|
||||
DoneState: '' as Ref<Attribute<DoneState>>
|
||||
},
|
||||
icon: {
|
||||
Board: '' as Asset,
|
||||
Card: '' as Asset
|
||||
|
@ -15,11 +15,11 @@
|
||||
//
|
||||
|
||||
import type { Contact } from '@hcengineering/contact'
|
||||
import type { Class, Doc, Ref, Timestamp } from '@hcengineering/core'
|
||||
import type { Attribute, Class, Doc, Ref, Timestamp } from '@hcengineering/core'
|
||||
import { Mixin } from '@hcengineering/core'
|
||||
import type { Asset, IntlString, Plugin } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import type { KanbanTemplateSpace, SpaceWithStates, State, Task } from '@hcengineering/task'
|
||||
import type { DoneState, KanbanTemplateSpace, SpaceWithStates, State, Task } from '@hcengineering/task'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -73,6 +73,10 @@ const lead = plugin(leadId, {
|
||||
Lead: '' as IntlString,
|
||||
ConfigLabel: '' as IntlString
|
||||
},
|
||||
attribute: {
|
||||
State: '' as Ref<Attribute<State>>,
|
||||
DoneState: '' as Ref<Attribute<DoneState>>
|
||||
},
|
||||
icon: {
|
||||
Funnel: '' as Asset,
|
||||
Lead: '' as Asset,
|
||||
|
@ -174,7 +174,12 @@
|
||||
|
||||
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
|
||||
|
||||
const [states, doneStates] = await createStates(client, templateId)
|
||||
const [states, doneStates] = await createStates(
|
||||
client,
|
||||
recruit.attribute.State,
|
||||
recruit.attribute.DoneState,
|
||||
templateId
|
||||
)
|
||||
|
||||
const id = await client.createDoc(
|
||||
recruit.class.Vacancy,
|
||||
|
@ -15,11 +15,21 @@
|
||||
|
||||
import { Event } from '@hcengineering/calendar'
|
||||
import type { Channel, Organization, Person } from '@hcengineering/contact'
|
||||
import type { AttachedData, AttachedDoc, Class, Doc, Mixin, Ref, Space, Timestamp } from '@hcengineering/core'
|
||||
import type {
|
||||
AttachedData,
|
||||
AttachedDoc,
|
||||
Attribute,
|
||||
Class,
|
||||
Doc,
|
||||
Mixin,
|
||||
Ref,
|
||||
Space,
|
||||
Timestamp
|
||||
} from '@hcengineering/core'
|
||||
import type { Asset, IntlString, Plugin, Resource } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import { TagReference } from '@hcengineering/tags'
|
||||
import type { KanbanTemplateSpace, SpaceWithStates, State, Task } from '@hcengineering/task'
|
||||
import type { DoneState, KanbanTemplateSpace, SpaceWithStates, State, Task } from '@hcengineering/task'
|
||||
import { AnyComponent, ResolvedLocation } from '@hcengineering/ui'
|
||||
|
||||
/**
|
||||
@ -155,6 +165,10 @@ const recruit = plugin(recruitId, {
|
||||
Candidate: '' as Ref<Mixin<Candidate>>,
|
||||
VacancyList: '' as Ref<Mixin<VacancyList>>
|
||||
},
|
||||
attribute: {
|
||||
State: '' as Ref<Attribute<State>>,
|
||||
DoneState: '' as Ref<Attribute<DoneState>>
|
||||
},
|
||||
component: {
|
||||
EditVacancy: '' as AnyComponent
|
||||
},
|
||||
|
@ -28,7 +28,7 @@
|
||||
let templateMap = new Map<Ref<KanbanTemplate>, KanbanTemplate>()
|
||||
const templatesQ = createQuery()
|
||||
$: if (folder !== undefined) {
|
||||
templatesQ.query(task.class.KanbanTemplate, { space: folder._id as Ref<Doc> as Ref<Space> }, (result) => {
|
||||
templatesQ.query(task.class.KanbanTemplate, { space: folder._id }, (result) => {
|
||||
templates = result
|
||||
})
|
||||
} else {
|
||||
@ -81,7 +81,7 @@
|
||||
|
||||
await Promise.all(
|
||||
doneStates.map(async (ds) => {
|
||||
await client.createDoc(ds.class, space as Ref<Doc> as Ref<Space>, {
|
||||
await client.createDoc(ds.class, space, {
|
||||
attachedTo: template,
|
||||
ofAttribute: task.attribute.DoneState,
|
||||
name: ds.name,
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Class, Data, Ref } from '@hcengineering/core'
|
||||
import { Attribute, Class, Data, Ref, Status } from '@hcengineering/core'
|
||||
import presentation, { Card, createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { DoneState, SpaceWithStates, State, createState } from '@hcengineering/task'
|
||||
import { EditBox, Label } from '@hcengineering/ui'
|
||||
@ -25,6 +25,7 @@
|
||||
const hierarchy = client.getHierarchy()
|
||||
export let status: State | undefined = undefined
|
||||
export let _class: Ref<Class<State | DoneState>> | undefined = status?._class
|
||||
export let ofAttribute: Ref<Attribute<Status>>
|
||||
export let value = status?.name ?? ''
|
||||
export let space: Ref<SpaceWithStates>
|
||||
|
||||
@ -40,7 +41,7 @@
|
||||
if (status === undefined) {
|
||||
if (!hierarchy.isDerived(_class, task.class.DoneState)) {
|
||||
const newDoc: Data<State> = {
|
||||
ofAttribute: task.attribute.State,
|
||||
ofAttribute,
|
||||
name: value.trim(),
|
||||
color: 9
|
||||
}
|
||||
@ -48,7 +49,7 @@
|
||||
await client.update(_space, { $push: { states: id } })
|
||||
} else {
|
||||
const newDoc: Data<DoneState> = {
|
||||
ofAttribute: task.attribute.DoneState,
|
||||
ofAttribute,
|
||||
name: value.trim()
|
||||
}
|
||||
const id = await createState(client, _class, newDoc)
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Class, Data, Ref, SortingOrder } from '@hcengineering/core'
|
||||
import { Attribute, Class, Data, Ref, SortingOrder, Status } from '@hcengineering/core'
|
||||
import presentation, { Card, getClient } from '@hcengineering/presentation'
|
||||
import { DoneStateTemplate, KanbanTemplate, KanbanTemplateSpace, StateTemplate, calcRank } from '@hcengineering/task'
|
||||
import { EditBox, Label } from '@hcengineering/ui'
|
||||
@ -26,6 +26,7 @@
|
||||
export let status: StateTemplate | undefined = undefined
|
||||
export let _class: Ref<Class<StateTemplate | DoneStateTemplate>> | undefined = status?._class
|
||||
export let template: KanbanTemplate
|
||||
export let ofAttribute: Ref<Attribute<Status>>
|
||||
export let space: KanbanTemplateSpace
|
||||
export let value = status?.name ?? ''
|
||||
|
||||
@ -36,14 +37,14 @@
|
||||
if (_class !== undefined && status === undefined) {
|
||||
const lastOne = await client.findOne(_class, attachedTo, { sort: { rank: SortingOrder.Descending } })
|
||||
let newDoc: Data<StateTemplate> = {
|
||||
ofAttribute: task.attribute.State,
|
||||
ofAttribute,
|
||||
name: value.trim(),
|
||||
rank: calcRank(lastOne, undefined),
|
||||
...attachedTo
|
||||
}
|
||||
if (!hierarchy.isDerived(_class, task.class.DoneState)) {
|
||||
newDoc = {
|
||||
ofAttribute: task.attribute.State,
|
||||
ofAttribute,
|
||||
name: value.trim(),
|
||||
color: 9,
|
||||
rank: calcRank(lastOne, undefined),
|
||||
|
@ -14,7 +14,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Doc, DocumentQuery, IdMap, Ref, Status } from '@hcengineering/core'
|
||||
import type { Attribute, Doc, DocumentQuery, IdMap, Ref, Status } from '@hcengineering/core'
|
||||
import { MessageBox, createQuery, getClient } from '@hcengineering/presentation'
|
||||
import type { DoneState, LostState, SpaceWithStates, State, WonState } from '@hcengineering/task'
|
||||
import { Icon, Label, Panel, Scroller, showPopup } from '@hcengineering/ui'
|
||||
@ -24,6 +24,8 @@
|
||||
import StatesEditor from './StatesEditor.svelte'
|
||||
|
||||
export let _id: Ref<SpaceWithStates>
|
||||
export let ofAttribute: Ref<Attribute<Status>>
|
||||
export let doneOfAttribute: Ref<Attribute<Status>>
|
||||
|
||||
let spaceInstance: SpaceWithStates | undefined
|
||||
|
||||
@ -150,13 +152,18 @@
|
||||
|
||||
<Scroller>
|
||||
<div class="popupPanel-body__main-content py-10 clear-mins">
|
||||
<StatesEditor
|
||||
{states}
|
||||
{wonStates}
|
||||
{lostStates}
|
||||
on:delete={(e) => deleteState(e.detail)}
|
||||
on:move={(e) => onMove(e.detail.stateID, e.detail.position)}
|
||||
/>
|
||||
{#if spaceInstance}
|
||||
<StatesEditor
|
||||
space={_id}
|
||||
{ofAttribute}
|
||||
{doneOfAttribute}
|
||||
{states}
|
||||
{wonStates}
|
||||
{lostStates}
|
||||
on:delete={(e) => deleteState(e.detail)}
|
||||
on:move={(e) => onMove(e.detail.stateID, e.detail.position)}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</Scroller>
|
||||
</Panel>
|
||||
|
@ -14,12 +14,11 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { Attribute, Ref, Status } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import type { DoneState, KanbanTemplate, KanbanTemplateSpace, State } from '@hcengineering/task'
|
||||
import type { DoneState, SpaceWithStates, State } from '@hcengineering/task'
|
||||
import {
|
||||
CircleButton,
|
||||
Component,
|
||||
IconAdd,
|
||||
IconCircles,
|
||||
IconMoreH,
|
||||
@ -39,8 +38,9 @@
|
||||
import Won from '../icons/Won.svelte'
|
||||
import StatusesPopup from './StatusesPopup.svelte'
|
||||
|
||||
export let template: KanbanTemplate | undefined = undefined
|
||||
export let space: KanbanTemplateSpace | undefined = undefined
|
||||
export let space: Ref<SpaceWithStates>
|
||||
export let ofAttribute: Ref<Attribute<Status>> = task.attribute.State
|
||||
export let doneOfAttribute: Ref<Attribute<Status>> = task.attribute.DoneState
|
||||
export let states: State[] = []
|
||||
export let wonStates: DoneState[] = []
|
||||
export let lostStates: DoneState[] = []
|
||||
@ -86,12 +86,8 @@
|
||||
|
||||
await client.updateDoc(state._class, state.space, state._id, { color })
|
||||
}
|
||||
const spaceEditor = (space as KanbanTemplateSpace)?.editor
|
||||
</script>
|
||||
|
||||
{#if spaceEditor}
|
||||
<Component is={spaceEditor} props={{ template }} />
|
||||
{/if}
|
||||
<div class="flex-no-shrink flex-between trans-title uppercase">
|
||||
<Label label={task.string.ActiveStates} />
|
||||
<CircleButton
|
||||
@ -102,15 +98,15 @@
|
||||
task.component.CreateStatePopup,
|
||||
{
|
||||
space,
|
||||
template,
|
||||
_class: template !== undefined ? task.class.StateTemplate : task.class.State
|
||||
ofAttribute,
|
||||
_class: task.class.State
|
||||
},
|
||||
undefined
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-col mt-3">
|
||||
<div class="flex-col flex-no-shrink mt-3">
|
||||
{#each states as state, i}
|
||||
{@const color = getPlatformColorDef(state.color ?? getColorNumberByText(state.name), $themeStore.dark)}
|
||||
{#if state}
|
||||
@ -155,7 +151,7 @@
|
||||
onDelete: () => dispatch('delete', { state }),
|
||||
showDelete: states.length > 1,
|
||||
onUpdate: () => {
|
||||
showPopup(task.component.CreateStatePopup, { status: state, template }, undefined)
|
||||
showPopup(task.component.CreateStatePopup, { status: state, space, ofAttribute }, undefined)
|
||||
}
|
||||
},
|
||||
eventToHTMLElement(ev),
|
||||
@ -169,7 +165,7 @@
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
<div class="flex-col mt-9">
|
||||
<div class="flex-col flex-no-shrink mt-9">
|
||||
<div class="flex-no-shrink flex-between trans-title uppercase">
|
||||
<Label label={task.string.DoneStatesWon} />
|
||||
<CircleButton
|
||||
@ -180,8 +176,8 @@
|
||||
task.component.CreateStatePopup,
|
||||
{
|
||||
space,
|
||||
template,
|
||||
_class: template !== undefined ? task.class.WonStateTemplate : task.class.WonState
|
||||
ofAttribute: doneOfAttribute,
|
||||
_class: task.class.WonState
|
||||
},
|
||||
undefined
|
||||
)
|
||||
@ -215,7 +211,11 @@
|
||||
onDelete: () => dispatch('delete', { state }),
|
||||
showDelete: wonStates.length > 1,
|
||||
onUpdate: () => {
|
||||
showPopup(task.component.CreateStatePopup, { status: state, template }, undefined)
|
||||
showPopup(
|
||||
task.component.CreateStatePopup,
|
||||
{ status: state, space, ofAttribute: doneOfAttribute },
|
||||
undefined
|
||||
)
|
||||
}
|
||||
},
|
||||
eventToHTMLElement(ev),
|
||||
@ -230,7 +230,7 @@
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-9">
|
||||
<div class="mt-9 flex-no-shrink">
|
||||
<div class="flex-no-shrink flex-between trans-title uppercase">
|
||||
<Label label={task.string.DoneStatesLost} />
|
||||
<CircleButton
|
||||
@ -241,8 +241,8 @@
|
||||
task.component.CreateStatePopup,
|
||||
{
|
||||
space,
|
||||
template,
|
||||
_class: template !== undefined ? task.class.LostStateTemplate : task.class.LostState
|
||||
ofAttribute: doneOfAttribute,
|
||||
_class: task.class.LostState
|
||||
},
|
||||
undefined
|
||||
)
|
||||
@ -276,7 +276,11 @@
|
||||
onDelete: () => dispatch('delete', { state }),
|
||||
showDelete: lostStates.length > 1,
|
||||
onUpdate: () => {
|
||||
showPopup(task.component.CreateStatePopup, { status: state, template }, undefined)
|
||||
showPopup(
|
||||
task.component.CreateStatePopup,
|
||||
{ status: state, space, ofAttribute: doneOfAttribute },
|
||||
undefined
|
||||
)
|
||||
}
|
||||
},
|
||||
eventToHTMLElement(ev),
|
||||
|
@ -53,6 +53,7 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
const elements: HTMLElement[] = []
|
||||
let selected: number | undefined
|
||||
@ -95,7 +96,11 @@
|
||||
const spaceEditor = space.editor
|
||||
|
||||
function add (_class: Ref<Class<StateTemplate | DoneStateTemplate>>) {
|
||||
const ofAttribute = hierarchy.isDerived(_class, task.class.DoneStateTemplate)
|
||||
? space.doneAttribute
|
||||
: space.ofAttribute
|
||||
showPopup(task.component.CreateStateTemplatePopup, {
|
||||
ofAttribute,
|
||||
space,
|
||||
template,
|
||||
_class
|
||||
@ -103,7 +108,10 @@
|
||||
}
|
||||
|
||||
function edit (status: StateTemplate) {
|
||||
showPopup(task.component.CreateStateTemplatePopup, { status, template, space })
|
||||
const ofAttribute = hierarchy.isDerived(status._class, task.class.DoneStateTemplate)
|
||||
? space.doneAttribute
|
||||
: space.ofAttribute
|
||||
showPopup(task.component.CreateStateTemplatePopup, { status, template, space, ofAttribute })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -14,38 +14,50 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Attribute, Ref, Status } from '@hcengineering/core'
|
||||
import { Resources } from '@hcengineering/platform'
|
||||
import { SpaceWithStates } from '@hcengineering/task'
|
||||
import { showPopup } from '@hcengineering/ui'
|
||||
import AssignedTasks from './components/AssignedTasks.svelte'
|
||||
import CreateStatePopup from './components/CreateStatePopup.svelte'
|
||||
import CreateStateTemplatePopup from './components/CreateStateTemplatePopup.svelte'
|
||||
import Dashboard from './components/Dashboard.svelte'
|
||||
import DueDateEditor from './components/DueDateEditor.svelte'
|
||||
import KanbanTemplatePresenter from './components/KanbanTemplatePresenter.svelte'
|
||||
import StatusTableView from './components/StatusTableView.svelte'
|
||||
import TaskHeader from './components/TaskHeader.svelte'
|
||||
import TaskPresenter from './components/TaskPresenter.svelte'
|
||||
import KanbanTemplateEditor from './components/kanban/KanbanTemplateEditor.svelte'
|
||||
import KanbanTemplateSelector from './components/kanban/KanbanTemplateSelector.svelte'
|
||||
import KanbanView from './components/kanban/KanbanView.svelte'
|
||||
import DoneStateEditor from './components/state/DoneStateEditor.svelte'
|
||||
import DoneStatePresenter from './components/state/DoneStatePresenter.svelte'
|
||||
import DoneStateRefPresenter from './components/state/DoneStateRefPresenter.svelte'
|
||||
import EditStatuses from './components/state/EditStatuses.svelte'
|
||||
import StateEditor from './components/state/StateEditor.svelte'
|
||||
import StatePresenter from './components/state/StatePresenter.svelte'
|
||||
import StatusTableView from './components/StatusTableView.svelte'
|
||||
import TaskHeader from './components/TaskHeader.svelte'
|
||||
import TaskPresenter from './components/TaskPresenter.svelte'
|
||||
import KanbanTemplatePresenter from './components/KanbanTemplatePresenter.svelte'
|
||||
import StateRefPresenter from './components/state/StateRefPresenter.svelte'
|
||||
import TodoItemPresenter from './components/todos/TodoItemPresenter.svelte'
|
||||
import TodoItemsPopup from './components/todos/TodoItemsPopup.svelte'
|
||||
import Todos from './components/todos/Todos.svelte'
|
||||
import TodoStatePresenter from './components/todos/TodoStatePresenter.svelte'
|
||||
import Dashboard from './components/Dashboard.svelte'
|
||||
import DoneStateRefPresenter from './components/state/DoneStateRefPresenter.svelte'
|
||||
import StateRefPresenter from './components/state/StateRefPresenter.svelte'
|
||||
import DueDateEditor from './components/DueDateEditor.svelte'
|
||||
import CreateStatePopup from './components/CreateStatePopup.svelte'
|
||||
import CreateStateTemplatePopup from './components/CreateStateTemplatePopup.svelte'
|
||||
import Todos from './components/todos/Todos.svelte'
|
||||
|
||||
export { default as AssigneePresenter } from './components/AssigneePresenter.svelte'
|
||||
export { StateRefPresenter }
|
||||
|
||||
async function editStatuses (object: SpaceWithStates): Promise<void> {
|
||||
showPopup(EditStatuses, { _id: object._id, spaceClass: object._class }, 'float')
|
||||
async function editStatuses (
|
||||
object: SpaceWithStates,
|
||||
ev: Event,
|
||||
props: {
|
||||
ofAttribute: Ref<Attribute<Status>>
|
||||
doneOfAttribute: Ref<Attribute<Status>>
|
||||
}
|
||||
): Promise<void> {
|
||||
showPopup(
|
||||
EditStatuses,
|
||||
{ _id: object._id, ofAttribute: props.ofAttribute, doneOfAttribute: props.doneOfAttribute },
|
||||
'float'
|
||||
)
|
||||
}
|
||||
|
||||
export type StatesBarPosition = 'start' | 'middle' | 'end' | undefined
|
||||
|
@ -158,6 +158,8 @@ export interface KanbanTemplateSpace extends Space {
|
||||
name: IntlString
|
||||
description: IntlString
|
||||
icon: AnyComponent
|
||||
ofAttribute: Ref<Attribute<State>>
|
||||
doneAttribute?: Ref<Attribute<DoneState>>
|
||||
editor?: AnyComponent
|
||||
attachedToClass: Ref<Class<Doc>>
|
||||
}
|
||||
|
@ -13,7 +13,17 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Class, Data, DocumentQuery, IdMap, Ref, SortingOrder, Status, TxOperations } from '@hcengineering/core'
|
||||
import {
|
||||
Attribute,
|
||||
Class,
|
||||
Data,
|
||||
DocumentQuery,
|
||||
IdMap,
|
||||
Ref,
|
||||
SortingOrder,
|
||||
Status,
|
||||
TxOperations
|
||||
} from '@hcengineering/core'
|
||||
import { LexoDecimal, LexoNumeralSystem36, LexoRank } from 'lexorank'
|
||||
import LexoRankBucket from 'lexorank/lib/lexoRank/lexoRankBucket'
|
||||
import task, { DoneState, DoneStateTemplate, KanbanTemplate, SpaceWithStates, State } from '.'
|
||||
@ -86,11 +96,13 @@ export async function createState<T extends Status> (
|
||||
*/
|
||||
export async function createStates (
|
||||
client: TxOperations,
|
||||
ofAttribute: Ref<Attribute<Status>>,
|
||||
doneAtrtribute?: Ref<Attribute<DoneState>>,
|
||||
templateId?: Ref<KanbanTemplate>
|
||||
): Promise<[Ref<Status>[], Ref<DoneState>[]]> {
|
||||
if (templateId === undefined) {
|
||||
const state = await createState(client, task.class.State, {
|
||||
ofAttribute: task.attribute.State,
|
||||
ofAttribute,
|
||||
name: 'New State',
|
||||
color: 9
|
||||
})
|
||||
@ -99,13 +111,13 @@ export async function createStates (
|
||||
|
||||
doneStates.push(
|
||||
await createState(client, task.class.WonState, {
|
||||
ofAttribute: task.attribute.DoneState,
|
||||
ofAttribute: doneAtrtribute ?? ofAttribute,
|
||||
name: 'Won'
|
||||
})
|
||||
)
|
||||
doneStates.push(
|
||||
await createState(client, task.class.LostState, {
|
||||
ofAttribute: task.attribute.DoneState,
|
||||
ofAttribute: doneAtrtribute ?? ofAttribute,
|
||||
name: 'Lost'
|
||||
})
|
||||
)
|
||||
@ -131,7 +143,7 @@ export async function createStates (
|
||||
for (const state of tmplStates) {
|
||||
states.push(
|
||||
await createState(client, task.class.State, {
|
||||
ofAttribute: task.attribute.State,
|
||||
ofAttribute,
|
||||
color: state.color,
|
||||
description: state.description,
|
||||
name: state.name
|
||||
@ -157,7 +169,7 @@ export async function createStates (
|
||||
|
||||
doneStates.push(
|
||||
await createState(client, cl, {
|
||||
ofAttribute: task.attribute.DoneState,
|
||||
ofAttribute: doneAtrtribute ?? ofAttribute,
|
||||
description: state.description,
|
||||
name: state.name
|
||||
})
|
||||
|
@ -55,7 +55,6 @@
|
||||
clip-rule="evenodd"
|
||||
d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14ZM8 15C11.866 15 15 11.866 15 8C15 4.13401 11.866 1 8 1C4.13401 1 1 4.13401 1 8C1 11.866 4.13401 15 8 15Z"
|
||||
/>
|
||||
|
||||
{#if statusIcon.count && statusIcon.index}
|
||||
<path
|
||||
d="M 4.5 4.5 L 9 4.5 A 4.5 4.5 0 {statusIcon.index > (statusIcon.count - 1) / 2 ? 1 : 0} 1 {Math.cos(
|
||||
@ -66,7 +65,11 @@
|
||||
transform="translate(3.5,3.5)"
|
||||
/>
|
||||
{:else}
|
||||
<circle cx="8" cy="8" r="4" fill="var(--theme-error-color)" opacity=".15" />
|
||||
<path
|
||||
d="M 4.5 4.5 L 9 4.5 A 4.5 4.5 0 1 1 {Math.cos(Math.PI - 0.01) * 4.5 + 4.5} {Math.sin(Math.PI - 0.01) * 4.5 +
|
||||
4.5} Z"
|
||||
transform="translate(3.5,3.5)"
|
||||
/>
|
||||
{/if}
|
||||
{:else if category._id === tracker.issueStatusCategory.Completed}
|
||||
<path
|
||||
|
@ -49,7 +49,7 @@
|
||||
statuses = getStates(_space, $statusStore).filter((p) => p.category === tracker.issueStatusCategory.Started)
|
||||
}
|
||||
|
||||
async function updateCategory (status: WithLookup<IssueStatus>, statuses: IssueStatus[]) {
|
||||
async function updateCategory (_space: Project | undefined, status: WithLookup<IssueStatus>, statuses: IssueStatus[]) {
|
||||
if (status.$lookup?.category) {
|
||||
category = status.$lookup.category
|
||||
}
|
||||
@ -68,7 +68,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: updateCategory(value, statuses)
|
||||
$: updateCategory(_space, value, statuses)
|
||||
$: icon = category?.icon
|
||||
$: color = value.color !== undefined ? value.color : category !== undefined ? category.color : -1
|
||||
</script>
|
||||
|
@ -117,7 +117,7 @@
|
||||
return {
|
||||
id: s._id,
|
||||
component: StatusPresenter,
|
||||
props: { value: s, size: 'small' },
|
||||
props: { value: s, size: 'small', space: value.space },
|
||||
isSelected: selectedStatus?._id === s._id ?? false
|
||||
}
|
||||
})
|
||||
|
@ -46,7 +46,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex-presenter flex-gap-1-5">
|
||||
{#each statuses as value, i}
|
||||
{#each statuses as value, i (value._id)}
|
||||
{#if value && i < 5}
|
||||
<div>
|
||||
<IssueStatusIcon {space} {value} size={'small'} />
|
||||
|
@ -13,27 +13,27 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import core, { Doc, FindResult, IdMap, Ref, RefTo, Space, Status } from '@hcengineering/core'
|
||||
import core, { Doc, FindResult, IdMap, Ref, RefTo, Space, Status, toIdMap } from '@hcengineering/core'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import task, { SpaceWithStates } from '@hcengineering/task'
|
||||
import ui, {
|
||||
addNotification,
|
||||
deviceOptionsStore,
|
||||
EditWithIcon,
|
||||
Icon,
|
||||
IconCheck,
|
||||
IconSearch,
|
||||
Label,
|
||||
Loading,
|
||||
addNotification,
|
||||
deviceOptionsStore,
|
||||
resizeObserver,
|
||||
themeStore
|
||||
} from '@hcengineering/ui'
|
||||
import { Filter } from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { buildConfigLookup, getPresenter } from '../../utils'
|
||||
import view from '../../plugin'
|
||||
import { FILTER_DEBOUNCE_MS, FilterRemovedNotification, sortFilterValues, statusStore } from '../..'
|
||||
import view from '../../plugin'
|
||||
import { buildConfigLookup, getPresenter } from '../../utils'
|
||||
|
||||
export let filter: Filter
|
||||
export let space: Ref<Space> | undefined = undefined
|
||||
@ -76,11 +76,11 @@
|
||||
}
|
||||
|
||||
if (space !== undefined) {
|
||||
const _space = await client.findOne(core.class.Space, { _id: space })
|
||||
const _space = await client.findOne(task.class.SpaceWithStates, { _id: space as Ref<SpaceWithStates> })
|
||||
if (_space) {
|
||||
values = (_space as any)[filter.key.key]
|
||||
.map((p: Ref<Status>) => statusStore.get(p))
|
||||
.filter((p: Status) => p !== undefined)
|
||||
const targetClass = (filter.key.attribute.type as RefTo<Status>).to
|
||||
const key = hierarchy.isDerived(targetClass, task.class.DoneState) ? 'doneStates' : 'states'
|
||||
values = (_space as any)[key].map((p: Ref<Status>) => statusStore.get(p)).filter((p: Status) => p !== undefined)
|
||||
for (const value of values) {
|
||||
targets.add(value?._id)
|
||||
}
|
||||
@ -89,13 +89,14 @@
|
||||
}
|
||||
}
|
||||
} else {
|
||||
values = []
|
||||
const statuses: Status[] = []
|
||||
for (const status of statusStore.values()) {
|
||||
if (hierarchy.isDerived(status._class, targetClass)) {
|
||||
values.push(status)
|
||||
if (hierarchy.isDerived(status._class, targetClass) && status.ofAttribute === filter.key.attribute._id) {
|
||||
statuses.push(status)
|
||||
targets.add(status._id)
|
||||
}
|
||||
}
|
||||
values = await sort(statuses)
|
||||
}
|
||||
if (targets.has(undefined)) {
|
||||
values.unshift(undefined)
|
||||
@ -120,6 +121,26 @@
|
||||
objectsPromise = undefined
|
||||
}
|
||||
|
||||
async function sort (statuses: Status[]): Promise<Status[]> {
|
||||
const categories = toIdMap(await client.findAll(core.class.StatusCategory, {}))
|
||||
statuses.sort((a, b) => {
|
||||
if (a.category !== undefined && b.category !== undefined && a.category !== b.category) {
|
||||
const aCat = categories.get(a.category)
|
||||
const bCat = categories.get(b.category)
|
||||
if (aCat !== undefined && bCat !== undefined) {
|
||||
return aCat.order - bCat.order
|
||||
}
|
||||
}
|
||||
if (_space != null) {
|
||||
const aIndex = _space.states.findIndex((s) => s === a._id)
|
||||
const bIndex = _space.states.findIndex((s) => s === b._id)
|
||||
return aIndex - bIndex
|
||||
}
|
||||
return a.name.localeCompare(b.name)
|
||||
})
|
||||
return statuses
|
||||
}
|
||||
|
||||
function isSelected (value: Doc | undefined | null, values: any[]): boolean {
|
||||
return values.includes(value?._id ?? value)
|
||||
}
|
||||
@ -182,7 +203,14 @@
|
||||
<div class="flex-row-center">
|
||||
{#if value}
|
||||
{#key value._id}
|
||||
<svelte:component this={attribute.presenter} {value} {...attribute.props} disabled oneLine />
|
||||
<svelte:component
|
||||
this={attribute.presenter}
|
||||
{value}
|
||||
{...attribute.props}
|
||||
{space}
|
||||
disabled
|
||||
oneLine
|
||||
/>
|
||||
{/key}
|
||||
{:else}
|
||||
<Label label={ui.string.NotSelected} />
|
||||
|
@ -71,7 +71,7 @@
|
||||
<SearchEdit bind:value={search} on:change={() => dispatch('search', search)} />
|
||||
<!-- <ActionIcon icon={IconMoreH} size={'small'} /> -->
|
||||
<div class="buttons-divider" />
|
||||
<FilterButton {_class} />
|
||||
<FilterButton {_class} space={spaceId} />
|
||||
</div>
|
||||
<div class="ac-header-full medium-gap">
|
||||
<ViewletSettingButton bind:viewOptions bind:viewlet />
|
||||
|
Loading…
Reference in New Issue
Block a user