From 9d52ddbbea18eb6b14d5cc38fafba340d895225e Mon Sep 17 00:00:00 2001 From: Eduard Aksamitov Date: Fri, 22 Mar 2024 11:37:24 +0300 Subject: [PATCH] feat(planner): drag-n-drop (#5031) Signed-off-by: Eduard Aksamitov --- models/time/package.json | 3 +- models/time/src/index.ts | 24 +++- models/time/src/migration.ts | 47 ++++++- packages/theme/styles/components.scss | 20 ++- plugins/document-resources/package.json | 1 + .../node-view/ToDoItemNodeView.svelte | 20 ++- .../src/components/CreateToDo.svelte | 33 +++-- .../src/components/CreateToDoPopup.svelte | 28 +++-- .../src/components/PlanView.svelte | 36 +++--- .../src/components/PlanningCalendar.svelte | 8 +- .../src/components/ToDoDraggable.svelte | 113 +++++++++++++++++ .../src/components/ToDoElement.svelte | 39 +++--- .../src/components/ToDoGroup.svelte | 116 ++++++++++-------- .../src/components/ToDoProjectGroup.svelte | 90 ++++++++++++++ .../src/components/ToDos.svelte | 50 +++++--- plugins/time-resources/src/dragging.ts | 23 ++++ plugins/time/package.json | 3 +- plugins/time/src/index.ts | 2 + server-plugins/time-resources/src/index.ts | 20 ++- 19 files changed, 534 insertions(+), 142 deletions(-) create mode 100644 plugins/time-resources/src/components/ToDoDraggable.svelte create mode 100644 plugins/time-resources/src/components/ToDoProjectGroup.svelte create mode 100644 plugins/time-resources/src/dragging.ts diff --git a/models/time/package.json b/models/time/package.json index 13f5b05b1c..32b180873c 100644 --- a/models/time/package.json +++ b/models/time/package.json @@ -50,6 +50,7 @@ "@hcengineering/notification": "^0.6.16", "@hcengineering/model-tracker": "^0.6.0", "@hcengineering/time": "^0.6.0", - "@hcengineering/time-resources": "^0.6.0" + "@hcengineering/time-resources": "^0.6.0", + "@hcengineering/rank": "^0.6.0" } } diff --git a/models/time/src/index.ts b/models/time/src/index.ts index 1c5f9ac74d..d54eed4d3a 100644 --- a/models/time/src/index.ts +++ b/models/time/src/index.ts @@ -26,10 +26,23 @@ import { type Space, type Timestamp, type Type, - DateRangeMode + DateRangeMode, + IndexKind } from '@hcengineering/core' import lead from '@hcengineering/lead' -import { Collection, Mixin, Model, Prop, TypeRef, TypeString, UX, type Builder, TypeDate } from '@hcengineering/model' +import { + Collection, + Mixin, + Model, + Prop, + TypeRef, + TypeString, + UX, + type Builder, + TypeDate, + Hidden, + Index +} from '@hcengineering/model' import { TEvent } from '@hcengineering/model-calendar' import core, { TAttachedDoc, TClass, TDoc, TType } from '@hcengineering/model-core' import tracker from '@hcengineering/model-tracker' @@ -51,7 +64,8 @@ import { type WorkSlot } from '@hcengineering/time' -import { type Resource } from '@hcengineering/platform' +import type { Resource } from '@hcengineering/platform' +import type { Rank } from '@hcengineering/task' import time from './plugin' import task from '@hcengineering/task' @@ -107,6 +121,10 @@ export class TToDO extends TAttachedDoc implements ToDo { @Prop(Collection(tags.class.TagReference, tags.string.TagLabel), tags.string.Tags) labels?: number | undefined + + @Index(IndexKind.Indexed) + @Hidden() + rank!: Rank } @Model(time.class.ProjectToDo, time.class.ToDo) diff --git a/models/time/src/migration.ts b/models/time/src/migration.ts index d1d4e7efcd..70dd0ed7e8 100644 --- a/models/time/src/migration.ts +++ b/models/time/src/migration.ts @@ -14,13 +14,14 @@ // import { type PersonAccount } from '@hcengineering/contact' -import { type Account, type Doc, type Ref, TxOperations } from '@hcengineering/core' +import { type Account, type Doc, type Ref, SortingOrder, TxOperations } from '@hcengineering/core' import { type MigrateOperation, type MigrationClient, type MigrationUpgradeClient, createOrUpdate } from '@hcengineering/model' +import { makeRank } from '@hcengineering/rank' import core from '@hcengineering/model-core' import task from '@hcengineering/task' import tags from '@hcengineering/tags' @@ -37,12 +38,14 @@ export async function migrateWorkSlots (client: TxOperations): Promise { const now = Date.now() const todos = new Map, Ref>() const count = new Map, number>() + let rank = makeRank(undefined, undefined) for (const oldWorkSlot of oldWorkSlots) { const todo = todos.get(oldWorkSlot.attachedTo) if (todo === undefined) { const acc = oldWorkSlot.space.replace('_calendar', '') as Ref const account = (await client.findOne(core.class.Account, { _id: acc })) as PersonAccount if (account.person !== undefined) { + rank = makeRank(undefined, rank) const todo = await client.addCollection( time.class.ProjectToDo, time.space.ToDos, @@ -57,7 +60,8 @@ export async function migrateWorkSlots (client: TxOperations): Promise { workslots: 0, priority: ToDoPriority.NoPriority, user: account.person, - visibility: 'public' + visibility: 'public', + rank } ) await client.update(oldWorkSlot, { @@ -105,6 +109,44 @@ async function migrateTodosSpace (client: TxOperations): Promise { } } +async function migrateTodosRanks (client: TxOperations): Promise { + const doneTodos = await client.findAll( + time.class.ToDo, + { + rank: { $exists: false }, + doneOn: null + }, + { + sort: { modifiedOn: SortingOrder.Ascending } + } + ) + let doneTodoRank = makeRank(undefined, undefined) + for (const todo of doneTodos) { + await client.update(todo, { + rank: doneTodoRank + }) + doneTodoRank = makeRank(undefined, doneTodoRank) + } + + const undoneTodos = await client.findAll( + time.class.ToDo, + { + rank: { $exists: false }, + doneOn: { $ne: null } + }, + { + sort: { doneOn: SortingOrder.Ascending } + } + ) + let undoneTodoRank = makeRank(undefined, undefined) + for (const todo of undoneTodos) { + await client.update(todo, { + rank: undoneTodoRank + }) + undoneTodoRank = makeRank(undefined, undoneTodoRank) + } +} + async function createDefaultSpace (tx: TxOperations): Promise { const current = await tx.findOne(core.class.Space, { _id: time.space.ToDos @@ -161,5 +203,6 @@ export const timeOperation: MigrateOperation = { ) await migrateWorkSlots(tx) await migrateTodosSpace(tx) + await migrateTodosRanks(tx) } } diff --git a/packages/theme/styles/components.scss b/packages/theme/styles/components.scss index a73ec4643b..93fee71c41 100644 --- a/packages/theme/styles/components.scss +++ b/packages/theme/styles/components.scss @@ -457,7 +457,7 @@ } } &.large { - padding: var(--spacing-2) var(--spacing-1_5) var(--spacing-1) var(--spacing-2); + padding: var(--spacing-2) var(--spacing-1_5) var(--spacing-2) var(--spacing-2); min-height: var(--global-extra-large-Size); .hulyAccordionItem-header__label-wrapper { @@ -526,6 +526,23 @@ } } +.hulyToDoLine-draggable { + position: relative; + + &.is-dragging-over-up::before { + position: absolute; + content: ''; + inset: 0; + border-top: 1px solid var(--global-focus-BorderColor); + } + &.is-dragging-over-down::before { + position: absolute; + content: ''; + inset: 0; + border-bottom: 1px solid var(--global-focus-BorderColor); + } +} + /* ToDo Line */ .hulyToDoLine-container { display: flex; @@ -567,6 +584,7 @@ color: inherit; border: none; outline: none; + cursor: grab; &.isNew::after { position: absolute; diff --git a/plugins/document-resources/package.json b/plugins/document-resources/package.json index 36990031e6..2fc366d096 100644 --- a/plugins/document-resources/package.json +++ b/plugins/document-resources/package.json @@ -60,6 +60,7 @@ "@hcengineering/workbench": "^0.6.9", "@hcengineering/document": "^0.6.0", "@hcengineering/time": "^0.6.0", + "@hcengineering/rank": "^0.6.0", "@tiptap/core": "^2.1.12", "slugify": "^1.6.6" } diff --git a/plugins/document-resources/src/components/node-view/ToDoItemNodeView.svelte b/plugins/document-resources/src/components/node-view/ToDoItemNodeView.svelte index 1a479f137e..cf15fa7099 100644 --- a/plugins/document-resources/src/components/node-view/ToDoItemNodeView.svelte +++ b/plugins/document-resources/src/components/node-view/ToDoItemNodeView.svelte @@ -1,11 +1,12 @@ + + +
+ +
diff --git a/plugins/time-resources/src/components/ToDoElement.svelte b/plugins/time-resources/src/components/ToDoElement.svelte index 1ae2055174..cfe324662c 100644 --- a/plugins/time-resources/src/components/ToDoElement.svelte +++ b/plugins/time-resources/src/components/ToDoElement.svelte @@ -1,3 +1,17 @@ + {#if showTitle} @@ -68,7 +97,7 @@ bottomSpace={false} counter={todos.length} duration={showDuration} - isOpen + isOpen={title !== time.string.Done} fixHeader background={'var(--theme-navpanel-color)'} > @@ -77,48 +106,31 @@ {#if groups} {#each groups as group} - - {#each todos.filter((td) => td.attachedSpace === group._id) as todo} - -
dispatch('dragstart', todo)}> - -
- {/each} -
+ td.attachedSpace === group._id)} + project={group} + groupName={title} + {largeSize} + {mode} + /> {/each} {/if} {#if withoutProject} - - {#each todos.filter((td) => !hasProject(td.attachedSpace)) as todo} - -
dispatch('dragstart', todo)}> - -
- {/each} -
+ !hasProject(td.attachedSpace))} + project={false} + groupName={title} + {largeSize} + {mode} + /> {/if} {:else}
- {#each todos as todo} - -
dispatch('dragstart', todo)}> + {#each todos as todo, index} + -
+ {/each}
{/if} diff --git a/plugins/time-resources/src/components/ToDoProjectGroup.svelte b/plugins/time-resources/src/components/ToDoProjectGroup.svelte new file mode 100644 index 0000000000..0a7d9be402 --- /dev/null +++ b/plugins/time-resources/src/components/ToDoProjectGroup.svelte @@ -0,0 +1,90 @@ + + + + + + {#each todos as todo, index} + + + + {/each} + diff --git a/plugins/time-resources/src/components/ToDos.svelte b/plugins/time-resources/src/components/ToDos.svelte index 3dc88d088d..bfcf018a02 100644 --- a/plugins/time-resources/src/components/ToDos.svelte +++ b/plugins/time-resources/src/components/ToDos.svelte @@ -1,21 +1,39 @@ + +