feat: auto generate rank in middleware (#10577)

Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
Alexander Onnikov
2026-03-02 19:18:11 +07:00
committed by GitHub
parent 38b97b6840
commit 58295e4169
26 changed files with 172 additions and 81 deletions
+4 -1
View File
@@ -5029,6 +5029,9 @@ importers:
'@hcengineering/query':
specifier: workspace:^0.7.17
version: link:../../../core/packages/query
'@hcengineering/rank':
specifier: workspace:^0.7.17
version: link:../../../core/packages/rank
'@hcengineering/server-core':
specifier: workspace:^0.7.18
version: link:../core
@@ -61377,7 +61380,7 @@ snapshots:
node-loader@2.0.0(webpack@5.102.1):
dependencies:
loader-utils: 2.0.4
webpack: 5.102.1
webpack: 5.102.1(esbuild@0.25.12)(webpack-cli@5.1.4)
node-localstorage@2.2.1:
dependencies:
@@ -394,6 +394,13 @@ export interface EnumOf extends Type<string> {
*/
export interface TypeHyperlink extends Type<Hyperlink> {}
/**
* @public
*/
export interface TypeRank extends Type<Rank> {
pos?: 'start' | 'end'
}
/**
* @public
*
+3 -3
View File
@@ -38,7 +38,7 @@ import core, {
type Obj,
type PersonId,
type PropertyType,
type Rank,
type TypeRank as TypeRankType,
type Ref,
type RefTo,
type Space,
@@ -531,8 +531,8 @@ export function TypeCollaborativeDoc (): Type<MarkupBlobRef> {
/**
* @public
*/
export function TypeRank (): Type<Rank> {
return { _class: core.class.TypeRank, label: core.string.Rank, icon: core.icon.TypeRank }
export function TypeRank (pos: 'start' | 'end' = 'end'): TypeRankType {
return { _class: core.class.TypeRank, label: core.string.Rank, icon: core.icon.TypeRank, pos }
}
export function TypePersonId (): Type<PersonId> {
@@ -38,6 +38,7 @@
"@hcengineering/core": "workspace:^0.7.24",
"@hcengineering/contact": "workspace:^0.7.0",
"@hcengineering/platform": "workspace:^0.7.19",
"@hcengineering/rank": "workspace:^0.7.17",
"@hcengineering/server-core": "workspace:^0.7.18",
"@hcengineering/query": "workspace:^0.7.17",
"@hcengineering/analytics": "workspace:^0.7.17",
@@ -44,3 +44,4 @@ export * from './userStatus'
export * from './findSecurity'
export * from './normalizeTx'
export * from './versioning'
export * from './rank'
@@ -0,0 +1,112 @@
//
// Copyright © 2025 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import core, {
type MeasureContext,
type Tx,
type SessionData,
type TxCreateDoc,
type TxApplyIf,
type Doc,
type Rank,
type TxMixin,
type TypeRank,
SortingOrder
} from '@hcengineering/core'
import { makeRank } from '@hcengineering/rank'
import {
type Middleware,
type TxMiddlewareResult,
type PipelineContext,
BaseMiddleware
} from '@hcengineering/server-core'
/**
* Special value to indicate that rank should be auto-generated
* @public
*/
export const RANK_AUTO = '' as Rank
export class RankMiddleware extends BaseMiddleware implements Middleware {
private constructor (context: PipelineContext, next?: Middleware) {
super(context, next)
}
static async create (
ctx: MeasureContext,
context: PipelineContext,
next: Middleware | undefined
): Promise<RankMiddleware> {
return new RankMiddleware(context, next)
}
async tx (ctx: MeasureContext<SessionData>, txes: Tx[]): Promise<TxMiddlewareResult> {
for (const tx of txes) {
await this.processTx(ctx, tx)
}
return await this.provideTx(ctx, txes)
}
private async processTx (ctx: MeasureContext<SessionData>, tx: Tx): Promise<void> {
if (tx._class === core.class.TxCreateDoc) {
await this.setRank(ctx, tx as TxCreateDoc<Doc>)
} else if (tx._class === core.class.TxApplyIf) {
const applyTx = tx as TxApplyIf
for (const atx of applyTx.txes) {
await this.processTx(ctx, atx)
}
}
}
private async setRank (ctx: MeasureContext<SessionData>, tx: TxCreateDoc<Doc> | TxMixin<Doc, Doc>): Promise<void> {
const attributes =
tx._class === core.class.TxCreateDoc
? this.context.hierarchy.getAllAttributes(tx.objectClass)
: this.context.hierarchy.getOwnAttributes((tx as TxMixin<Doc, Doc>).mixin)
for (const attr of attributes) {
if (attr[1].type._class === core.class.TypeRank) {
const rankAttr = attr[1].name
const typeRank = attr[1].type as TypeRank
const rank = (tx.attributes as any)[rankAttr]
if (rank !== undefined && rank !== RANK_AUTO) {
continue
}
const pos = typeRank.pos ?? 'end'
// Query for either the first (Beginning) or last (End) document
const sortOrder = pos === 'end' ? SortingOrder.Descending : SortingOrder.Ascending
const existingDoc = await this.provideFindAll(
ctx,
tx.objectClass,
{ space: tx.objectSpace },
{
sort: { [rankAttr]: sortOrder },
projection: { [rankAttr]: 1 },
limit: 1
}
)
const lastRank = existingDoc.length > 0 ? (existingDoc[0] as any)[rankAttr] : undefined
const newRank = pos === 'end' ? makeRank(lastRank, undefined) : makeRank(undefined, lastRank)
;(tx.attributes as any)[rankAttr] = newRank
}
}
}
}
+4 -1
View File
@@ -63,6 +63,7 @@ import {
ReadOnly,
TypeCollaborativeDoc,
TypeNumber,
TypeRank,
TypeRef,
TypeString,
UX
@@ -127,7 +128,9 @@ export class TCard extends TDoc implements Card {
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files })
attachments?: number
rank!: Rank
@Prop(TypeRank(), core.string.Rank)
@Hidden()
rank!: Rank
@Prop(Collection(time.class.ToDo), getEmbeddedLabel('Action Items'))
todos?: CollectionSize<ToDo>
+3 -1
View File
@@ -75,7 +75,8 @@ import {
UX,
TypeCollaborativeDoc,
TypeMarkup,
ReadOnly
ReadOnly,
TypeRank
} from '@hcengineering/model'
import attachment from '@hcengineering/model-attachment'
import chunter, { TChatMessage } from '@hcengineering/model-chunter'
@@ -181,6 +182,7 @@ export class TProjectMeta extends TDoc implements ProjectMeta {
@Prop(Collection(documents.class.ProjectDocument), documents.string.Documents)
documents!: CollectionSize<ProjectDocument>
@Prop(TypeRank(), core.string.Rank)
@Index(IndexKind.Indexed)
@Hidden()
rank!: Rank
+2
View File
@@ -38,6 +38,7 @@ import {
TypeAccountUuid,
TypeCollaborativeDoc,
TypeNumber,
TypeRank,
TypeRef,
TypeString,
UX
@@ -116,6 +117,7 @@ export class TDocument extends TDoc implements Document, Todoable {
@Prop(Collection(time.class.ToDo), getEmbeddedLabel('Action Items'))
todos?: CollectionSize<ToDo>
@Prop(TypeRank(), core.string.Rank)
@Index(IndexKind.Indexed)
@Hidden()
rank!: Rank
+2 -1
View File
@@ -36,6 +36,7 @@ import {
ReadOnly,
TypeBoolean,
TypeDate,
TypeRank,
TypeRecord,
TypeRef,
TypeString,
@@ -113,7 +114,7 @@ export class TTask extends TAttachedDoc implements Task {
@Prop(TypeDate(), task.string.DueDate, { editor: task.component.DueDateEditor })
dueDate!: Timestamp | null
@Prop(TypeString(), task.string.Rank)
@Prop(TypeRank(), task.string.Rank)
@Index(IndexKind.IndexedDsc)
@Hidden()
rank!: Rank
+3 -1
View File
@@ -44,7 +44,8 @@ import {
TypeString,
UX,
type Builder,
TypeMarkup
TypeMarkup,
TypeRank
} from '@hcengineering/model'
import { TEvent } from '@hcengineering/model-calendar'
import core, { TAttachedDoc, TClass, TDoc, TType } from '@hcengineering/model-core'
@@ -131,6 +132,7 @@ export class TToDo extends TAttachedDoc implements ToDo {
@Prop(Collection(tags.class.TagReference, tags.string.TagLabel), tags.string.Tags)
labels?: number | undefined
@Prop(TypeRank(), core.string.Rank)
@Index(IndexKind.Indexed)
@Hidden()
rank!: Rank
+3 -14
View File
@@ -1,17 +1,7 @@
import { Organization } from '@hcengineering/contact'
import core, {
PersonId,
Client,
Data,
Doc,
Ref,
SortingOrder,
Status,
TxOperations,
generateId
} from '@hcengineering/core'
import core, { PersonId, Client, Data, Doc, Ref, Status, TxOperations, generateId } from '@hcengineering/core'
import recruit, { Applicant, Vacancy } from '@hcengineering/recruit'
import task, { ProjectType, makeRank } from '@hcengineering/task'
import task, { ProjectType } from '@hcengineering/task'
export async function createVacancy (
rawClient: Client,
@@ -71,13 +61,12 @@ export async function createApplication (
throw new Error('sequence object not found')
}
const lastOne = await client.findOne(recruit.class.Applicant, {}, { sort: { rank: SortingOrder.Descending } })
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
await client.addCollection(recruit.class.Applicant, _space, doc._id, recruit.mixin.Candidate, 'applications', {
...data,
status: selectedState._id,
number: (incResult as any).object.sequence,
rank: makeRank(lastOne?.rank, undefined)
rank: ''
})
}
@@ -18,7 +18,7 @@
import core, { AttachedData, Ref, SortingOrder, Space, generateId } from '@hcengineering/core'
import { OK, Status } from '@hcengineering/platform'
import { Card, SpaceSelector, createQuery, getClient } from '@hcengineering/presentation'
import task, { TaskType, makeRank } from '@hcengineering/task'
import { TaskType } from '@hcengineering/task'
import { EditBox, Grid, Status as StatusControl } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import board from '../plugin'
@@ -62,7 +62,6 @@
throw new Error('sequence object not found')
}
const lastOne = await client.findOne(board.class.Card, {}, { sort: { rank: SortingOrder.Descending } })
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
const number = (incResult as any).object.sequence
@@ -73,7 +72,7 @@
title,
kind,
identifier: `CARD-${number}`,
rank: makeRank(lastOne?.rank, undefined),
rank: '',
assignee: null,
description: '',
members: [],
@@ -15,8 +15,7 @@
<script lang="ts">
import type { Card as BoardCard } from '@hcengineering/board'
import board from '../../plugin'
import { makeRank } from '@hcengineering/task'
import core, { AttachedData, generateId, Ref, SortingOrder, Space } from '@hcengineering/core'
import core, { AttachedData, generateId, Ref, Space } from '@hcengineering/core'
import { IconAdd, Button, showPopup } from '@hcengineering/ui'
import { getClient } from '@hcengineering/presentation'
import AddCardEditor from './AddCardEditor.svelte'
@@ -36,14 +35,13 @@
throw new Error('sequence object not found')
}
const lastOne = await client.findOne(board.class.Card, {}, { sort: { rank: SortingOrder.Descending } })
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
const value: AttachedData<BoardCard> = {
status: state._id,
number: (incResult as any).object.sequence,
title,
rank: makeRank(lastOne?.rank, undefined),
rank: '',
assignee: null,
description: '',
members: [],
@@ -6,11 +6,9 @@ import core, {
type Ref,
type Space,
type AttachedData,
SortingOrder,
type Status
} from '@hcengineering/core'
import { showPanel } from '@hcengineering/ui'
import { makeRank } from '@hcengineering/task'
import board from '../plugin'
export async function createCard (
@@ -24,7 +22,6 @@ export async function createCard (
throw new Error('sequence object not found')
}
const lastOne = await client.findOne(board.class.Card, {}, { sort: { rank: SortingOrder.Descending } })
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
const number = (incResult as any).object.sequence
@@ -34,7 +31,7 @@ export async function createCard (
startDate: null,
dueDate: null,
number,
rank: makeRank(lastOne?.rank, undefined),
rank: '',
assignee: null,
identifier: `CARD-${number}`,
description: '',
@@ -16,10 +16,9 @@
import { Analytics } from '@hcengineering/analytics'
import { Card, CardEvents, cardId } from '@hcengineering/card'
import { chatId } from '@hcengineering/chat'
import { Data, Doc, fillDefaults, MarkupBlobRef, SortingOrder, WithLookup } from '@hcengineering/core'
import { Data, Doc, fillDefaults, MarkupBlobRef, WithLookup } from '@hcengineering/core'
import { translate } from '@hcengineering/platform'
import { createQuery, getClient } from '@hcengineering/presentation'
import { makeRank } from '@hcengineering/rank'
import { ButtonIcon, getCurrentLocation, IconAdd, Label, navigate, resizeObserver, Section } from '@hcengineering/ui'
import view, { encodeObjectURI, Viewlet, ViewletPreference, ViewOptions } from '@hcengineering/view'
import {
@@ -101,13 +100,12 @@
async function createCard (): Promise<void> {
const client = getClient()
const hierarchy = client.getHierarchy()
const lastOne = await client.findOne(card.class.Card, {}, { sort: { rank: SortingOrder.Descending } })
const title = await translate(card.string.Card, {})
const data: Data<Card> = {
parent: object._id,
title,
rank: makeRank(lastOne?.rank, undefined),
rank: '',
content: '' as MarkupBlobRef,
blobs: {},
parentInfo: [
@@ -15,9 +15,8 @@
<script lang="ts">
import { Analytics } from '@hcengineering/analytics'
import { Card, CardEvents } from '@hcengineering/card'
import core, { Class, Data, Doc, fillDefaults, MarkupBlobRef, Ref, SortingOrder } from '@hcengineering/core'
import core, { Class, Data, Doc, fillDefaults, MarkupBlobRef, Ref } from '@hcengineering/core'
import { translate } from '@hcengineering/platform'
import { makeRank } from '@hcengineering/rank'
import { ButtonIcon, getCurrentLocation, IconAdd, navigate } from '@hcengineering/ui'
import { getClient } from '@hcengineering/presentation'
import card from '../plugin'
@@ -29,12 +28,11 @@
async function createCard (): Promise<void> {
if (_class === undefined) return
const lastOne = await client.findOne(card.class.Card, {}, { sort: { rank: SortingOrder.Descending } })
const title = await translate(card.string.Card, {})
const data: Data<Card> = {
title,
rank: makeRank(lastOne?.rank, undefined),
rank: '',
content: '' as MarkupBlobRef,
parentInfo: [],
blobs: {}
+1 -4
View File
@@ -34,7 +34,6 @@ import core, {
type MarkupBlobRef,
type Ref,
type RelatedDocument,
SortingOrder,
type Space,
toRank,
type TxOperations,
@@ -50,7 +49,6 @@ import presentation, {
MessageBox,
type ObjectSearchResult
} from '@hcengineering/presentation'
import { makeRank } from '@hcengineering/rank'
import { EmptyMarkup, isEmptyMarkup } from '@hcengineering/text'
import {
getCurrentLocation,
@@ -537,7 +535,6 @@ export async function createCard (
): Promise<Ref<Card>> {
const client = getClient()
const hierarchy = client.getHierarchy()
const lastOne = await client.findOne(card.class.Card, {}, { sort: { rank: SortingOrder.Descending } })
const title = data.title ?? (await translate(card.string.Card, {}))
const _id = id ?? generateId()
@@ -550,7 +547,7 @@ export async function createCard (
blobs: {},
...data,
title,
rank: makeRank(lastOne?.rank, undefined),
rank: '',
content
}
@@ -28,8 +28,7 @@ import {
linkPreviewType,
type Message,
type MessageID,
MessageType,
SortingOrder
MessageType
} from '@hcengineering/communication-types'
import cardPlugin, { type Card, type MasterTag } from '@hcengineering/card'
import { addRefreshListener, deleteFile, getClient, getCommunicationClient } from '@hcengineering/presentation'
@@ -45,7 +44,6 @@ import {
import { getMetadata, getResource } from '@hcengineering/platform'
import { employeeByPersonIdStore } from '@hcengineering/contact-resources'
import { getEmployeeBySocialId } from '@hcengineering/contact'
import { makeRank } from '@hcengineering/rank'
import chat from '@hcengineering/chat'
import { markupToText } from '@hcengineering/text'
import { get } from 'svelte/store'
@@ -130,12 +128,11 @@ export async function attachCardToMessage (
const author =
get(employeeByPersonIdStore).get(message.creator) ?? (await getEmployeeBySocialId(client, message.creator))
const lastOne = await client.findOne(cardPlugin.class.Card, {}, { sort: { rank: SortingOrder.Descending } })
const data = fillDefaults<Card>(
hierarchy,
{
title,
rank: makeRank(lastOne?.rank, undefined),
rank: '',
content: '' as MarkupBlobRef,
blobs: {},
parentInfo: [
+2 -5
View File
@@ -18,13 +18,11 @@ import {
getCurrentAccount,
type MarkupBlobRef,
type Ref,
SortingOrder,
type Timestamp
} from '@hcengineering/core'
import { type Poll, type PollAnswer } from '@hcengineering/communication'
import { getClient, getCommunicationClient } from '@hcengineering/presentation'
import card, { type Card } from '@hcengineering/card'
import { makeRank } from '@hcengineering/rank'
import { type Card } from '@hcengineering/card'
import { type AppletAttachment, type MessageID } from '@hcengineering/communication-types'
import communication from './plugin'
@@ -71,11 +69,10 @@ export async function createPoll (parent: Card, message: MessageID, params: Poll
const client = getClient()
const communicationClient = getCommunicationClient()
const hierarchy = client.getHierarchy()
const lastOne = await client.findOne(card.class.Card, {}, { sort: { rank: SortingOrder.Descending } })
const data: Data<Poll> = {
title: params.question,
rank: makeRank(lastOne?.rank, undefined),
rank: '',
content: '' as MarkupBlobRef,
parentInfo: [],
blobs: {},
@@ -24,13 +24,12 @@
getCurrentAccount,
hasAccountRole,
Ref,
SortingOrder,
Status as TaskStatus
} from '@hcengineering/core'
import { Customer, Funnel, Lead, LeadEvents } from '@hcengineering/lead'
import { OK, Status } from '@hcengineering/platform'
import { Card, createQuery, getClient, InlineAttributeBar, SpaceSelector } from '@hcengineering/presentation'
import task, { getStates, makeRank, TaskType } from '@hcengineering/task'
import task, { getStates, TaskType } from '@hcengineering/task'
import { TaskKindSelector, typeStore } from '@hcengineering/task-resources'
import { Button, createFocusManager, EditBox, FocusHandler, Label, Status as StatusControl } from '@hcengineering/ui'
import { statusStore } from '@hcengineering/view-resources'
@@ -93,7 +92,6 @@
throw new Error('kind is not specified')
}
const lastOne = await client.findOne(lead.class.Lead, {}, { sort: { rank: SortingOrder.Descending } })
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
const number = (incResult as any).object.sequence
@@ -103,7 +101,7 @@
identifier: `LEAD-${number}`,
title,
kind,
rank: makeRank(lastOne?.rank, undefined),
rank: '',
assignee: null,
startDate: null,
dueDate: null,
@@ -25,8 +25,8 @@
Doc,
FindOptions,
Markup,
PersonId,
Ref,
SortingOrder,
Space,
Status as TaskStatus,
fillDefaults,
@@ -43,7 +43,7 @@
getClient
} from '@hcengineering/presentation'
import { recruitId, type Applicant, type Candidate, type Vacancy, RecruitEvents } from '@hcengineering/recruit'
import task, { TaskType, getStates, makeRank } from '@hcengineering/task'
import { TaskType, getStates } from '@hcengineering/task'
import { TaskKindSelector, selectedTypeStore, typeStore } from '@hcengineering/task-resources'
import { EmptyMarkup, isEmptyMarkup } from '@hcengineering/text'
import ui, {
@@ -98,7 +98,7 @@
_id: generateId(),
collection: 'applications',
modifiedOn: Date.now(),
modifiedBy: '',
modifiedBy: '' as PersonId,
startDate: null,
dueDate: null,
kind: '' as Ref<TaskType>,
@@ -126,7 +126,6 @@
throw new Error('kind is not specified')
}
const lastOne = await client.findOne(recruit.class.Applicant, {}, { sort: { rank: SortingOrder.Descending } })
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
const candidateInstance = await client.findOne(contact.class.Person, { _id: _candidate })
@@ -159,7 +158,7 @@
status: selectedState._id,
number,
identifier: `APP-${number}`,
rank: makeRank(lastOne?.rank, undefined),
rank: '',
kind
},
doc._id
@@ -40,7 +40,7 @@
} from '@hcengineering/presentation'
import { RecruitEvents, Vacancy, Vacancy as VacancyClass } from '@hcengineering/recruit'
import tags from '@hcengineering/tags'
import task, { ProjectType, makeRank } from '@hcengineering/task'
import task, { ProjectType } from '@hcengineering/task'
import { selectedTypeStore, typeStore } from '@hcengineering/task-resources'
import tracker, { Issue, IssueStatus, IssueTemplate, IssueTemplateData, Project } from '@hcengineering/tracker'
import {
@@ -160,11 +160,6 @@
template: IssueTemplateData,
parent: Ref<Issue> = tracker.ids.NoParent
): Promise<Ref<Issue> | undefined> {
const lastOne = await client.findOne<Issue>(
tracker.class.Issue,
{ space },
{ sort: { rank: SortingOrder.Descending } }
)
const incResult = await client.updateDoc(
tracker.class.Project,
core.space.Space,
@@ -175,7 +170,6 @@
true
)
const project = await client.findOne(tracker.class.Project, { _id: space })
const rank = makeRank(lastOne?.rank, undefined)
const taskType = await client.findOne(task.class.TaskType, { ofClass: tracker.class.Issue })
if (taskType === undefined) {
return
@@ -193,7 +187,7 @@
number,
status: project?.defaultIssueStatus as Ref<IssueStatus>,
priority: template.priority,
rank,
rank: '',
comments: 0,
subIssues: 0,
dueDate: null,
@@ -50,7 +50,7 @@
SpaceSelector
} from '@hcengineering/presentation'
import tags, { type TagElement, TagReference } from '@hcengineering/tags'
import { makeRank, TaskType } from '@hcengineering/task'
import { TaskType } from '@hcengineering/task'
import { TaskKindSelector } from '@hcengineering/task-resources'
import { EmptyMarkup, isEmptyMarkup } from '@hcengineering/text'
import {
@@ -460,11 +460,6 @@
try {
const operations = client.apply(undefined, 'tracker.createIssue')
const lastOne = await client.findOne<Issue>(
tracker.class.Issue,
{ space: _space },
{ sort: { rank: SortingOrder.Descending } }
)
const incResult = await client.updateDoc(
tracker.class.Project,
core.space.Space,
@@ -488,7 +483,7 @@
number,
status: object.status,
priority: object.priority,
rank: makeRank(lastOne?.rank, undefined),
rank: '',
comments: 0,
subIssues: 0,
dueDate: object.dueDate,
@@ -58,7 +58,6 @@
if (project === undefined) return
saved = true
for (const subIssue of subIssues) {
const lastOne = await client.findOne<Issue>(tracker.class.Issue, {}, { sort: { rank: SortingOrder.Descending } })
const incResult = await client.updateDoc(
tracker.class.Project,
core.space.Space,
@@ -79,7 +78,7 @@
number,
status: subIssue.status ?? project.defaultIssueStatus,
priority: subIssue.priority,
rank: makeRank(lastOne?.rank, undefined),
rank: '',
comments: 0,
subIssues: 0,
dueDate: null,
+2
View File
@@ -42,6 +42,7 @@ import {
PrivateMiddleware,
QueryJoinMiddleware,
QueueMiddleware,
RankMiddleware,
SpacePermissionsMiddleware,
SpaceSecurityMiddleware,
VersioningMiddleware,
@@ -143,6 +144,7 @@ export function createServerPipeline (
NormalizeTxMiddleware.create,
IdentityMiddleware.create,
ModifiedMiddleware.create,
RankMiddleware.create,
FindSecurityMiddleware.create,
PluginConfigurationMiddleware.create,
PrivateMiddleware.create,