diff --git a/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.spec.ts b/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.spec.ts index 7549ea1323..9636023429 100644 --- a/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.spec.ts +++ b/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.spec.ts @@ -559,19 +559,19 @@ describe('BulkEditorComponent', () => { let req = httpTestingController.expectOne( `${environment.apiBaseUrl}documents/bulk_edit/` ) - req.flush(true) + req.flush({ result: 'OK', task_id: 'queued-task' }) expect(req.request.body).toEqual({ from_webui: true, documents: [3, 4], method: 'modify_tags', parameters: { add_tags: [101], remove_tags: [] }, }) - httpTestingController.match( + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload - httpTestingController.match( + ) + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id` - ) // listAllFilteredIds + ) }) it('should execute modify tags bulk operation for all filtered documents', () => { @@ -608,7 +608,7 @@ describe('BulkEditorComponent', () => { const req = httpTestingController.expectOne( `${environment.apiBaseUrl}documents/bulk_edit/` ) - req.flush(true) + req.flush({ result: 'OK', task_id: 'queued-task' }) expect(req.request.body).toEqual({ from_webui: true, all: true, @@ -617,9 +617,9 @@ describe('BulkEditorComponent', () => { method: 'modify_tags', parameters: { add_tags: [101], remove_tags: [] }, }) - httpTestingController.match( + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload + ) }) it('should execute modify tags bulk operation with confirmation dialog if enabled', () => { @@ -646,12 +646,12 @@ describe('BulkEditorComponent', () => { httpTestingController .expectOne(`${environment.apiBaseUrl}documents/bulk_edit/`) .flush(true) - httpTestingController.match( + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload - httpTestingController.match( + ) + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id` - ) // listAllFilteredIds + ) }) it('should set modal dialog text accordingly for tag edit confirmation', () => { @@ -731,19 +731,19 @@ describe('BulkEditorComponent', () => { let req = httpTestingController.expectOne( `${environment.apiBaseUrl}documents/bulk_edit/` ) - req.flush(true) + req.flush({ result: 'OK', task_id: 'queued-task' }) expect(req.request.body).toEqual({ from_webui: true, documents: [3, 4], method: 'set_correspondent', parameters: { correspondent: 101 }, }) - httpTestingController.match( + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload - httpTestingController.match( + ) + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id` - ) // listAllFilteredIds + ) }) it('should execute modify correspondent bulk operation with confirmation dialog if enabled', () => { @@ -770,12 +770,12 @@ describe('BulkEditorComponent', () => { httpTestingController .expectOne(`${environment.apiBaseUrl}documents/bulk_edit/`) .flush(true) - httpTestingController.match( + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload - httpTestingController.match( + ) + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id` - ) // listAllFilteredIds + ) }) it('should set modal dialog text accordingly for correspondent edit confirmation', () => { @@ -830,19 +830,19 @@ describe('BulkEditorComponent', () => { let req = httpTestingController.expectOne( `${environment.apiBaseUrl}documents/bulk_edit/` ) - req.flush(true) + req.flush({ result: 'OK', task_id: 'queued-task' }) expect(req.request.body).toEqual({ from_webui: true, documents: [3, 4], method: 'set_document_type', parameters: { document_type: 101 }, }) - httpTestingController.match( + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload - httpTestingController.match( + ) + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id` - ) // listAllFilteredIds + ) }) it('should execute modify document type bulk operation with confirmation dialog if enabled', () => { @@ -869,12 +869,12 @@ describe('BulkEditorComponent', () => { httpTestingController .expectOne(`${environment.apiBaseUrl}documents/bulk_edit/`) .flush(true) - httpTestingController.match( + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload - httpTestingController.match( + ) + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id` - ) // listAllFilteredIds + ) }) it('should set modal dialog text accordingly for document type edit confirmation', () => { @@ -929,19 +929,19 @@ describe('BulkEditorComponent', () => { let req = httpTestingController.expectOne( `${environment.apiBaseUrl}documents/bulk_edit/` ) - req.flush(true) + req.flush({ result: 'OK', task_id: 'queued-task' }) expect(req.request.body).toEqual({ from_webui: true, documents: [3, 4], method: 'set_storage_path', parameters: { storage_path: 101 }, }) - httpTestingController.match( + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload - httpTestingController.match( + ) + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id` - ) // listAllFilteredIds + ) }) it('should execute modify storage path bulk operation with confirmation dialog if enabled', () => { @@ -968,12 +968,12 @@ describe('BulkEditorComponent', () => { httpTestingController .expectOne(`${environment.apiBaseUrl}documents/bulk_edit/`) .flush(true) - httpTestingController.match( + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload - httpTestingController.match( + ) + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id` - ) // listAllFilteredIds + ) }) it('should set modal dialog text accordingly for storage path edit confirmation', () => { @@ -1028,19 +1028,19 @@ describe('BulkEditorComponent', () => { let req = httpTestingController.expectOne( `${environment.apiBaseUrl}documents/bulk_edit/` ) - req.flush(true) + req.flush({ result: 'OK', task_id: 'queued-task' }) expect(req.request.body).toEqual({ from_webui: true, documents: [3, 4], method: 'modify_custom_fields', parameters: { add_custom_fields: [101], remove_custom_fields: [102] }, }) - httpTestingController.match( + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload - httpTestingController.match( + ) + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id` - ) // listAllFilteredIds + ) }) it('should execute modify custom fields bulk operation with confirmation dialog if enabled', () => { @@ -1067,12 +1067,12 @@ describe('BulkEditorComponent', () => { httpTestingController .expectOne(`${environment.apiBaseUrl}documents/bulk_edit/`) .flush(true) - httpTestingController.match( + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload - httpTestingController.match( + ) + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id` - ) // listAllFilteredIds + ) // coverage for modal messages component.setCustomFields({ @@ -1175,18 +1175,18 @@ describe('BulkEditorComponent', () => { const notifySpy = jest .spyOn(trashService, 'notifyMovedToTrash') .mockImplementation(() => {}) - req.flush(true) + req.flush({ result: 'OK', task_id: 'queued-task' }) expect(req.request.body).toEqual({ from_webui: true, documents: [3, 4], }) - expect(notifySpy).toHaveBeenCalledWith(expect.any(String), [3, 4]) - httpTestingController.match( + expect(notifySpy).not.toHaveBeenCalled() + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload - httpTestingController.match( + ) + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id` - ) // listAllFilteredIds + ) component.showConfirmationDialogs = false fixture.detectChanges() @@ -1197,12 +1197,12 @@ describe('BulkEditorComponent', () => { req = httpTestingController.expectOne( `${environment.apiBaseUrl}documents/delete/` ) - req.flush(true) - // ids aren't known when all matching documents are selected, so no undo - expect(notifySpy).toHaveBeenLastCalledWith(expect.any(String), null) - httpTestingController.match( + req.flush({ result: 'OK', task_id: 'queued-task' }) + // Acceptance does not claim deletion has completed. + expect(notifySpy).not.toHaveBeenCalled() + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload + ) }) it('should not be accessible with insufficient global permissions', () => { @@ -1601,7 +1601,7 @@ describe('BulkEditorComponent', () => { let req = httpTestingController.expectOne( `${environment.apiBaseUrl}documents/bulk_edit/` ) - req.flush(true) + req.flush({ result: 'OK', task_id: 'queued-task' }) expect(req.request.body).toEqual({ from_webui: true, documents: [3, 4], @@ -1611,12 +1611,12 @@ describe('BulkEditorComponent', () => { merge: true, }, }) - httpTestingController.match( + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload - httpTestingController.match( + ) + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id` - ) // listAllFilteredIds + ) }) it('should not attempt to retrieve objects if user does not have permissions', () => { @@ -1917,15 +1917,18 @@ describe('BulkEditorComponent', () => { expect(toastServiceShowErrorSpy).toHaveBeenCalled() expect(listReloadSpy).not.toHaveBeenCalled() - modal.componentInstance.succeeded.emit() - expect(toastServiceShowInfoSpy).toHaveBeenCalled() - expect(listReloadSpy).toHaveBeenCalled() - httpTestingController.match( + modal.componentInstance.succeeded.emit({ + result: 'OK', + task_id: 'custom-fields-task', + }) + expect(toastServiceShowInfoSpy).not.toHaveBeenCalled() + expect(listReloadSpy).not.toHaveBeenCalled() + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true` - ) // list reload - httpTestingController.match( + ) + httpTestingController.expectNone( `${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id` - ) // listAllFilteredIds + ) }) it('should create share link bundle and enable manage callback', () => { diff --git a/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.ts b/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.ts index dda5249754..73c166be5f 100644 --- a/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.ts +++ b/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.ts @@ -49,7 +49,6 @@ import { StoragePathService } from 'src/app/services/rest/storage-path.service' import { TagService } from 'src/app/services/rest/tag.service' import { SettingsService } from 'src/app/services/settings.service' import { ToastService } from 'src/app/services/toast.service' -import { TrashService } from 'src/app/services/trash.service' import { flattenTags } from 'src/app/utils/flatten-tags' import { queryParamsFromFilterRules } from 'src/app/utils/query-params' import { MergeAsVersionsConfirmDialogComponent } from '../../common/confirm-dialog/merge-as-versions-confirm-dialog/merge-as-versions-confirm-dialog.component' @@ -100,7 +99,6 @@ export class BulkEditorComponent private openDocumentService = inject(OpenDocumentsService) private settings = inject(SettingsService) private toastService = inject(ToastService) - private trashService = inject(TrashService) private storagePathService = inject(StoragePathService) private customFieldService = inject(CustomFieldsService) public readonly permissionService = inject(PermissionsService) @@ -291,18 +289,16 @@ export class BulkEditorComponent .bulkEdit(overrideSelection ?? this.getSelectionQuery(), method, args) .pipe(first()) .subscribe({ - next: (response) => { - if (response.task_id) { - modal?.close() - this.list.selectNone() - } else { - this.handleOperationSuccess(modal) - } - }, + next: () => this.handleOperationQueued(modal), error: (error) => this.handleOperationError(modal, error), }) } + private handleOperationQueued(modal: NgbModalRef) { + modal?.close() + this.list.selectNone() + } + private executeDocumentAction( modal: NgbModalRef, request: Observable, @@ -901,28 +897,11 @@ export class BulkEditorComponent } private deleteSelected(modal: NgbModalRef) { - const documents = this.list.allSelected - ? null - : Array.from(this.list.selected) - const count = this.getSelectionSize() this.documentService .deleteDocuments(this.getSelectionQuery()) .pipe(first()) .subscribe({ - next: (response) => { - const completed = () => - this.trashService.notifyMovedToTrash( - $localize`Moved ${count} document(s) to the trash`, - documents - ) - if (response.task_id) { - modal?.close() - this.list.selectNone() - } else { - this.handleOperationSuccess(modal) - completed() - } - }, + next: () => this.handleOperationQueued(modal), error: (error) => this.handleOperationError(modal, error), }) } @@ -1094,14 +1073,7 @@ export class BulkEditorComponent dialog.selection = this.getSelectionQuery() dialog.selectionCount = this.getSelectionSize() - dialog.succeeded.subscribe((result) => { - if (result?.task_id) { - this.list.selectNone() - } else { - this.toastService.showSuccess($localize`Custom fields updated.`) - this.handleOperationSuccess(null) - } - }) + dialog.succeeded.subscribe(() => this.handleOperationQueued(null)) dialog.failed.subscribe((error) => { this.toastService.showError( $localize`Error updating custom fields.`, diff --git a/src-ui/src/app/components/document-list/bulk-editor/custom-fields-bulk-edit-dialog/custom-fields-bulk-edit-dialog.component.spec.ts b/src-ui/src/app/components/document-list/bulk-editor/custom-fields-bulk-edit-dialog/custom-fields-bulk-edit-dialog.component.spec.ts index 01865e5311..064961058d 100644 --- a/src-ui/src/app/components/document-list/bulk-editor/custom-fields-bulk-edit-dialog/custom-fields-bulk-edit-dialog.component.spec.ts +++ b/src-ui/src/app/components/document-list/bulk-editor/custom-fields-bulk-edit-dialog/custom-fields-bulk-edit-dialog.component.spec.ts @@ -59,7 +59,7 @@ describe('CustomFieldsBulkEditDialogComponent', () => { it('should emit succeeded event and close modal on successful save', () => { const editSpy = jest .spyOn(documentService, 'bulkEdit') - .mockReturnValue(of('Success')) + .mockReturnValue(of({ result: 'OK', task_id: 'custom-fields-task' })) const successSpy = jest.spyOn(component.succeeded, 'emit') component.selection = [1, 2] diff --git a/src-ui/src/app/components/document-list/bulk-editor/custom-fields-bulk-edit-dialog/custom-fields-bulk-edit-dialog.component.ts b/src-ui/src/app/components/document-list/bulk-editor/custom-fields-bulk-edit-dialog/custom-fields-bulk-edit-dialog.component.ts index 920d8cadca..67ce981417 100644 --- a/src-ui/src/app/components/document-list/bulk-editor/custom-fields-bulk-edit-dialog/custom-fields-bulk-edit-dialog.component.ts +++ b/src-ui/src/app/components/document-list/bulk-editor/custom-fields-bulk-edit-dialog/custom-fields-bulk-edit-dialog.component.ts @@ -16,6 +16,7 @@ import { NumberComponent } from 'src/app/components/common/input/number/number.c import { SelectComponent } from 'src/app/components/common/input/select/select.component' import { TextComponent } from 'src/app/components/common/input/text/text.component' import { UrlComponent } from 'src/app/components/common/input/url/url.component' +import { BulkOperationResponse } from 'src/app/data/bulk-operation' import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field' import { DocumentSelectionQuery, @@ -49,7 +50,7 @@ export class CustomFieldsBulkEditDialogComponent { CustomFieldDataType = CustomFieldDataType @Output() - succeeded = new EventEmitter() + succeeded = new EventEmitter() @Output() failed = new EventEmitter() diff --git a/src-ui/src/app/data/bulk-operation.ts b/src-ui/src/app/data/bulk-operation.ts index 0728a12e5b..5619a1bfba 100644 --- a/src-ui/src/app/data/bulk-operation.ts +++ b/src-ui/src/app/data/bulk-operation.ts @@ -1,4 +1,4 @@ export interface BulkOperationResponse { result: string - task_id?: string + task_id: string }