mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 11:01:54 +03:00
UBER-408 Issue as task (#3497)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
d29a2df4d9
commit
ab02db5890
@ -26,6 +26,7 @@ const object: AttachedData<Issue> = {
|
||||
milestone: null,
|
||||
number: 0,
|
||||
rank: '',
|
||||
doneState: null,
|
||||
status: '' as Ref<IssueStatus>,
|
||||
priority: IssuePriority.NoPriority,
|
||||
dueDate: null,
|
||||
@ -86,6 +87,7 @@ async function genIssue (client: TxOperations, statuses: Ref<IssueStatus>[]): Pr
|
||||
component: object.component,
|
||||
milestone: object.milestone,
|
||||
number: (incResult as any).object.sequence,
|
||||
doneState: null,
|
||||
status: faker.random.arrayElement(statuses),
|
||||
priority: faker.random.arrayElement(Object.values(IssuePriority)) as IssuePriority,
|
||||
rank: calcRank(lastOne, undefined),
|
||||
|
@ -158,7 +158,7 @@ async function genApplicant (
|
||||
const applicant: AttachedData<Applicant> = {
|
||||
number: faker.datatype.number(),
|
||||
assignee: faker.random.arrayElement(emoloyeeIds),
|
||||
state: faker.random.arrayElement(states),
|
||||
status: faker.random.arrayElement(states),
|
||||
doneState: null,
|
||||
rank: rank as string,
|
||||
startDate: null,
|
||||
@ -201,7 +201,7 @@ async function genApplicant (
|
||||
recruit.class.Applicant,
|
||||
'applications',
|
||||
{
|
||||
state: faker.random.arrayElement(states)
|
||||
status: faker.random.arrayElement(states)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
@ -17,22 +17,20 @@
|
||||
import automation, { AutomationSupport } from '@hcengineering/automation'
|
||||
import { Board, boardId, Card, CardCover, CommonBoardPreference, MenuPage } from '@hcengineering/board'
|
||||
import type { Employee } from '@hcengineering/contact'
|
||||
import { Class, DOMAIN_MODEL, IndexKind, Markup, Ref, Type } from '@hcengineering/core'
|
||||
import { Class, DOMAIN_MODEL, IndexKind, Markup, Ref, Timestamp, Type } from '@hcengineering/core'
|
||||
import {
|
||||
ArrOf,
|
||||
Builder,
|
||||
Collection,
|
||||
Index,
|
||||
Model,
|
||||
Prop,
|
||||
TypeBoolean,
|
||||
TypeDate,
|
||||
TypeMarkup,
|
||||
TypeRef,
|
||||
TypeString,
|
||||
UX
|
||||
} from '@hcengineering/model'
|
||||
import attachment from '@hcengineering/model-attachment'
|
||||
import chunter from '@hcengineering/model-chunter'
|
||||
import contact from '@hcengineering/model-contact'
|
||||
import core, { TDoc, TType } from '@hcengineering/model-core'
|
||||
import preference, { TPreference } from '@hcengineering/model-preference'
|
||||
@ -90,12 +88,6 @@ export class TCard extends TTask implements Card {
|
||||
@Index(IndexKind.FullText)
|
||||
location?: string
|
||||
|
||||
@Prop(Collection(chunter.class.Comment), chunter.string.Comments)
|
||||
comments?: number
|
||||
|
||||
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files })
|
||||
attachments?: number
|
||||
|
||||
@Prop(TypeRef(contact.class.Employee), board.string.Assignee)
|
||||
declare assignee: Ref<Employee> | null
|
||||
|
||||
@ -104,6 +96,9 @@ export class TCard extends TTask implements Card {
|
||||
|
||||
@Prop(TypeCardCover(), board.string.Cover)
|
||||
cover?: CardCover
|
||||
|
||||
@Prop(TypeDate(), task.string.StartDate)
|
||||
startDate!: Timestamp | null
|
||||
}
|
||||
|
||||
@Model(board.class.MenuPage, core.class.Doc, DOMAIN_MODEL)
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
// To help typescript locate view plugin properly
|
||||
import type { Employee } from '@hcengineering/contact'
|
||||
import { FindOptions, IndexKind, Ref, SortingOrder } from '@hcengineering/core'
|
||||
import { FindOptions, IndexKind, Ref, SortingOrder, Timestamp } from '@hcengineering/core'
|
||||
import { Customer, Funnel, Lead, leadId } from '@hcengineering/lead'
|
||||
import {
|
||||
Builder,
|
||||
@ -25,6 +25,7 @@ import {
|
||||
Model,
|
||||
Prop,
|
||||
ReadOnly,
|
||||
TypeDate,
|
||||
TypeMarkup,
|
||||
TypeRef,
|
||||
TypeString,
|
||||
@ -69,16 +70,13 @@ export class TLead extends TTask implements Lead {
|
||||
@ReadOnly()
|
||||
declare attachedTo: Ref<Customer>
|
||||
|
||||
@Prop(TypeDate(), task.string.StartDate)
|
||||
startDate!: Timestamp | null
|
||||
|
||||
@Prop(TypeString(), lead.string.Title)
|
||||
@Index(IndexKind.FullText)
|
||||
title!: string
|
||||
|
||||
@Prop(Collection(chunter.class.Comment), chunter.string.Comments)
|
||||
comments?: number
|
||||
|
||||
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files })
|
||||
attachments?: number
|
||||
|
||||
@Prop(TypeRef(contact.class.Employee), lead.string.Assignee)
|
||||
declare assignee: Ref<Employee> | null
|
||||
}
|
||||
@ -247,7 +245,7 @@ export function createModel (builder: Builder): void {
|
||||
presenter: tracker.component.RelatedIssueSelector,
|
||||
label: tracker.string.Issues
|
||||
},
|
||||
'state',
|
||||
'status',
|
||||
'doneState',
|
||||
'attachments',
|
||||
'comments',
|
||||
@ -272,9 +270,9 @@ export function createModel (builder: Builder): void {
|
||||
)
|
||||
|
||||
const leadViewOptions: ViewOptionsModel = {
|
||||
groupBy: ['state', 'assignee'],
|
||||
groupBy: ['status', 'assignee'],
|
||||
orderBy: [
|
||||
['state', SortingOrder.Ascending],
|
||||
['status', SortingOrder.Ascending],
|
||||
['modifiedOn', SortingOrder.Descending],
|
||||
['createdOn', SortingOrder.Descending],
|
||||
['dueDate', SortingOrder.Ascending],
|
||||
@ -304,7 +302,7 @@ export function createModel (builder: Builder): void {
|
||||
config: [
|
||||
{ key: '', displayProps: { fixed: 'left', key: 'lead' } },
|
||||
{
|
||||
key: 'state',
|
||||
key: 'status',
|
||||
props: { kind: 'list', size: 'small', shouldShowName: false }
|
||||
},
|
||||
{
|
||||
@ -402,7 +400,7 @@ export function createModel (builder: Builder): void {
|
||||
lead.class.Lead,
|
||||
lead.ids.LeadNotificationGroup,
|
||||
[],
|
||||
['comments', 'state', 'doneState']
|
||||
['comments', 'status', 'doneState']
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
|
@ -55,6 +55,7 @@ import {
|
||||
recruitId
|
||||
} from '@hcengineering/recruit'
|
||||
import setting from '@hcengineering/setting'
|
||||
import { State } from '@hcengineering/task'
|
||||
import { KeyBinding, ViewOptionsModel } from '@hcengineering/view'
|
||||
import recruit from './plugin'
|
||||
import { createReviewModel, reviewTableConfig, reviewTableOptions } from './review'
|
||||
@ -158,14 +159,14 @@ export class TApplicant extends TTask implements Applicant {
|
||||
@Index(IndexKind.Indexed)
|
||||
declare space: Ref<Vacancy>
|
||||
|
||||
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files })
|
||||
attachments?: number
|
||||
|
||||
@Prop(Collection(chunter.class.Comment), chunter.string.Comments)
|
||||
comments?: number
|
||||
@Prop(TypeDate(), task.string.StartDate)
|
||||
startDate!: Timestamp | null
|
||||
|
||||
@Prop(TypeRef(contact.class.Employee), recruit.string.AssignedRecruiter)
|
||||
declare assignee: Ref<Employee> | null
|
||||
|
||||
@Prop(TypeRef(task.class.State), task.string.TaskState, { _id: task.attribute.State })
|
||||
declare status: Ref<State>
|
||||
}
|
||||
|
||||
@Model(recruit.class.ApplicantMatch, core.class.AttachedDoc, DOMAIN_TASK)
|
||||
@ -425,7 +426,7 @@ export function createModel (builder: Builder): void {
|
||||
{
|
||||
attachTo: recruit.class.Applicant,
|
||||
descriptor: view.viewlet.Table,
|
||||
config: ['', '$lookup.attachedTo', 'state', 'doneState', 'modifiedOn'],
|
||||
config: ['', '$lookup.attachedTo', 'status', 'doneState', 'modifiedOn'],
|
||||
configOptions: {
|
||||
sortable: true
|
||||
},
|
||||
@ -440,7 +441,7 @@ export function createModel (builder: Builder): void {
|
||||
{
|
||||
attachTo: recruit.class.Applicant,
|
||||
descriptor: view.viewlet.Table,
|
||||
config: ['', '$lookup.space.name', '$lookup.space.$lookup.company', 'state', 'comments', 'doneState'],
|
||||
config: ['', '$lookup.space.name', '$lookup.space.$lookup.company', 'status', 'comments', 'doneState'],
|
||||
configOptions: {
|
||||
sortable: true
|
||||
},
|
||||
@ -535,7 +536,7 @@ export function createModel (builder: Builder): void {
|
||||
presenter: tracker.component.RelatedIssueSelector,
|
||||
label: tracker.string.Issues
|
||||
},
|
||||
'state',
|
||||
'status',
|
||||
'doneState',
|
||||
'attachments',
|
||||
'comments',
|
||||
@ -583,7 +584,7 @@ export function createModel (builder: Builder): void {
|
||||
presenter: tracker.component.RelatedIssueSelector,
|
||||
label: tracker.string.Issues
|
||||
},
|
||||
'state',
|
||||
'status',
|
||||
'attachments',
|
||||
'comments',
|
||||
'modifiedOn',
|
||||
@ -651,9 +652,9 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
const applicantViewOptions = (colors: boolean): ViewOptionsModel => {
|
||||
const model: ViewOptionsModel = {
|
||||
groupBy: ['state', 'assignee', 'space', 'createdBy', 'modifiedBy'],
|
||||
groupBy: ['status', 'assignee', 'space', 'createdBy', 'modifiedBy'],
|
||||
orderBy: [
|
||||
['state', SortingOrder.Ascending],
|
||||
['status', SortingOrder.Ascending],
|
||||
['modifiedOn', SortingOrder.Descending],
|
||||
['createdOn', SortingOrder.Descending],
|
||||
['dueDate', SortingOrder.Ascending],
|
||||
@ -684,7 +685,7 @@ export function createModel (builder: Builder): void {
|
||||
config: [
|
||||
{ key: '', displayProps: { fixed: 'left', key: 'app' } },
|
||||
{
|
||||
key: 'state',
|
||||
key: 'status',
|
||||
props: { kind: 'list', size: 'small', shouldShowName: false }
|
||||
},
|
||||
{
|
||||
@ -778,7 +779,7 @@ export function createModel (builder: Builder): void {
|
||||
'',
|
||||
'space',
|
||||
'assignee',
|
||||
'state',
|
||||
'status',
|
||||
'attachments',
|
||||
'dueDate',
|
||||
'comments',
|
||||
@ -1125,7 +1126,7 @@ export function createModel (builder: Builder): void {
|
||||
action: view.actionImpl.ValueSelector,
|
||||
actionPopup: view.component.ValueSelector,
|
||||
actionProps: {
|
||||
attribute: 'state',
|
||||
attribute: 'status',
|
||||
_class: task.class.State,
|
||||
query: {},
|
||||
searchField: 'name',
|
||||
@ -1285,7 +1286,7 @@ export function createModel (builder: Builder): void {
|
||||
recruit.class.Applicant,
|
||||
recruit.ids.ApplicationNotificationGroup,
|
||||
[],
|
||||
['comments', 'state', 'doneState', 'dueDate']
|
||||
['comments', 'status', 'doneState', 'dueDate']
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
|
@ -15,6 +15,8 @@
|
||||
|
||||
import type { Employee } from '@hcengineering/contact'
|
||||
import contact from '@hcengineering/contact'
|
||||
import attachment from '@hcengineering/model-attachment'
|
||||
import chunter from '@hcengineering/model-chunter'
|
||||
import { Arr, Attribute, Class, Doc, Domain, IndexKind, Ref, Space, Status, Timestamp } from '@hcengineering/core'
|
||||
import {
|
||||
Builder,
|
||||
@ -88,8 +90,8 @@ export class TLostState extends TDoneState implements LostState {}
|
||||
@Model(task.class.Task, core.class.AttachedDoc, DOMAIN_TASK)
|
||||
@UX(task.string.Task, task.icon.Task, task.string.Task)
|
||||
export class TTask extends TAttachedDoc implements Task {
|
||||
@Prop(TypeRef(task.class.State), task.string.TaskState, { _id: task.attribute.State })
|
||||
state!: Ref<State>
|
||||
@Prop(TypeRef(core.class.Status), task.string.TaskState, { _id: task.attribute.State })
|
||||
status!: Ref<Status>
|
||||
|
||||
@Prop(TypeRef(task.class.DoneState), task.string.TaskStateDone, { _id: task.attribute.DoneState })
|
||||
doneState!: Ref<DoneState> | null
|
||||
@ -105,13 +107,16 @@ export class TTask extends TAttachedDoc implements Task {
|
||||
@Prop(TypeDate(), task.string.DueDate, { editor: task.component.DueDateEditor })
|
||||
dueDate!: Timestamp | null
|
||||
|
||||
@Prop(TypeDate(), task.string.StartDate)
|
||||
startDate!: Timestamp | null
|
||||
|
||||
declare rank: string
|
||||
|
||||
@Prop(Collection(tags.class.TagReference, task.string.TaskLabels), task.string.TaskLabels)
|
||||
labels!: number
|
||||
labels?: number
|
||||
|
||||
@Prop(Collection(chunter.class.Comment), chunter.string.Comments)
|
||||
comments?: number
|
||||
|
||||
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files })
|
||||
attachments?: number
|
||||
}
|
||||
|
||||
@Model(task.class.TodoItem, core.class.AttachedDoc, DOMAIN_TASK)
|
||||
|
@ -13,11 +13,13 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Class, Doc, Domain, Ref, Space, TxOperations } from '@hcengineering/core'
|
||||
import { Class, DOMAIN_TX, Doc, Domain, Ref, Space, TxOperations } from '@hcengineering/core'
|
||||
import { MigrateOperation, MigrationClient, MigrationUpgradeClient, createOrUpdate } from '@hcengineering/model'
|
||||
import core from '@hcengineering/model-core'
|
||||
import tags from '@hcengineering/model-tags'
|
||||
import { DoneStateTemplate, KanbanTemplate, StateTemplate, genRanks } from '@hcengineering/task'
|
||||
import view, { Filter } from '@hcengineering/view'
|
||||
import { DOMAIN_TASK } from '.'
|
||||
import task from './plugin'
|
||||
|
||||
/**
|
||||
@ -125,8 +127,72 @@ async function createDefaults (tx: TxOperations): Promise<void> {
|
||||
await createDefaultSequence(tx)
|
||||
}
|
||||
|
||||
async function renameState (client: MigrationClient): Promise<void> {
|
||||
const toUpdate = await client.find(DOMAIN_TASK, { state: { $exists: true } })
|
||||
if (toUpdate.length > 0) {
|
||||
for (const doc of toUpdate) {
|
||||
await client.update(
|
||||
DOMAIN_TX,
|
||||
{ objectId: doc._id },
|
||||
{ $rename: { 'attributes.state': 'attributes.status', 'operations.state': 'operations.status' } }
|
||||
)
|
||||
await client.update(
|
||||
DOMAIN_TX,
|
||||
{ 'tx.objectId': doc._id },
|
||||
{ $rename: { 'tx.attributes.state': 'tx.attributes.status', 'tx.operations.state': 'tx.operations.status' } }
|
||||
)
|
||||
}
|
||||
await client.update(DOMAIN_TASK, { _id: { $in: toUpdate.map((p) => p._id) } }, { $rename: { state: 'status' } })
|
||||
}
|
||||
}
|
||||
|
||||
async function renameStatePrefs (client: MigrationUpgradeClient): Promise<void> {
|
||||
const txop = new TxOperations(client, core.account.System)
|
||||
const prefs = await client.findAll(view.class.ViewletPreference, {})
|
||||
for (const pref of prefs) {
|
||||
let update = false
|
||||
const config = pref.config
|
||||
for (let index = 0; index < config.length; index++) {
|
||||
const conf = config[index]
|
||||
if (typeof conf === 'string') {
|
||||
if (conf === 'state') {
|
||||
config[index] = 'status'
|
||||
update = true
|
||||
} else if (conf === '$lookup.state') {
|
||||
config[index] = '$lookup.status'
|
||||
update = true
|
||||
}
|
||||
} else if (conf.key === 'state') {
|
||||
conf.key = 'status'
|
||||
update = true
|
||||
}
|
||||
}
|
||||
if (update) {
|
||||
await txop.update(pref, {
|
||||
config
|
||||
})
|
||||
}
|
||||
}
|
||||
const res = await client.findAll(view.class.FilteredView, { filters: /"key":"state"/ as any })
|
||||
if (res.length > 0) {
|
||||
for (const doc of res) {
|
||||
const filters = JSON.parse(doc.filters) as Filter[]
|
||||
for (const filter of filters) {
|
||||
if (filter.key.key === 'state') {
|
||||
filter.key.key = 'status'
|
||||
}
|
||||
}
|
||||
await txop.update(doc, {
|
||||
filters: JSON.stringify(filters)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const taskOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {},
|
||||
async migrate (client: MigrationClient): Promise<void> {
|
||||
await renameState(client)
|
||||
},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
await createDefaults(tx)
|
||||
@ -144,5 +210,6 @@ export const taskOperation: MigrateOperation = {
|
||||
},
|
||||
task.category.TaskTag
|
||||
)
|
||||
await renameStatePrefs(client)
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@
|
||||
"@hcengineering/model-notification": "^0.6.0",
|
||||
"@hcengineering/tracker": "^0.6.10",
|
||||
"@hcengineering/tracker-resources": "^0.6.0",
|
||||
"@hcengineering/model-task": "^0.6.0",
|
||||
"@hcengineering/model-chunter": "^0.6.0",
|
||||
"@hcengineering/workbench": "^0.6.8",
|
||||
"@hcengineering/view": "^0.6.8",
|
||||
|
@ -46,6 +46,7 @@ import {
|
||||
} from '@hcengineering/model'
|
||||
import attachment from '@hcengineering/model-attachment'
|
||||
import chunter from '@hcengineering/model-chunter'
|
||||
import { TTask } from '@hcengineering/model-task'
|
||||
import core, { DOMAIN_SPACE, TAttachedDoc, TDoc, TSpace, TStatus, TType } from '@hcengineering/model-core'
|
||||
import view, { actionTemplates, classPresenter, createAction, showColorsViewOption } from '@hcengineering/model-view'
|
||||
import workbench, { createNavigateAction } from '@hcengineering/model-workbench'
|
||||
@ -53,7 +54,7 @@ import notification from '@hcengineering/notification'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import setting from '@hcengineering/setting'
|
||||
import tags, { TagElement } from '@hcengineering/tags'
|
||||
import task from '@hcengineering/task'
|
||||
import task, { DoneState } from '@hcengineering/task'
|
||||
import {
|
||||
Component,
|
||||
Issue,
|
||||
@ -150,9 +151,9 @@ export function TypeReportedTime (): Type<number> {
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@Model(tracker.class.Issue, core.class.AttachedDoc, DOMAIN_TRACKER)
|
||||
@Model(tracker.class.Issue, task.class.Task)
|
||||
@UX(tracker.string.Issue, tracker.icon.Issue, 'TSK', 'title')
|
||||
export class TIssue extends TAttachedDoc implements Issue {
|
||||
export class TIssue extends TTask implements Issue {
|
||||
@Prop(TypeRef(tracker.class.Issue), tracker.string.Parent)
|
||||
declare attachedTo: Ref<Issue>
|
||||
|
||||
@ -202,14 +203,12 @@ export class TIssue extends TAttachedDoc implements Issue {
|
||||
|
||||
parents!: IssueParentInfo[]
|
||||
|
||||
@Prop(Collection(chunter.class.Comment), tracker.string.Comments, { icon: chunter.icon.Chunter })
|
||||
comments!: number
|
||||
|
||||
@Prop(Collection(attachment.class.Attachment), tracker.string.Attachments, { icon: attachment.icon.Attachment })
|
||||
attachments!: number
|
||||
|
||||
@Prop(Collection(tags.class.TagReference), tracker.string.Labels)
|
||||
labels?: number
|
||||
declare labels: number
|
||||
|
||||
@Prop(TypeRef(task.class.DoneState), task.string.TaskStateDone, { _id: task.attribute.DoneState })
|
||||
@Hidden()
|
||||
declare doneState: Ref<DoneState> | null
|
||||
|
||||
@Prop(TypeRef(tracker.class.Project), tracker.string.Project, { icon: tracker.icon.Issues })
|
||||
@Index(IndexKind.Indexed)
|
||||
|
@ -18,6 +18,8 @@ import { MigrateOperation, MigrationClient, MigrationUpgradeClient, createOrUpda
|
||||
import tags from '@hcengineering/tags'
|
||||
import { IssueStatus, Project, TimeReportDayType, createStatuses } from '@hcengineering/tracker'
|
||||
import tracker from './plugin'
|
||||
import { DOMAIN_TRACKER } from '.'
|
||||
import { DOMAIN_TASK } from '@hcengineering/model-task'
|
||||
|
||||
async function createDefaultProject (tx: TxOperations): Promise<void> {
|
||||
const current = await tx.findOne(tracker.class.Project, {
|
||||
@ -86,8 +88,17 @@ async function fixProjectIcons (tx: TxOperations): Promise<void> {
|
||||
await Promise.all(promises)
|
||||
}
|
||||
|
||||
async function moveIssues (client: MigrationClient): Promise<void> {
|
||||
const docs = await client.find(DOMAIN_TRACKER, { _class: tracker.class.Issue })
|
||||
if (docs.length > 0) {
|
||||
await client.move(DOMAIN_TRACKER, { _class: tracker.class.Issue }, DOMAIN_TASK)
|
||||
}
|
||||
}
|
||||
|
||||
export const trackerOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {},
|
||||
async migrate (client: MigrationClient): Promise<void> {
|
||||
await moveIssues(client)
|
||||
},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
await createDefaults(tx)
|
||||
|
@ -62,7 +62,7 @@ export async function createApplication (
|
||||
|
||||
await client.addCollection(recruit.class.Applicant, _space, doc._id, recruit.mixin.Candidate, 'applications', {
|
||||
...data,
|
||||
state: state._id,
|
||||
status: state._id,
|
||||
number: (incResult as any).object.sequence,
|
||||
rank: calcRank(lastOne, undefined)
|
||||
})
|
||||
|
@ -517,8 +517,8 @@ export async function convert (
|
||||
}
|
||||
|
||||
if (existing !== undefined) {
|
||||
if (existing.state !== state?._id) {
|
||||
update.state = state._id
|
||||
if (existing.status !== state?._id) {
|
||||
update.status = state._id
|
||||
}
|
||||
if (Object.keys(update).length > 0) {
|
||||
await ops.update(existing, update)
|
||||
|
@ -52,7 +52,7 @@
|
||||
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
|
||||
|
||||
const value: AttachedData<BoardCard> = {
|
||||
state: state._id,
|
||||
status: state._id,
|
||||
doneState: null,
|
||||
number: (incResult as any).object.sequence,
|
||||
title,
|
||||
|
@ -63,7 +63,7 @@
|
||||
let checklists: TodoItem[] = []
|
||||
const mixins: Mixin<Doc>[] = []
|
||||
const allowedCollections = ['labels']
|
||||
const ignoreKeys = ['isArchived', 'location', 'title', 'description', 'state', 'number', 'assignee', 'doneState']
|
||||
const ignoreKeys = ['isArchived', 'location', 'title', 'description', 'status', 'number', 'assignee', 'doneState']
|
||||
|
||||
function change (field: string, value: any) {
|
||||
if (object) {
|
||||
@ -79,8 +79,8 @@
|
||||
object = result[0]
|
||||
})
|
||||
|
||||
$: object?.state &&
|
||||
stateQuery.query(task.class.State, { _id: object.state }, (result) => {
|
||||
$: object?.status &&
|
||||
stateQuery.query(task.class.State, { _id: object.status }, (result) => {
|
||||
state = result[0]
|
||||
})
|
||||
|
||||
@ -128,7 +128,7 @@
|
||||
<div class="flex fs-title flex-gap-1">
|
||||
<span class="over-underline" on:click={handleMove}>{space?.name}</span>><span
|
||||
class="over-underline"
|
||||
on:click={handleMove}>{state?.title}</span
|
||||
on:click={handleMove}>{state?.name}</span
|
||||
>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
|
@ -125,7 +125,7 @@
|
||||
}
|
||||
)
|
||||
$: listProvider.update(cards)
|
||||
$: groupByDocs = groupBy(cards, 'state')
|
||||
$: groupByDocs = groupBy(cards, 'status')
|
||||
|
||||
const getUpdateProps = (doc: Doc, category: CategoryType): DocumentUpdate<DocWithRank> | undefined => {
|
||||
const groupValue =
|
||||
|
@ -23,7 +23,7 @@
|
||||
{_class}
|
||||
config={[
|
||||
'title',
|
||||
'state',
|
||||
'status',
|
||||
{
|
||||
key: '',
|
||||
presenter: tags.component.TagsPresenter,
|
||||
@ -40,5 +40,5 @@
|
||||
'modifiedOn'
|
||||
]}
|
||||
{options}
|
||||
query={{ isArchived, state: { $in: states } }}
|
||||
query={{ isArchived, status: { $in: states } }}
|
||||
/>
|
||||
|
@ -40,7 +40,7 @@
|
||||
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
|
||||
|
||||
const value: AttachedData<BoardCard> = {
|
||||
state: state._id,
|
||||
status: state._id,
|
||||
doneState: null,
|
||||
number: (incResult as any).object.sequence,
|
||||
title,
|
||||
|
@ -24,7 +24,7 @@
|
||||
let status: Status = OK
|
||||
const selected = {
|
||||
space: value.space,
|
||||
state: value.state,
|
||||
status: value.status,
|
||||
rank: value.rank
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
|
||||
|
||||
const copy: AttachedData<Card> = {
|
||||
state: selected.state,
|
||||
status: selected.status,
|
||||
doneState: null,
|
||||
number: (incResult as any).object.sequence,
|
||||
title,
|
||||
@ -119,18 +119,18 @@
|
||||
<Label label={board.string.List} />
|
||||
</div>
|
||||
{#key selected.space}
|
||||
<StateSelect label={board.string.List} object={value} space={selected.space} bind:selected={selected.state} />
|
||||
<StateSelect label={board.string.List} object={value} space={selected.space} bind:selected={selected.status} />
|
||||
{/key}
|
||||
</div>
|
||||
<div class="w-full flex ml-2">
|
||||
<div style:flex-basis="10%" class="text-md">
|
||||
<Label label={board.string.Position} />
|
||||
</div>
|
||||
{#key selected.state}
|
||||
{#key selected.status}
|
||||
<RankSelect
|
||||
label={board.string.Position}
|
||||
object={value}
|
||||
state={selected.state}
|
||||
state={selected.status}
|
||||
bind:selected={selected.rank}
|
||||
isCopying={true}
|
||||
/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
let status: Status = OK
|
||||
const selected = {
|
||||
space: value.space,
|
||||
state: value.state,
|
||||
status: value.status,
|
||||
rank: value.rank
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
update.space = selected.space
|
||||
}
|
||||
|
||||
if (selected.state !== value.state) update.state = selected.state
|
||||
if (selected.status !== value.status) update.status = selected.status
|
||||
if (selected.rank !== value.rank) update.rank = selected.rank
|
||||
client.update(value, update)
|
||||
dispatch('close')
|
||||
@ -60,7 +60,7 @@
|
||||
|
||||
<Popup
|
||||
label={board.string.MoveCard}
|
||||
canSave={status === OK && (value.state !== selected.state || value.rank !== selected.rank)}
|
||||
canSave={status === OK && (value.status !== selected.status || value.rank !== selected.rank)}
|
||||
okAction={move}
|
||||
okLabel={board.string.Move}
|
||||
on:close={() => {
|
||||
@ -82,15 +82,15 @@
|
||||
<Label label={board.string.List} />
|
||||
</div>
|
||||
{#key selected.space}
|
||||
<StateSelect label={board.string.List} object={value} space={selected.space} bind:selected={selected.state} />
|
||||
<StateSelect label={board.string.List} object={value} space={selected.space} bind:selected={selected.status} />
|
||||
{/key}
|
||||
</div>
|
||||
<div class="w-full flex ml-2">
|
||||
<div style:flex-basis="10%" class="text-md">
|
||||
<Label label={board.string.Position} />
|
||||
</div>
|
||||
{#key selected.state}
|
||||
<RankSelect label={board.string.Position} object={value} state={selected.state} bind:selected={selected.rank} />
|
||||
{#key selected.status}
|
||||
<RankSelect label={board.string.Position} object={value} state={selected.status} bind:selected={selected.rank} />
|
||||
{/key}
|
||||
</div>
|
||||
</Popup>
|
||||
|
@ -17,7 +17,7 @@
|
||||
const tasksQuery = createQuery()
|
||||
tasksQuery.query(
|
||||
board.class.Card,
|
||||
{ state, isArchived: { $nin: [true] } },
|
||||
{ status: state, isArchived: { $nin: [true] } },
|
||||
async (result) => {
|
||||
const filteredResult = isCopying ? result : result.filter((t) => t._id !== object._id)
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
let selectedRank = ranks.slice(-1)[0].id
|
||||
|
||||
if (object.state === state) {
|
||||
if (object.status === state) {
|
||||
const index = result.findIndex((t) => t._id === object._id)
|
||||
|
||||
if (index !== -1) {
|
||||
|
@ -19,16 +19,16 @@
|
||||
{ space, isArchived: { $nin: [true] } },
|
||||
async (result) => {
|
||||
if (!result) return
|
||||
states = result.map(({ _id, title }) => ({ id: _id, label: title }))
|
||||
states = result.map(({ _id, name }) => ({ id: _id, label: name }))
|
||||
;[{ _id: selected }] = result
|
||||
if (object.space === space) {
|
||||
const index = states.findIndex(({ id }) => id === object.state)
|
||||
const index = states.findIndex(({ id }) => id === object.status)
|
||||
states[index].label = await translate(
|
||||
board.string.Current,
|
||||
{ label: states[index].label },
|
||||
$themeStore.language
|
||||
)
|
||||
selected = object.state
|
||||
selected = object.status
|
||||
}
|
||||
},
|
||||
{ sort: { rank: SortingOrder.Ascending } }
|
||||
|
@ -44,7 +44,7 @@ async function ConvertToCard (object: TodoItem): Promise<void> {
|
||||
const client = getClient()
|
||||
const todoItemCard = await getCardFromTodoItem(client, object)
|
||||
if (todoItemCard === undefined) return
|
||||
await createCard(client, todoItemCard.space, todoItemCard.state, {
|
||||
await createCard(client, todoItemCard.space, todoItemCard.status, {
|
||||
title: object.name,
|
||||
assignee: object.assignee,
|
||||
dueDate: object.dueTo
|
||||
|
@ -16,7 +16,7 @@ import board from '../plugin'
|
||||
export async function createCard (
|
||||
client: Client,
|
||||
space: Ref<Space>,
|
||||
state: Ref<State>,
|
||||
status: Ref<State>,
|
||||
attribues: Partial<AttachedData<Card>>
|
||||
): Promise<Ref<Card>> {
|
||||
const sequence = await client.findOne(task.class.Sequence, { attachedTo: board.class.Card })
|
||||
@ -29,7 +29,7 @@ export async function createCard (
|
||||
|
||||
const value: AttachedData<Card> = {
|
||||
title: '',
|
||||
state,
|
||||
status,
|
||||
doneState: null,
|
||||
startDate: null,
|
||||
dueDate: null,
|
||||
|
@ -15,11 +15,11 @@
|
||||
//
|
||||
|
||||
import { Employee } from '@hcengineering/contact'
|
||||
import type { Class, Doc, Markup, Ref, Type } from '@hcengineering/core'
|
||||
import type { 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'
|
||||
import type { DoneState, KanbanTemplateSpace, SpaceWithStates, Task } from '@hcengineering/task'
|
||||
import type { DoneState, KanbanTemplateSpace, SpaceWithStates, State, Task } from '@hcengineering/task'
|
||||
import type { AnyComponent } from '@hcengineering/ui'
|
||||
import { Action, ActionCategory } from '@hcengineering/view'
|
||||
import { TagCategory } from '@hcengineering/tags'
|
||||
@ -63,9 +63,8 @@ export interface Card extends Task {
|
||||
location?: string
|
||||
|
||||
cover?: CardCover | null
|
||||
|
||||
comments?: number
|
||||
attachments?: number
|
||||
status: Ref<State>
|
||||
startDate: Timestamp | null
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,7 +67,7 @@
|
||||
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
|
||||
|
||||
const value: AttachedData<Lead> = {
|
||||
state: state._id,
|
||||
status: state._id,
|
||||
doneState: null,
|
||||
number: (incResult as any).object.sequence,
|
||||
title,
|
||||
|
@ -42,7 +42,7 @@
|
||||
<Scroller horizontal>
|
||||
<Table
|
||||
_class={lead.class.Lead}
|
||||
config={['', 'state', 'doneState']}
|
||||
config={['', 'status', 'doneState']}
|
||||
query={{ attachedTo: objectId }}
|
||||
{loadingProps}
|
||||
/>
|
||||
@ -50,7 +50,7 @@
|
||||
{:else}
|
||||
<Table
|
||||
_class={lead.class.Lead}
|
||||
config={['', 'state', 'doneState']}
|
||||
config={['', 'status', 'doneState']}
|
||||
query={{ attachedTo: objectId }}
|
||||
{loadingProps}
|
||||
/>
|
||||
|
@ -21,4 +21,4 @@
|
||||
export let value: Customer
|
||||
</script>
|
||||
|
||||
<Table _class={leads.class.Lead} config={['', 'state', 'doneState']} query={{ attachedTo: value._id }} />
|
||||
<Table _class={leads.class.Lead} config={['', 'status', 'doneState']} query={{ attachedTo: value._id }} />
|
||||
|
@ -15,11 +15,11 @@
|
||||
//
|
||||
|
||||
import type { Contact } from '@hcengineering/contact'
|
||||
import type { Class, Doc, Ref } from '@hcengineering/core'
|
||||
import type { Class, Doc, Ref, Timestamp } from '@hcengineering/core'
|
||||
import { Mixin } from '@hcengineering/core'
|
||||
import type { Asset, Plugin } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import type { KanbanTemplateSpace, SpaceWithStates, Task } from '@hcengineering/task'
|
||||
import type { KanbanTemplateSpace, SpaceWithStates, State, Task } from '@hcengineering/task'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -44,11 +44,9 @@ export interface Customer extends Contact {
|
||||
*/
|
||||
export interface Lead extends Task {
|
||||
attachedTo: Ref<Customer>
|
||||
|
||||
status: Ref<State>
|
||||
startDate: Timestamp | null
|
||||
title: string
|
||||
|
||||
comments?: number
|
||||
attachments?: number
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,7 +33,7 @@
|
||||
<div class="popup-table">
|
||||
<Table
|
||||
_class={recruit.class.Applicant}
|
||||
config={['', '$lookup.space.name', '$lookup.space.company', 'state', 'doneState']}
|
||||
config={['', '$lookup.space.name', '$lookup.space.company', 'status', 'doneState']}
|
||||
query={{ attachedTo: value._id }}
|
||||
loadingProps={{ length: value.applications ?? 0 }}
|
||||
/>
|
||||
|
@ -78,7 +78,7 @@
|
||||
$: _candidate = candidate
|
||||
|
||||
const doc: Applicant = {
|
||||
state: '' as Ref<State>,
|
||||
status: '' as Ref<State>,
|
||||
doneState: null,
|
||||
number: 0,
|
||||
assignee,
|
||||
@ -142,7 +142,7 @@
|
||||
'applications',
|
||||
{
|
||||
...doc,
|
||||
state: state._id,
|
||||
status: state._id,
|
||||
doneState: null,
|
||||
number: (incResult as any).object.sequence,
|
||||
assignee: doc.assignee,
|
||||
|
@ -89,14 +89,14 @@
|
||||
</div>
|
||||
{/if}
|
||||
<div class="card-labels mb-2">
|
||||
{#if groupByKey !== 'state' && enabledConfig(config, 'state')}
|
||||
{#if groupByKey !== 'status' && enabledConfig(config, 'status')}
|
||||
<StateRefPresenter
|
||||
size={'small'}
|
||||
kind={'link-bordered'}
|
||||
shrink={1}
|
||||
value={object.state}
|
||||
onChange={(state) => {
|
||||
client.update(object, { state })
|
||||
value={object.status}
|
||||
onChange={(status) => {
|
||||
client.update(object, { status })
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
@ -69,7 +69,7 @@
|
||||
const op = client.apply('application.states')
|
||||
|
||||
for (const a of selected) {
|
||||
await moveToSpace(op, a, _space, { state: state._id, doneState: null })
|
||||
await moveToSpace(op, a, _space, { status: state._id, doneState: null })
|
||||
}
|
||||
await op.commit()
|
||||
loading = false
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
const options: FindOptions<Applicant> = {
|
||||
lookup: {
|
||||
state: task.class.State,
|
||||
status: task.class.State,
|
||||
space: core.class.Space,
|
||||
doneState: task.class.DoneState,
|
||||
attachedTo: recruit.mixin.Candidate
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
const options: FindOptions<Applicant> = {
|
||||
lookup: {
|
||||
state: task.class.State,
|
||||
status: task.class.State,
|
||||
space: core.class.Space,
|
||||
doneState: task.class.DoneState,
|
||||
attachedTo: recruit.mixin.Candidate
|
||||
@ -35,7 +35,7 @@
|
||||
<div class="popup-table">
|
||||
<Table
|
||||
_class={recruit.class.Applicant}
|
||||
config={['', 'attachedTo', 'state', 'doneState', 'modifiedOn']}
|
||||
config={['', 'attachedTo', 'status', 'doneState', 'modifiedOn']}
|
||||
{options}
|
||||
query={{ ...(resultQuery ?? {}), space: { $in: value } }}
|
||||
loadingProps={{ length: 0 }}
|
||||
|
@ -19,7 +19,7 @@ import type { AttachedData, AttachedDoc, Class, Doc, Mixin, Ref, Space, Timestam
|
||||
import type { Asset, Plugin, Resource } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import { TagReference } from '@hcengineering/tags'
|
||||
import type { KanbanTemplateSpace, SpaceWithStates, Task } from '@hcengineering/task'
|
||||
import type { KanbanTemplateSpace, SpaceWithStates, State, Task } from '@hcengineering/task'
|
||||
import { AnyComponent, ResolvedLocation } from '@hcengineering/ui'
|
||||
|
||||
/**
|
||||
@ -87,8 +87,8 @@ export interface CandidateDraft {
|
||||
export interface Applicant extends Task {
|
||||
space: Ref<Vacancy>
|
||||
attachedTo: Ref<Candidate>
|
||||
attachments?: number
|
||||
comments?: number
|
||||
status: Ref<State>
|
||||
startDate: Timestamp | null
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,7 +117,7 @@
|
||||
})
|
||||
)
|
||||
for (const value of result) {
|
||||
const group = template.get(value.state)
|
||||
const group = template.get(value.status)
|
||||
if (group === undefined) continue
|
||||
if (value.doneState === null) {
|
||||
group.values[0].value++
|
||||
@ -127,13 +127,13 @@
|
||||
const index = won ? 1 : 2
|
||||
group.values[index].value++
|
||||
}
|
||||
template.set(value.state, group)
|
||||
template.set(value.status, group)
|
||||
}
|
||||
items = Array.from(template.values())
|
||||
},
|
||||
{
|
||||
projection: {
|
||||
state: 1,
|
||||
status: 1,
|
||||
doneState: 1
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@
|
||||
|
||||
function updateConfig (config: string[]): string[] {
|
||||
if (state !== undefined) {
|
||||
return config.filter((p) => p !== 'state')
|
||||
return config.filter((p) => p !== 'status')
|
||||
}
|
||||
if (selectedDoneStates.size === 1) {
|
||||
return config.filter((p) => p !== 'doneState')
|
||||
@ -85,7 +85,7 @@
|
||||
resConfig = updateConfig(config)
|
||||
const result = client.getHierarchy().clone(query)
|
||||
if (state) {
|
||||
result.state = state
|
||||
result.status = state
|
||||
}
|
||||
if (selectedDoneStates.size > 0) {
|
||||
result.doneState = {
|
||||
|
@ -55,7 +55,7 @@
|
||||
return contact.class.Employee
|
||||
}
|
||||
|
||||
const taskKeys = ['state', 'assignee', 'doneState']
|
||||
const taskKeys = ['status', 'assignee', 'doneState']
|
||||
|
||||
$: filtredKeys = keys.filter((p) => !taskKeys.includes(p.key)) // todo
|
||||
</script>
|
||||
@ -76,7 +76,7 @@
|
||||
<AttributesBar {object} _class={object._class} keys={filtredKeys} />
|
||||
</div>
|
||||
</div>
|
||||
<AttributesBar {object} _class={object._class} keys={['doneState', 'state']} showHeader={false} />
|
||||
<AttributesBar {object} _class={object._class} keys={['doneState', 'status']} showHeader={false} />
|
||||
</div>
|
||||
{:else}
|
||||
<DocAttributeBar {object} {ignoreKeys} {mixins} {allowedCollections} on:update />
|
||||
|
@ -145,7 +145,7 @@
|
||||
lookup: {
|
||||
...options?.lookup,
|
||||
space: task.class.SpaceWithStates,
|
||||
state: task.class.State,
|
||||
status: task.class.State,
|
||||
doneState: task.class.DoneState
|
||||
},
|
||||
sort: {
|
||||
|
@ -63,7 +63,7 @@
|
||||
if (hierarchy.isDerived(state._class, task.class.DoneState)) {
|
||||
query = { doneState: state._id }
|
||||
} else {
|
||||
query = { state: state._id }
|
||||
query = { status: state._id }
|
||||
}
|
||||
|
||||
const objectsInThisState = await client.findAll(containingClass, query)
|
||||
|
@ -79,12 +79,13 @@ export interface LostState extends DoneState {}
|
||||
* @public
|
||||
*/
|
||||
export interface Task extends AttachedDoc, DocWithRank {
|
||||
state: Ref<State>
|
||||
status: Ref<Status>
|
||||
doneState: Ref<DoneState> | null
|
||||
number: number
|
||||
assignee: Ref<Employee> | null
|
||||
dueDate: Timestamp | null
|
||||
startDate: Timestamp | null
|
||||
comments?: number
|
||||
attachments?: number
|
||||
todoItems?: number
|
||||
labels?: number
|
||||
}
|
||||
|
@ -359,6 +359,7 @@
|
||||
)
|
||||
|
||||
const value: AttachedData<Issue> = {
|
||||
doneState: null,
|
||||
title: getTitle(object.title),
|
||||
description: object.description,
|
||||
assignee: object.assignee,
|
||||
|
@ -77,6 +77,7 @@
|
||||
)
|
||||
const childId = subIssue._id
|
||||
const cvalue: AttachedData<Issue> = {
|
||||
doneState: null,
|
||||
title: subIssue.title.trim(),
|
||||
description: subIssue.description,
|
||||
assignee: subIssue.assignee,
|
||||
|
@ -33,6 +33,7 @@ import {
|
||||
} from '@hcengineering/core'
|
||||
import { Asset, IntlString, Plugin, Resource, plugin } from '@hcengineering/platform'
|
||||
import { TagCategory, TagElement, TagReference } from '@hcengineering/tags'
|
||||
import { Task } from '@hcengineering/task'
|
||||
import { AnyComponent, Location, ResolvedLocation } from '@hcengineering/ui'
|
||||
import { Action, ActionCategory, IconProps } from '@hcengineering/view'
|
||||
|
||||
@ -133,15 +134,13 @@ export interface Milestone extends Doc {
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface Issue extends AttachedDoc {
|
||||
export interface Issue extends Task {
|
||||
attachedTo: Ref<Issue>
|
||||
title: string
|
||||
description: Markup
|
||||
status: Ref<IssueStatus>
|
||||
priority: IssuePriority
|
||||
|
||||
number: number
|
||||
assignee: Ref<Employee> | null
|
||||
component: Ref<Component> | null
|
||||
|
||||
// For subtasks
|
||||
@ -150,16 +149,8 @@ export interface Issue extends AttachedDoc {
|
||||
relations?: RelatedDocument[]
|
||||
parents: IssueParentInfo[]
|
||||
|
||||
comments: number
|
||||
attachments?: number
|
||||
labels?: number
|
||||
|
||||
space: Ref<Project>
|
||||
|
||||
dueDate: Timestamp | null
|
||||
|
||||
rank: string
|
||||
|
||||
milestone?: Ref<Milestone> | null
|
||||
|
||||
// Estimation in man days
|
||||
|
@ -14,37 +14,8 @@
|
||||
//
|
||||
|
||||
import core, { ApplyOperations, SortingOrder, Status, TxOperations, generateId } from '@hcengineering/core'
|
||||
import { LexoRank, LexoDecimal, LexoNumeralSystem36 } from 'lexorank'
|
||||
import LexoRankBucket from 'lexorank/lib/lexoRank/lexoRankBucket'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const genRanks = (count: number): Generator<string, void, unknown> =>
|
||||
(function * () {
|
||||
const sys = new LexoNumeralSystem36()
|
||||
const base = 36
|
||||
const max = base ** 6
|
||||
const gap = LexoDecimal.parse(Math.trunc(max / (count + 2)).toString(base), sys)
|
||||
let cur = LexoDecimal.parse('0', sys)
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
cur = cur.add(gap)
|
||||
yield new LexoRank(LexoRankBucket.BUCKET_0, cur).toString()
|
||||
}
|
||||
})()
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const calcRank = (prev?: { rank: string }, next?: { rank: string }): string => {
|
||||
const a = prev?.rank !== undefined ? LexoRank.parse(prev.rank) : LexoRank.min()
|
||||
const b = next?.rank !== undefined ? LexoRank.parse(next.rank) : LexoRank.max()
|
||||
if (a.equals(b)) {
|
||||
return a.genNext().toString()
|
||||
}
|
||||
return a.between(b).toString()
|
||||
}
|
||||
import { genRanks } from '@hcengineering/task'
|
||||
export { calcRank, genRanks } from '@hcengineering/task'
|
||||
|
||||
/**
|
||||
* Generates statuses for provided space.
|
||||
|
@ -50,13 +50,13 @@
|
||||
async function move (doc: Doc): Promise<void> {
|
||||
const needStates = currentSpace ? hierarchy.isDerived(currentSpace._class, task.class.SpaceWithStates) : false
|
||||
if (needStates) {
|
||||
const state = await client.findOne(task.class.State, { space: doc.space })
|
||||
if (state === undefined) {
|
||||
throw new Error('Move: state not found')
|
||||
const status = await client.findOne(task.class.State, { space: doc.space })
|
||||
if (status === undefined) {
|
||||
throw new Error('Move: status not found')
|
||||
}
|
||||
const lastOne = await client.findOne((doc as Task)._class, {}, { sort: { rank: SortingOrder.Descending } })
|
||||
await moveToSpace(client, doc, space, {
|
||||
state: state._id,
|
||||
status: status._id,
|
||||
rank: calcRank(lastOne, undefined)
|
||||
})
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user