EZQMS-602: Moved Rank to its own package (#4845)

Signed-off-by: Petr Vyazovetskiy <develop.pit@gmail.com>
This commit is contained in:
Pete Anøther 2024-03-05 02:38:10 -03:00 committed by GitHub
parent 423d6f044a
commit bbe4a3a6d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 477 additions and 398 deletions

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ import core, {
import tracker, { Issue, IssuePriority, IssueStatus, Project } from '@hcengineering/tracker'
import { connect } from './connect'
import { calcRank } from '@hcengineering/task'
import { makeRank } from '@hcengineering/task'
let objectId: Ref<Issue> = generateId()
const space = tracker.project.DefaultProject
@ -94,7 +94,7 @@ async function genIssue (client: TxOperations, statuses: Ref<IssueStatus>[]): Pr
number,
status: faker.random.arrayElement(statuses),
priority: faker.random.arrayElement(Object.values(IssuePriority)) as IssuePriority,
rank: calcRank(lastOne, undefined),
rank: makeRank(lastOne?.rank, undefined),
comments: 0,
subIssues: 0,
dueDate: object.dueDate,

View File

@ -15,7 +15,7 @@ import core, {
import { MinioService } from '@hcengineering/minio'
import recruit from '@hcengineering/model-recruit'
import { Applicant, Candidate, Vacancy } from '@hcengineering/recruit'
import task, { ProjectType, TaskType, genRanks } from '@hcengineering/task'
import task, { ProjectType, TaskType, genRanks, type Rank } from '@hcengineering/task'
import faker from 'faker'
import jpeg, { BufferRet } from 'jpeg-js'
import { AttachmentOptions, addAttachments } from './attachments'
@ -174,7 +174,7 @@ async function genApplicant (
options: RecruitOptions,
minio: MinioService,
workspaceId: WorkspaceId,
rank: string
rank: Rank
): Promise<void> {
const applicantId = `vacancy-${vacancyId}-${candidateId}` as Ref<Applicant>

View File

@ -72,6 +72,7 @@ import {
type ProjectType,
type ProjectTypeClass,
type ProjectTypeDescriptor,
type Rank,
type Sequence,
type Task,
type TaskStatusFactory,
@ -123,7 +124,7 @@ export class TTask extends TAttachedDoc implements Task {
@Prop(TypeString(), task.string.Rank)
@Index(IndexKind.IndexedDsc)
@Hidden()
rank!: string
rank!: Rank
@Prop(Collection(tags.class.TagReference, task.string.TaskLabels), task.string.TaskLabels)
labels?: number

View File

@ -36,4 +36,4 @@
"StatusCategory": "Categoría de estado",
"Account": "Cuenta"
}
}
}

View File

@ -36,4 +36,4 @@
"StatusCategory": "Categoria de estado",
"Account": "Conta"
}
}
}

View File

@ -44,6 +44,7 @@
"@hcengineering/platform": "^0.6.9",
"@hcengineering/core": "^0.6.28",
"@hcengineering/presentation": "^0.6.2",
"@hcengineering/notification": "^0.6.16"
"@hcengineering/notification": "^0.6.16",
"@hcengineering/rank": "^0.6.0"
}
}

View File

@ -25,10 +25,10 @@
Space
} from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation'
import { makeRank } from '@hcengineering/rank'
import { ScrollBox, Scroller } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import { CardDragEvent, DocWithRank, Item } from '../types'
import { calcRank } from '../utils'
import KanbanRow from './KanbanRow.svelte'
export let categories: CategoryType[] = []
@ -204,8 +204,7 @@
const arr = getGroupByValues(groupByDocs, state) ?? []
const s = arr.findIndex((p) => p._id === dragCard?._id)
if (s !== -1) {
const newRank = calcRank(arr[s - 1], arr[s + 1])
dragCard.rank = newRank
dragCard.rank = makeRank(arr[s - 1]?.rank, arr[s + 1]?.rank)
}
}
isDragging = false

View File

@ -17,4 +17,3 @@ import '@hcengineering/platform-rig/profiles/ui/svelte'
export * from './types'
export { default as Kanban } from './components/Kanban.svelte'
export { default as KanbanCardEmpty } from './components/KanbanCardEmpty.svelte'

View File

@ -1,11 +1,12 @@
import { type Doc } from '@hcengineering/core'
import { type Asset } from '@hcengineering/platform'
import type { Rank } from '@hcengineering/rank'
/**
* @public
*/
export interface DocWithRank extends Doc {
rank: string
rank: Rank
}
export type StateType = any

View File

@ -1,47 +0,0 @@
//
// Copyright © 2020, 2021 Anticrm Platform Contributors.
//
// 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 { 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()
}

View File

@ -119,10 +119,6 @@ function getAttrs (target: any, prop: string): Record<string, any> {
/**
* @public
* @param type -
* @param label -
* @param icon -
* @returns
*/
export function Prop (type: Type<PropertyType>, label: IntlString, extra: Partial<Attribute<PropertyType>> = {}) {
return function (target: any, propertyKey: string): void {
@ -225,9 +221,6 @@ export function Mixin<T extends Obj> (_class: Ref<Class<T>>, _extends: Ref<Class
/**
* @public
* @param label -
* @param icon -
* @returns
*/
export function UX<T extends Obj> (
label: IntlString,

View File

@ -0,0 +1,7 @@
module.exports = {
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
}

View File

@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@hcengineering/platform-rig"
}

View File

@ -0,0 +1,7 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
roots: ["./src"],
coverageReporters: ["text-summary", "html"]
}

View File

@ -0,0 +1,38 @@
{
"name": "@hcengineering/rank",
"version": "0.6.0",
"main": "lib/index.js",
"svelte": "src/index.ts",
"types": "types/index.d.ts",
"author": "Anticrm Platform Contributors",
"license": "EPL-2.0",
"scripts": {
"_phase:build": "compile transpile src",
"_phase:validate": "compile validate",
"_phase:test": "jest --passWithNoTests --silent",
"_phase:format": "format src",
"build": "compile",
"test": "jest --passWithNoTests --silent",
"build:watch": "compile",
"format": "format src"
},
"devDependencies": {
"@hcengineering/platform-rig": "^0.6.0",
"@typescript-eslint/eslint-plugin": "^6.11.0",
"@typescript-eslint/parser": "^6.11.0",
"eslint-config-standard-with-typescript": "^40.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.4.0",
"eslint-plugin-promise": "^6.1.1",
"eslint": "^8.54.0",
"prettier": "^3.1.0",
"prettier-plugin-svelte": "^3.1.0",
"jest": "^29.7.0",
"ts-jest": "^29.1.1",
"@types/jest":"^29.5.5",
"typescript":"^5.3.3"
},
"dependencies": {
"lexorank": "~1.0.4"
}
}

View File

@ -1,5 +1,5 @@
<!--
// Copyright © 2022 Hardcore Engineering Inc.
//
// Copyright © 2024 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
@ -11,27 +11,7 @@
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
//
<div class="card-container">
<slot />
</div>
<style lang="scss">
.card-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 0.75rem 1.5rem;
color: var(--dark-color);
background-color: var(--theme-kanban-card-bg-color);
border: 1px dotted var(--theme-kanban-card-border);
border-radius: 0.75rem;
cursor: pointer;
&:hover {
color: var(--theme-caption-color);
}
}
</style>
export * from './types'
export * from './utils'

View File

@ -0,0 +1,21 @@
//
// Copyright © 2024 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.
//
/**
* @public
*
* String representation of {@link https://www.npmjs.com/package/lexorank LexoRank} type
*/
export type Rank = string

View File

@ -0,0 +1,42 @@
//
// Copyright © 2024 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 LexoRankBucket from 'lexorank/lib/lexoRank/lexoRankBucket'
import type { Rank } from './types'
import { LexoDecimal, LexoNumeralSystem36, LexoRank } from 'lexorank'
/** @public */
export function genRanks (count: number): Rank[] {
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)
const res: string[] = []
for (let i = 0; i < count; i++) {
cur = cur.add(gap)
res.push(new LexoRank(LexoRankBucket.BUCKET_0, cur).toString())
}
return res
}
/** @public */
export function makeRank (prev: Rank | undefined, next: Rank | undefined): Rank {
const prevLexoRank = prev === undefined ? LexoRank.min() : LexoRank.parse(prev)
const nextLexoRank = next === undefined ? LexoRank.max() : LexoRank.parse(next)
return prevLexoRank.equals(nextLexoRank)
? prevLexoRank.genNext().toString()
: prevLexoRank.between(nextLexoRank).toString()
}

View File

@ -0,0 +1,10 @@
{
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
"declarationDir": "./types",
"tsBuildInfoFile": ".build/build.tsbuildinfo"
}
}

View File

@ -1,7 +1,7 @@
import { Organization } from '@hcengineering/contact'
import core, { Account, Client, Data, Doc, Ref, SortingOrder, Status, TxOperations } from '@hcengineering/core'
import recruit, { Applicant, Vacancy } from '@hcengineering/recruit'
import task, { ProjectType, calcRank } from '@hcengineering/task'
import task, { ProjectType, makeRank } from '@hcengineering/task'
export async function createVacancy (
rawClient: Client,
@ -60,6 +60,6 @@ export async function createApplication (
...data,
status: selectedState._id,
number: (incResult as any).object.sequence,
rank: calcRank(lastOne, undefined)
rank: makeRank(lastOne?.rank, undefined)
})
}

View File

@ -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, calcRank } from '@hcengineering/task'
import task, { TaskType, makeRank } from '@hcengineering/task'
import { EditBox, Grid, Status as StatusControl } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import board from '../plugin'
@ -73,7 +73,7 @@
title,
kind,
identifier: `CARD-${number}`,
rank: calcRank(lastOne, undefined),
rank: makeRank(lastOne?.rank, undefined),
assignee: null,
description: '',
members: [],

View File

@ -15,7 +15,7 @@
<script lang="ts">
import type { Card as BoardCard } from '@hcengineering/board'
import board from '../../plugin'
import task, { calcRank } from '@hcengineering/task'
import task, { makeRank } from '@hcengineering/task'
import { AttachedData, generateId, Ref, SortingOrder, Space } from '@hcengineering/core'
import { IconAdd, Button, showPopup } from '@hcengineering/ui'
import { getClient } from '@hcengineering/presentation'
@ -43,7 +43,7 @@
status: state._id,
number: (incResult as any).object.sequence,
title,
rank: calcRank(lastOne, undefined),
rank: makeRank(lastOne?.rank, undefined),
assignee: null,
description: '',
members: [],

View File

@ -3,7 +3,7 @@
import { Ref, SortingOrder } from '@hcengineering/core'
import { IntlString, translate } from '@hcengineering/platform'
import { createQuery } from '@hcengineering/presentation'
import { calcRank, State } from '@hcengineering/task'
import { makeRank, State } from '@hcengineering/task'
import { DropdownLabels, DropdownTextItem, themeStore } from '@hcengineering/ui'
import board from '../../plugin'
@ -22,7 +22,7 @@
const filteredResult = isCopying ? result : result.filter((t) => t._id !== object._id)
;[ranks] = [...filteredResult, undefined].reduce<[DropdownTextItem[], Card | undefined]>(
([arr, prev], next) => [[...arr, { id: calcRank(prev, next), label: `${arr.length + 1}` }], next],
([arr, prev], next) => [[...arr, { id: makeRank(prev?.rank, next?.rank), label: `${arr.length + 1}` }], next],
[[], undefined]
)

View File

@ -11,7 +11,7 @@ import {
type Status
} from '@hcengineering/core'
import { showPanel } from '@hcengineering/ui'
import task, { calcRank } from '@hcengineering/task'
import task, { makeRank } from '@hcengineering/task'
import board from '../plugin'
export async function createCard (
@ -35,7 +35,7 @@ export async function createCard (
startDate: null,
dueDate: null,
number,
rank: calcRank(lastOne, undefined),
rank: makeRank(lastOne?.rank, undefined),
assignee: null,
identifier: `CARD-${number}`,
description: '',

View File

@ -20,7 +20,7 @@
import type { Customer, Funnel, Lead } from '@hcengineering/lead'
import { OK, Status } from '@hcengineering/platform'
import { Card, createQuery, getClient, InlineAttributeBar, SpaceSelector } from '@hcengineering/presentation'
import task, { calcRank, getStates, TaskType } from '@hcengineering/task'
import task, { getStates, makeRank, 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'
@ -92,7 +92,7 @@
identifier: `LEAD-${number}`,
title,
kind,
rank: calcRank(lastOne, undefined),
rank: makeRank(lastOne?.rank, undefined),
assignee: null,
startDate: null,
dueDate: null,

View File

@ -41,7 +41,7 @@
getClient
} from '@hcengineering/presentation'
import type { Applicant, Candidate, Vacancy } from '@hcengineering/recruit'
import task, { TaskType, calcRank, getStates } from '@hcengineering/task'
import task, { TaskType, getStates, makeRank } from '@hcengineering/task'
import ui, {
Button,
ColorPopup,
@ -152,7 +152,7 @@
number,
identifier: `APP-${number}`,
assignee: doc.assignee,
rank: calcRank(lastOne, undefined),
rank: makeRank(lastOne?.rank, undefined),
startDate: null,
dueDate: null,
kind

View File

@ -20,7 +20,7 @@
import { Card, createQuery, getClient, InlineAttributeBar, MessageBox } from '@hcengineering/presentation'
import { Vacancy as VacancyClass } from '@hcengineering/recruit'
import tags from '@hcengineering/tags'
import task, { calcRank, ProjectType } from '@hcengineering/task'
import task, { makeRank, ProjectType } from '@hcengineering/task'
import tracker, { Issue, IssueStatus, IssueTemplate, IssueTemplateData, Project } from '@hcengineering/tracker'
import {
Button,
@ -113,7 +113,7 @@
true
)
const project = await client.findOne(tracker.class.Project, { _id: space })
const rank = calcRank(lastOne, undefined)
const rank = makeRank(lastOne?.rank, undefined)
const taskType = await client.findOne(task.class.TaskType, { ofClass: tracker.class.Issue })
if (taskType === undefined) {
return

View File

@ -28,10 +28,11 @@ import {
import { type IntlString, type Resources } from '@hcengineering/platform'
import { createQuery, getClient } from '@hcengineering/presentation'
import task, {
calcRank,
getStatusIndex,
makeRank,
type Project,
type ProjectType,
type Rank,
type Task,
type TaskType
} from '@hcengineering/task'
@ -238,8 +239,8 @@ async function statusSort (
}
})
} else {
const res = new Map<Ref<Status>, string>()
let prevRank: string | undefined
const res = new Map<Ref<Status>, Rank>()
let prevRank: Rank | undefined
const types = await client.findAll(task.class.ProjectType, {})
for (const state of value) {
if (res.has(state)) continue
@ -254,17 +255,14 @@ async function statusSort (
const st = statuses[index]
const prev = index > 0 ? res.get(statuses[index - 1]) : prevRank
const next = index < statuses.length - 1 ? res.get(statuses[index + 1]) : undefined
const rank = calcRank(
prev !== undefined ? { rank: prev } : undefined,
next !== undefined ? { rank: next } : undefined
)
const rank = makeRank(prev, next)
res.set(st, rank)
prevRank = rank
}
}
const result: Array<{
_id: Ref<Status>
rank: string
rank: Rank
}> = []
for (const [key, value] of res.entries()) {
result.push({ _id: key, rank: value })

View File

@ -37,9 +37,9 @@
"@hcengineering/core": "^0.6.28",
"@hcengineering/notification": "^0.6.16",
"@hcengineering/platform": "^0.6.9",
"@hcengineering/rank": "^0.6.0",
"@hcengineering/ui": "^0.6.11",
"@hcengineering/view": "^0.6.9",
"lexorank": "~1.0.4"
"@hcengineering/view": "^0.6.9"
},
"repository": "https://github.com/hcengineering/anticrm",
"publishConfig": {

View File

@ -29,14 +29,16 @@ import {
import { NotificationType } from '@hcengineering/notification'
import type { Asset, IntlString, Plugin, Resource } from '@hcengineering/platform'
import { plugin } from '@hcengineering/platform'
import type { Rank } from '@hcengineering/rank'
import type { AnyComponent, ComponentExtensionId } from '@hcengineering/ui'
import { Action, IconProps, ViewletDescriptor } from '@hcengineering/view'
/**
* @public
*/
export * from './utils'
export type { Rank } from '@hcengineering/rank'
/** @public */
export interface DocWithRank extends Doc {
rank: string
rank: Rank
}
export interface Project extends Space {
@ -303,4 +305,3 @@ const task = plugin(taskId, {
})
export default task
export * from './utils'

View File

@ -29,37 +29,18 @@ import core, {
type RefTo
} from '@hcengineering/core'
import { PlatformError, getEmbeddedLabel, unknownStatus } from '@hcengineering/platform'
import { LexoDecimal, LexoNumeralSystem36, LexoRank } from 'lexorank'
import LexoRankBucket from 'lexorank/lib/lexoRank/lexoRankBucket'
import task, { Project, ProjectStatus, ProjectType, Task, TaskType } from '.'
import { makeRank, type Rank } from '@hcengineering/rank'
export { genRanks, makeRank } from '@hcengineering/rank'
/**
* @public
*
* TODO: Drop after everything migrates to {@link makeRank}
*/
export function genRanks (count: number): string[] {
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)
const res: string[] = []
for (let i = 0; i < count; i++) {
cur = cur.add(gap)
res.push(new LexoRank(LexoRankBucket.BUCKET_0, cur).toString())
}
return res
}
/**
* @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()
export const calcRank = (prev?: { rank: Rank }, next?: { rank: Rank }): string => {
return makeRank(prev?.rank, next?.rank)
}
/**

View File

@ -44,7 +44,7 @@
getClient
} from '@hcengineering/presentation'
import tags, { TagElement, TagReference } from '@hcengineering/tags'
import { TaskType, calcRank } from '@hcengineering/task'
import { TaskType, makeRank } from '@hcengineering/task'
import { TaskKindSelector } from '@hcengineering/task-resources'
import {
Component as ComponentType,
@ -434,7 +434,7 @@
number,
status: object.status,
priority: object.priority,
rank: calcRank(lastOne, undefined),
rank: makeRank(lastOne?.rank, undefined),
comments: 0,
subIssues: 0,
dueDate: object.dueDate,

View File

@ -15,7 +15,7 @@
<script lang="ts">
import core, { AttachedData, FindOptions, Ref, SortingOrder } from '@hcengineering/core'
import { ObjectPopup, getClient } from '@hcengineering/presentation'
import { calcRank } from '@hcengineering/task'
import { makeRank } from '@hcengineering/task'
import { Issue, IssueDraft } from '@hcengineering/tracker'
import { createEventDispatcher } from 'svelte'
import tracker from '../plugin'
@ -51,7 +51,7 @@
{ sort: { rank: SortingOrder.Descending } }
)
rank = calcRank(lastAttachedIssue, undefined)
rank = makeRank(lastAttachedIssue?.rank, undefined)
}
await client.update(docValue, {

View File

@ -18,7 +18,7 @@
import core, { AttachedData, Doc, Ref, SortingOrder } from '@hcengineering/core'
import { DraftController, draftsStore, getClient } from '@hcengineering/presentation'
import tags from '@hcengineering/tags'
import { calcRank } from '@hcengineering/task'
import { makeRank } from '@hcengineering/task'
import { Component, Issue, IssueDraft, IssueParentInfo, Milestone, Project } from '@hcengineering/tracker'
import { Button, ExpandCollapse, Scroller } from '@hcengineering/ui'
import { onDestroy } from 'svelte'
@ -79,7 +79,7 @@
number,
status: subIssue.status ?? project.defaultIssueStatus,
priority: subIssue.priority,
rank: calcRank(lastOne, undefined),
rank: makeRank(lastOne?.rank, undefined),
comments: 0,
subIssues: 0,
dueDate: null,

View File

@ -37,7 +37,7 @@ import core, {
} from '@hcengineering/core'
import { type Asset, type IntlString } from '@hcengineering/platform'
import { createQuery, getClient } from '@hcengineering/presentation'
import task, { calcRank, getStatusIndex, type ProjectType } from '@hcengineering/task'
import task, { getStatusIndex, makeRank, type ProjectType } from '@hcengineering/task'
import { activeProjects as taskActiveProjects, taskTypeStore } from '@hcengineering/task-resources'
import {
IssuePriority,
@ -576,7 +576,7 @@ async function updateIssuesOnMove (
space,
{
...updates.get(attached._id as Ref<Issue>),
rank: calcRank(lastOne, undefined),
rank: makeRank(lastOne?.rank, undefined),
number: (incResult as any).object.sequence
},
updates
@ -622,7 +622,7 @@ export async function moveIssueToSpace (
space,
{
...updates.get(doc._id),
rank: calcRank(lastOne, undefined),
rank: makeRank(lastOne?.rank, undefined),
number,
identifier: `${space.identifier}-${number}`
},

View File

@ -19,7 +19,7 @@
import core, { Class, Client, Doc, Ref, SortingOrder, Space } from '@hcengineering/core'
import { OK, Resource, Status, getResource, translate } from '@hcengineering/platform'
import task, { Project, Task, calcRank } from '@hcengineering/task'
import task, { Project, Task, makeRank } from '@hcengineering/task'
import { createEventDispatcher } from 'svelte'
import view from '../plugin'
import { moveToSpace } from '../utils'
@ -51,7 +51,7 @@
if (needRank) {
const lastOne = await client.findOne((doc as Task)._class, { space }, { sort: { rank: SortingOrder.Descending } })
await moveToSpace(client, doc, space, {
rank: calcRank(lastOne, undefined)
rank: makeRank(lastOne?.rank, undefined)
})
} else {
await moveToSpace(client, doc, space)

View File

@ -29,7 +29,7 @@
} from '@hcengineering/core'
import { IntlString } from '@hcengineering/platform'
import { createQuery, getClient } from '@hcengineering/presentation'
import { DocWithRank, calcRank } from '@hcengineering/task'
import { DocWithRank, makeRank } from '@hcengineering/task'
import { AnyComponent, AnySvelteComponent, ExpandCollapse, mouseAttractor } from '@hcengineering/ui'
import { AttributeModel, BuildModelKey, ViewOptionModel, ViewOptions, Viewlet } from '@hcengineering/view'
import { createEventDispatcher } from 'svelte'
@ -286,7 +286,7 @@
const prev = limited[dragItemIndex - 1] as DocWithRank
const next = limited[dragItemIndex + 1] as DocWithRank
try {
const newRank = calcRank(prev, next)
const newRank = makeRank(prev?.rank, next?.rank)
if ((dragItem.doc as DocWithRank)?.rank !== newRank) {
;(update as any).rank = newRank
}

View File

@ -16,7 +16,7 @@
import { Class, Doc, DocumentQuery, FindOptions, FindResult, Ref, SortingOrder } from '@hcengineering/core'
import { Asset, getResource, IntlString } from '@hcengineering/platform'
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
import { calcRank, DocWithRank } from '@hcengineering/task'
import { DocWithRank, makeRank } from '@hcengineering/task'
import { Button, Component, Icon, IconAdd, IconSize, Label, Loading } from '@hcengineering/ui'
import view, { ObjectFactory } from '@hcengineering/view'
import { flip } from 'svelte/animate'
@ -123,7 +123,8 @@
]
const sortingOrder = queryOptions?.sort?.rank ?? SORTING_ORDER
const rank = sortingOrder === SortingOrder.Ascending ? calcRank(prev, next) : calcRank(next, prev)
const rank =
sortingOrder === SortingOrder.Ascending ? makeRank(prev?.rank, next?.rank) : makeRank(next?.rank, prev?.rank)
try {
areItemsSorting = true

View File

@ -586,6 +586,11 @@
"projectFolder": "packages/query",
"shouldPublish": true
},
{
"packageName": "@hcengineering/rank",
"projectFolder": "packages/rank",
"shouldPublish": true
},
{
"packageName": "@hcengineering/view",
"projectFolder": "plugins/view",