mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 03:14:40 +03:00
EZQMS-602: Moved Rank to its own package (#4845)
Signed-off-by: Petr Vyazovetskiy <develop.pit@gmail.com>
This commit is contained in:
parent
423d6f044a
commit
bbe4a3a6d6
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -36,4 +36,4 @@
|
||||
"StatusCategory": "Categoría de estado",
|
||||
"Account": "Cuenta"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,4 +36,4 @@
|
||||
"StatusCategory": "Categoria de estado",
|
||||
"Account": "Conta"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
@ -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,
|
||||
|
7
packages/rank/.eslintrc.js
Normal file
7
packages/rank/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
4
packages/rank/config/rig.json
Normal file
4
packages/rank/config/rig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
"rigPackageName": "@hcengineering/platform-rig"
|
||||
}
|
7
packages/rank/jest.config.js
Normal file
7
packages/rank/jest.config.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
|
||||
roots: ["./src"],
|
||||
coverageReporters: ["text-summary", "html"]
|
||||
}
|
38
packages/rank/package.json
Normal file
38
packages/rank/package.json
Normal 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"
|
||||
}
|
||||
}
|
@ -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'
|
21
packages/rank/src/types.ts
Normal file
21
packages/rank/src/types.ts
Normal 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
|
42
packages/rank/src/utils.ts
Normal file
42
packages/rank/src/utils.ts
Normal 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()
|
||||
}
|
10
packages/rank/tsconfig.json
Normal file
10
packages/rank/tsconfig.json
Normal 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"
|
||||
}
|
||||
}
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
@ -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: [],
|
||||
|
@ -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: [],
|
||||
|
@ -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]
|
||||
)
|
||||
|
||||
|
@ -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: '',
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 })
|
||||
|
@ -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": {
|
||||
|
@ -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'
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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,
|
||||
|
@ -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, {
|
||||
|
@ -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,
|
||||
|
@ -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}`
|
||||
},
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user