mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2026-09-09 18:02:54 +00:00
[ACS-12332] Add checkout and cancel-checkout node support (#5334)
* [ACS-12332] Add checkout and cancel-checkout node support * [ACS-12332] cr fix
This commit is contained in:
@@ -743,5 +743,21 @@
|
||||
"TITLE": "AI Agents",
|
||||
"DISCOVERY": "Discovery"
|
||||
}
|
||||
},
|
||||
"CHECKOUT": {
|
||||
"ERRORS": {
|
||||
"CHECKOUT": {
|
||||
"400": "This node cannot be checked out. It must be a content (cm:content) node.",
|
||||
"403": "You do not have permission to check out this node.",
|
||||
"409": "This node is already checked out or locked by another user."
|
||||
},
|
||||
"CANCEL_CHECKOUT": {
|
||||
"400": "Checkout cannot be cancelled. The node is not a content node or is not currently checked out.",
|
||||
"403": "You do not have permission to cancel the checkout for this node.",
|
||||
"409": "Failed to cancel checkout. Please try again or contact your IT team."
|
||||
},
|
||||
"404": "Node not found.",
|
||||
"UNKNOWN": "An unexpected error occurred. Please try again or contact your IT team."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2410,4 +2410,91 @@ describe('ContentManagementService', () => {
|
||||
expect(showErrorSpy).toHaveBeenCalledWith('APP.MESSAGES.ERRORS.GENERIC');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Checkout operations', () => {
|
||||
const nodeId = 'fake-node-id';
|
||||
const makeApiError = (statusCode: number): Error => new Error(JSON.stringify({ error: { statusCode } }));
|
||||
|
||||
describe('checkout()', () => {
|
||||
it('should return the working copy NodeEntry on success', () => {
|
||||
const fakeEntry = { entry: { id: nodeId } } as NodeEntry;
|
||||
spyOn(nodesApiService, 'checkoutNode').and.returnValue(of(fakeEntry));
|
||||
contentManagementService.checkout(nodeId).subscribe((result) => {
|
||||
expect(nodesApiService.checkoutNode).toHaveBeenCalledWith(nodeId);
|
||||
expect(result).toEqual(fakeEntry);
|
||||
});
|
||||
});
|
||||
|
||||
it('should show 400 error notification', () => {
|
||||
spyOn(nodesApiService, 'checkoutNode').and.returnValue(throwError(() => makeApiError(400)));
|
||||
contentManagementService.checkout(nodeId).subscribe({ next: () => {} });
|
||||
expect(showErrorSpy).toHaveBeenCalledWith('CHECKOUT.ERRORS.CHECKOUT.400');
|
||||
});
|
||||
|
||||
it('should show 403 error notification', () => {
|
||||
spyOn(nodesApiService, 'checkoutNode').and.returnValue(throwError(() => makeApiError(403)));
|
||||
contentManagementService.checkout(nodeId).subscribe({ next: () => {} });
|
||||
expect(showErrorSpy).toHaveBeenCalledWith('CHECKOUT.ERRORS.CHECKOUT.403');
|
||||
});
|
||||
|
||||
it('should show 404 error notification', () => {
|
||||
spyOn(nodesApiService, 'checkoutNode').and.returnValue(throwError(() => makeApiError(404)));
|
||||
contentManagementService.checkout(nodeId).subscribe({ next: () => {} });
|
||||
expect(showErrorSpy).toHaveBeenCalledWith('CHECKOUT.ERRORS.404');
|
||||
});
|
||||
|
||||
it('should show 409 error notification', () => {
|
||||
spyOn(nodesApiService, 'checkoutNode').and.returnValue(throwError(() => makeApiError(409)));
|
||||
contentManagementService.checkout(nodeId).subscribe({ next: () => {} });
|
||||
expect(showErrorSpy).toHaveBeenCalledWith('CHECKOUT.ERRORS.CHECKOUT.409');
|
||||
});
|
||||
|
||||
it('should show UNKNOWN notification for unrecognised status code (500)', () => {
|
||||
spyOn(nodesApiService, 'checkoutNode').and.returnValue(throwError(() => makeApiError(500)));
|
||||
contentManagementService.checkout(nodeId).subscribe({ next: () => {} });
|
||||
expect(showErrorSpy).toHaveBeenCalledWith('CHECKOUT.ERRORS.UNKNOWN');
|
||||
});
|
||||
});
|
||||
|
||||
describe('cancelCheckout()', () => {
|
||||
it('should return the original NodeEntry on success', () => {
|
||||
const fakeEntry = { entry: { id: nodeId } } as NodeEntry;
|
||||
spyOn(nodesApiService, 'cancelCheckoutNode').and.returnValue(of(fakeEntry));
|
||||
contentManagementService.cancelCheckout(nodeId).subscribe((result) => {
|
||||
expect(result).toEqual(fakeEntry);
|
||||
expect(nodesApiService.cancelCheckoutNode).toHaveBeenCalledWith(nodeId);
|
||||
});
|
||||
});
|
||||
|
||||
it('should show 400 error notification', () => {
|
||||
spyOn(nodesApiService, 'cancelCheckoutNode').and.returnValue(throwError(() => makeApiError(400)));
|
||||
contentManagementService.cancelCheckout(nodeId).subscribe({ next: () => {} });
|
||||
expect(showErrorSpy).toHaveBeenCalledWith('CHECKOUT.ERRORS.CANCEL_CHECKOUT.400');
|
||||
});
|
||||
|
||||
it('should show 403 error notification', () => {
|
||||
spyOn(nodesApiService, 'cancelCheckoutNode').and.returnValue(throwError(() => makeApiError(403)));
|
||||
contentManagementService.cancelCheckout(nodeId).subscribe({ next: () => {} });
|
||||
expect(showErrorSpy).toHaveBeenCalledWith('CHECKOUT.ERRORS.CANCEL_CHECKOUT.403');
|
||||
});
|
||||
|
||||
it('should show 404 error notification', () => {
|
||||
spyOn(nodesApiService, 'cancelCheckoutNode').and.returnValue(throwError(() => makeApiError(404)));
|
||||
contentManagementService.cancelCheckout(nodeId).subscribe({ next: () => {} });
|
||||
expect(showErrorSpy).toHaveBeenCalledWith('CHECKOUT.ERRORS.404');
|
||||
});
|
||||
|
||||
it('should show 409 error notification', () => {
|
||||
spyOn(nodesApiService, 'cancelCheckoutNode').and.returnValue(throwError(() => makeApiError(409)));
|
||||
contentManagementService.cancelCheckout(nodeId).subscribe({ next: () => {} });
|
||||
expect(showErrorSpy).toHaveBeenCalledWith('CHECKOUT.ERRORS.CANCEL_CHECKOUT.409');
|
||||
});
|
||||
|
||||
it('should show UNKNOWN notification for unrecognised status code', () => {
|
||||
spyOn(nodesApiService, 'cancelCheckoutNode').and.returnValue(throwError(() => makeApiError(503)));
|
||||
contentManagementService.cancelCheckout(nodeId).subscribe({ next: () => {} });
|
||||
expect(showErrorSpy).toHaveBeenCalledWith('CHECKOUT.ERRORS.UNKNOWN');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -53,7 +53,7 @@ import { DeletedNodesPaging, Node, NodeEntry, PathInfo, SiteBodyCreate, SiteEntr
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { forkJoin, Observable, of, zip } from 'rxjs';
|
||||
import { forkJoin, Observable, of, zip, EMPTY } from 'rxjs';
|
||||
import { catchError, map, mergeMap, take, tap } from 'rxjs/operators';
|
||||
import { LinkOperationResult, NodeActionsService } from './node-actions.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
@@ -543,6 +543,35 @@ export class ContentManagementService {
|
||||
});
|
||||
}
|
||||
|
||||
checkout(nodeId: string): Observable<NodeEntry> {
|
||||
return this.nodesApiService.checkoutNode(nodeId).pipe(
|
||||
catchError((err) => {
|
||||
this.notificationService.showError(this.resolveCheckoutErrorKey(err, 'CHECKOUT'));
|
||||
return EMPTY;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
cancelCheckout(nodeId: string): Observable<NodeEntry> {
|
||||
return this.nodesApiService.cancelCheckoutNode(nodeId).pipe(
|
||||
catchError((err) => {
|
||||
this.notificationService.showError(this.resolveCheckoutErrorKey(err, 'CANCEL_CHECKOUT'));
|
||||
return EMPTY;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private resolveCheckoutErrorKey(error: Error, operation: 'CHECKOUT' | 'CANCEL_CHECKOUT'): string {
|
||||
let statusCode = -1;
|
||||
try {
|
||||
statusCode = JSON.parse(error.message).error.statusCode;
|
||||
} catch {}
|
||||
if (statusCode === 404) {
|
||||
return 'CHECKOUT.ERRORS.404';
|
||||
}
|
||||
return [400, 403, 409].includes(statusCode) ? `CHECKOUT.ERRORS.${operation}.${statusCode}` : 'CHECKOUT.ERRORS.UNKNOWN';
|
||||
}
|
||||
|
||||
private showCopyMessage(info: any, nodes: Array<NodeEntry>, newItems?: Array<NodeEntry>) {
|
||||
const succeeded = newItems?.length ?? 0;
|
||||
const failed = nodes.length - succeeded;
|
||||
|
||||
Reference in New Issue
Block a user