feat: collection move
Some checks failed
JS Unit Tests / test (pull_request) Failing after 26s
Build Test / test (pull_request) Successful in 32s
PHP Unit Tests / test (pull_request) Successful in 53s

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-05-06 12:03:05 -04:00
parent 9b6823c481
commit fbc8ac2d7e
5 changed files with 117 additions and 11 deletions

View File

@@ -17,6 +17,8 @@ import type {
CollectionDeleteResponse,
CollectionDeleteRequest,
CollectionInterface,
CollectionMoveRequest,
CollectionMoveResponse,
} from '../types/collection';
import { useIntegrationStore } from '@KTXC/stores/integrationStore';
import { CollectionObject, CollectionPropertiesObject } from '../models/collection';
@@ -132,6 +134,18 @@ export const collectionService = {
return true;
},
/**
* Move a collection to a new target collection
*
* @param request - move request parameters
*
* @returns Promise with moved collection object
*/
async move(request: CollectionMoveRequest): Promise<CollectionObject> {
const response = await transceivePost<CollectionMoveRequest, CollectionMoveResponse>('collection.move', request);
return createCollectionObject(response);
}
};
export default collectionService;

View File

@@ -4,9 +4,9 @@
import { ref, computed, readonly } from 'vue'
import { defineStore } from 'pinia'
import { collectionService } from '../services'
import { collectionService, entityService } from '../services'
import { CollectionObject, CollectionPropertiesObject } from '../models/collection'
import type { SourceSelector, ListFilter, ListSort } from '../types'
import type { SourceSelector, ListFilter, ListSort, CollectionIdentifier, CollectionMoveResponse } from '../types'
export const useCollectionsStore = defineStore('mailCollectionsStore', () => {
const ROOT_IDENTIFIER = '__root__'
@@ -425,6 +425,51 @@ export const useCollectionsStore = defineStore('mailCollectionsStore', () => {
}
}
/**
* Move collections to another target collection.
*
* Updates local store keys for successfully moved collections when they are
* already present in cache.
*
* @param target - target collection identifier
* @param source - source collection identifier
*
* @returns Promise with move results keyed by source identifier
*/
async function move(target: CollectionIdentifier, source: CollectionIdentifier): Promise<CollectionObject> {
transceiving.value = true
try {
const response = await collectionService.move({ target, source })
if (!(response instanceof CollectionObject)) {
console.warn('[Mail Manager][Store] - Move failed. Received unexpected response from move operation:', response)
throw new Error('Failed to move collection: unexpected response from move operation')
}
const sourceCollection = _collections.value[source]
if (sourceCollection) {
deindexCollection(sourceCollection)
}
delete _collections.value[source]
const movedCollection = response
const movedKey = identifierKey(movedCollection.provider, movedCollection.service, movedCollection.identifier)
_collections.value[movedKey] = movedCollection
indexCollection(movedCollection)
console.debug('[Mail Manager][Store] - Successfully moved collection:', source, ' to ', movedKey)
return response
} catch (error: any) {
console.error('[Mail Manager][Store] - Failed to move collection:', error)
throw error
} finally {
transceiving.value = false
}
}
// Return public API
return {
// State (readonly)
@@ -445,5 +490,6 @@ export const useCollectionsStore = defineStore('mailCollectionsStore', () => {
create,
update,
delete: remove,
move,
}
})

View File

@@ -1,7 +1,7 @@
/**
* Collection type definitions
*/
import type { ListFilter, ListSort, SourceSelector } from './common';
import type { CollectionIdentifier, ListFilter, ListSort, SourceSelector } from './common';
/**
* Collection information
@@ -119,7 +119,6 @@ export interface CollectionDeleteRequest {
identifier: string | number;
options?: {
force?: boolean; // Whether to force delete even if collection is not empty
recursive?: boolean; // Whether to delete child collections/items as well
};
}
@@ -127,3 +126,13 @@ export interface CollectionDeleteResponse {
outcome: 'deleted' | 'moved';
data?: CollectionInterface | null; // If moved, the new location of the collection
}
/**
* Collection move
*/
export interface CollectionMoveRequest {
target: CollectionIdentifier;
source: CollectionIdentifier;
}
export interface CollectionMoveResponse extends CollectionInterface {};