From fa82ee193994b89d4ddc5b5304e9d3eb96673978 Mon Sep 17 00:00:00 2001 From: Alexander Onnikov Date: Mon, 8 Jul 2024 16:10:42 +0700 Subject: [PATCH] UBERF-7524 Move files and folders in drive (#6016) Signed-off-by: Alexander Onnikov --- models/drive/src/index.ts | 36 +++++- models/drive/src/plugin.ts | 1 + .../src/components/CreateFolder.svelte | 3 - .../src/components/MoveResource.svelte | 107 ++++++++++++++++++ plugins/drive-resources/src/index.ts | 2 + plugins/drive-resources/src/utils.ts | 32 ++++++ 6 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 plugins/drive-resources/src/components/MoveResource.svelte diff --git a/models/drive/src/index.ts b/models/drive/src/index.ts index c2b56aed21..293728896e 100644 --- a/models/drive/src/index.ts +++ b/models/drive/src/index.ts @@ -45,7 +45,7 @@ import { import { TDoc, TTypedSpace } from '@hcengineering/model-core' import print from '@hcengineering/model-print' import tracker from '@hcengineering/model-tracker' -import view, { type Viewlet, createAction } from '@hcengineering/model-view' +import view, { type Viewlet, actionTemplates, createAction } from '@hcengineering/model-view' import workbench from '@hcengineering/model-workbench' import { getEmbeddedLabel } from '@hcengineering/platform' @@ -410,6 +410,23 @@ function defineFolder (builder: Builder): void { }, drive.action.RenameFolder ) + + createAction(builder, { + ...actionTemplates.move, + action: view.actionImpl.ShowPopup, + actionProps: { + component: drive.component.MoveResource, + element: 'top', + fillProps: { + _object: 'value' + } + }, + target: drive.class.Folder, + context: { + mode: ['browser', 'context'], + group: 'tools' + } + }) } function defineFile (builder: Builder): void { @@ -488,6 +505,23 @@ function defineFile (builder: Builder): void { }, drive.action.RenameFile ) + + createAction(builder, { + ...actionTemplates.move, + action: view.actionImpl.ShowPopup, + actionProps: { + component: drive.component.MoveResource, + element: 'top', + fillProps: { + _object: 'value' + } + }, + target: drive.class.File, + context: { + mode: ['browser', 'context'], + group: 'tools' + } + }) } function defineApplication (builder: Builder): void { diff --git a/models/drive/src/plugin.ts b/models/drive/src/plugin.ts index 3d23b41053..74020eb196 100644 --- a/models/drive/src/plugin.ts +++ b/models/drive/src/plugin.ts @@ -43,6 +43,7 @@ export default mergeIds(driveId, drive, { FolderPresenter: '' as AnyComponent, FilePresenter: '' as AnyComponent, FileSizePresenter: '' as AnyComponent, + MoveResource: '' as AnyComponent, ResourcePresenter: '' as AnyComponent }, function: { diff --git a/plugins/drive-resources/src/components/CreateFolder.svelte b/plugins/drive-resources/src/components/CreateFolder.svelte index e386281434..7ca2bbceb9 100644 --- a/plugins/drive-resources/src/components/CreateFolder.svelte +++ b/plugins/drive-resources/src/components/CreateFolder.svelte @@ -113,9 +113,6 @@ allowDeselect showNavigate={false} docProps={{ disabled: true, noUnderline: true }} - on:object={(evt) => { - console.log('selected', evt) - }} /> diff --git a/plugins/drive-resources/src/components/MoveResource.svelte b/plugins/drive-resources/src/components/MoveResource.svelte new file mode 100644 index 0000000000..93c8056b47 --- /dev/null +++ b/plugins/drive-resources/src/components/MoveResource.svelte @@ -0,0 +1,107 @@ + + + + dispatch('close')} + on:changeContent +> + + + + +
+ { + parent = drive.ids.Root + }} + /> + +
+
diff --git a/plugins/drive-resources/src/index.ts b/plugins/drive-resources/src/index.ts index 4117cfcb0c..b1941a4f3e 100644 --- a/plugins/drive-resources/src/index.ts +++ b/plugins/drive-resources/src/index.ts @@ -32,6 +32,7 @@ import FileSizePresenter from './components/FileSizePresenter.svelte' import FolderPanel from './components/FolderPanel.svelte' import FolderPresenter from './components/FolderPresenter.svelte' import GridView from './components/GridView.svelte' +import MoveResource from './components/MoveResource.svelte' import ResourcePresenter from './components/ResourcePresenter.svelte' import { getDriveLink, getFileLink, getFolderLink, resolveLocation } from './navigation' @@ -109,6 +110,7 @@ export default async (): Promise => ({ FolderPanel, FolderPresenter, GridView, + MoveResource, ResourcePresenter }, actionImpl: { diff --git a/plugins/drive-resources/src/utils.ts b/plugins/drive-resources/src/utils.ts index 8b3cce5844..21d198831f 100644 --- a/plugins/drive-resources/src/utils.ts +++ b/plugins/drive-resources/src/utils.ts @@ -98,6 +98,38 @@ export async function renameResource (resource: Resource): Promise { }) } +export async function moveResources (resources: Resource[], space: Ref, parent: Ref): Promise { + const client = getClient() + + const folder = parent !== drive.ids.Root ? await client.findOne(drive.class.Folder, { _id: parent }) : undefined + + const path = folder !== undefined ? [folder._id, ...folder.path] : [] + + const folders = resources.filter((p) => p._class === drive.class.Folder).map((p) => p._id) + const children = await client.findAll(drive.class.Resource, { path: { $in: folders } }) + const byParent = new Map, Resource[]>() + for (const child of children) { + const group = byParent.get(child.parent) ?? [] + group.push(child) + byParent.set(child.parent, group) + } + + const ops = client.apply(parent) + + for (const resource of resources) { + await ops.update(resource, { space, parent, path }) + + const children = byParent.get(resource._id) ?? [] + for (const child of children) { + // remove old path and add new path + const childPath = [...child.path.filter((p) => !resource.path.includes(p)), ...path] + await ops.update(child, { space, path: childPath }) + } + } + + await ops.commit() +} + const fileTypesMap: Record = { 'application/pdf': FileTypePdf, audio: FileTypeAudio,