mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2026-09-09 18:02:54 +00:00
[ACS-12333][ACS-12335][ACS-12334] Add Checkout / Check-in Support (#5360)
Co-authored-by: Adam Świderski <adam.tomasz.swiderski@gmail.com>
This commit is contained in:
co-authored by
Adam Świderski
parent
ff7560b7fc
commit
c4f3e988c8
@@ -5,6 +5,7 @@
|
||||
}"
|
||||
[maxRetries]="settings.viewerMaxRetries"
|
||||
[nodeId]="nodeId"
|
||||
[readOnly]="node?.aspectNames?.includes('cm:checkedOut')"
|
||||
[versionId]="versionId"
|
||||
[allowNavigate]="navigateMultiple"
|
||||
[allowRightSidebar]="true"
|
||||
|
||||
@@ -24,8 +24,15 @@
|
||||
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
import { AuthenticationService } from '@alfresco/adf-core';
|
||||
import { DiscoveryApiService, DocumentListService, FileUploadCompleteEvent, NodesApiService, UploadService } from '@alfresco/adf-content-services';
|
||||
import { AuthenticationService, UnitTestingUtils } from '@alfresco/adf-core';
|
||||
import {
|
||||
AlfrescoViewerComponent,
|
||||
DiscoveryApiService,
|
||||
DocumentListService,
|
||||
FileUploadCompleteEvent,
|
||||
NodesApiService,
|
||||
UploadService
|
||||
} from '@alfresco/adf-content-services';
|
||||
import { ClosePreviewAction, RefreshPreviewAction, ViewNodeAction } from '@alfresco/aca-shared/store';
|
||||
import { AcaViewerComponent } from './viewer.component';
|
||||
import { of } from 'rxjs';
|
||||
@@ -64,6 +71,7 @@ describe('AcaViewerComponent', () => {
|
||||
let appHookService: AppHookService;
|
||||
let documentListService: DocumentListService;
|
||||
let store: Store<any>;
|
||||
let testingUtils: UnitTestingUtils;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -86,6 +94,7 @@ describe('AcaViewerComponent', () => {
|
||||
appHookService = TestBed.inject(AppHookService);
|
||||
documentListService = TestBed.inject(DocumentListService);
|
||||
store = TestBed.inject(Store);
|
||||
testingUtils = new UnitTestingUtils(fixture.debugElement);
|
||||
});
|
||||
|
||||
it('should set folderId and call displayNode with nodeId upon init', () => {
|
||||
@@ -189,6 +198,39 @@ describe('AcaViewerComponent', () => {
|
||||
expect(contentApi.getNodeInfo).toHaveBeenCalledWith('displayed-node');
|
||||
}));
|
||||
|
||||
it('should navigate the viewer to the original node when a working copy is checked in on new version upload', fakeAsync(() => {
|
||||
spyOn(store, 'dispatch');
|
||||
spyOn(component, 'displayNode').and.stub();
|
||||
fixture.detectChanges();
|
||||
component.nodeId = 'working-copy-node';
|
||||
component.node = { id: 'working-copy-node', aspectNames: ['cm:workingcopy'] } as Node;
|
||||
|
||||
uploadService.fileUploadComplete.next({
|
||||
file: { id: 'working-copy-node' },
|
||||
data: { entry: { id: 'original-node' } }
|
||||
} as FileUploadCompleteEvent);
|
||||
tick(300);
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith(jasmine.objectContaining({ ...new ViewNodeAction('original-node', { location: router.url }) }));
|
||||
expect(component.displayNode).not.toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should set readOnly on the viewer when the node is a checked-out original (cm:checkedOut aspect)', () => {
|
||||
component.nodeId = 'checked-out-node';
|
||||
component.node = { id: 'checked-out-node', aspectNames: ['cm:checkedOut'] } as Node;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(testingUtils.getByDirective(AlfrescoViewerComponent).componentInstance.readOnly).toBe(true);
|
||||
});
|
||||
|
||||
it('should not set readOnly on the viewer when the node is not checked out', () => {
|
||||
component.nodeId = 'regular-node';
|
||||
component.node = { id: 'regular-node', aspectNames: [] } as Node;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(testingUtils.getByDirective(AlfrescoViewerComponent).componentInstance.readOnly).toBe(false);
|
||||
});
|
||||
|
||||
describe('return on event', () => {
|
||||
beforeEach(async () => {
|
||||
spyOn<any>(component, 'navigateToFileLocation');
|
||||
|
||||
@@ -187,10 +187,15 @@ export class AcaViewerComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.uploadService.fileUploadDeleted.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.navigateToFileLocation());
|
||||
|
||||
this.uploadService.fileUploadComplete.pipe(debounceTime(300), takeUntilDestroyed(this.destroyRef)).subscribe((file) => {
|
||||
this.nodesApiService.nodeUpdated.next(file.data.entry);
|
||||
if (file.data.entry.id === this.nodeId) {
|
||||
void this.displayNode(file.data.entry.id);
|
||||
this.uploadService.fileUploadComplete.pipe(debounceTime(300), takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
|
||||
const uploadedEntry = event.data.entry;
|
||||
this.nodesApiService.nodeUpdated.next(uploadedEntry);
|
||||
|
||||
if (this.node?.aspectNames?.includes('cm:workingcopy') && event.file?.id === this.nodeId && uploadedEntry.id !== this.nodeId) {
|
||||
const location = this.route.snapshot.queryParams['location'] || this.router.url;
|
||||
this.store.dispatch(new ViewNodeAction(uploadedEntry.id, { location }));
|
||||
} else if (uploadedEntry.id === this.nodeId) {
|
||||
void this.displayNode(uploadedEntry.id);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -218,4 +218,66 @@ describe('ViewerService', () => {
|
||||
it('should return empty array when there are no nodes', async () => {
|
||||
expect(await viewerService.getFileIds('', null)).toEqual([]);
|
||||
});
|
||||
|
||||
describe('cm:checkedOut filtering for personal-files and libraries', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(preferences, 'get').and.returnValues(...preferencesNoCurSortValues);
|
||||
});
|
||||
|
||||
it('should exclude cm:checkedOut nodes from personal-files results', async () => {
|
||||
const listWithCheckedOut = {
|
||||
list: {
|
||||
entries: [
|
||||
{ entry: { id: 'node1', name: 'node 1', aspectNames: [] } },
|
||||
{ entry: { id: 'node2', name: 'node 2', aspectNames: ['cm:checkedOut'] } },
|
||||
{ entry: { id: 'node3', name: 'node 3', aspectNames: ['cm:titled'] } }
|
||||
]
|
||||
}
|
||||
} as NodePaging;
|
||||
spyOn(contentApi, 'getNodeChildren').and.returnValue(of(listWithCheckedOut));
|
||||
|
||||
const ids = await viewerService.getFileIds('personal-files', 'folder1');
|
||||
|
||||
expect(ids).toEqual(['node1', 'node3']);
|
||||
});
|
||||
|
||||
it('should exclude cm:checkedOut nodes from libraries results', async () => {
|
||||
const listWithCheckedOut = {
|
||||
list: {
|
||||
entries: [
|
||||
{ entry: { id: 'node1', name: 'node 1', aspectNames: ['cm:checkedOut'] } },
|
||||
{ entry: { id: 'node2', name: 'node 2', aspectNames: [] } }
|
||||
]
|
||||
}
|
||||
} as NodePaging;
|
||||
spyOn(contentApi, 'getNodeChildren').and.returnValue(of(listWithCheckedOut));
|
||||
|
||||
const ids = await viewerService.getFileIds('libraries', 'folder1');
|
||||
|
||||
expect(ids).toEqual(['node2']);
|
||||
});
|
||||
|
||||
it('should include nodes when aspectNames is undefined', async () => {
|
||||
const listWithUndefinedAspects = {
|
||||
list: {
|
||||
entries: [{ entry: { id: 'node1', name: 'node 1' } }, { entry: { id: 'node2', name: 'node 2', aspectNames: undefined } }]
|
||||
}
|
||||
} as NodePaging;
|
||||
spyOn(contentApi, 'getNodeChildren').and.returnValue(of(listWithUndefinedAspects));
|
||||
|
||||
const ids = await viewerService.getFileIds('personal-files', 'folder1');
|
||||
|
||||
expect(ids).toEqual(['node1', 'node2']);
|
||||
});
|
||||
|
||||
it('should pass aspectNames in include and fields to getNodeChildren', async () => {
|
||||
spyOn(contentApi, 'getNodeChildren').and.returnValue(of(list as NodePaging));
|
||||
|
||||
await viewerService.getFileIds('personal-files', 'folder1');
|
||||
|
||||
const callArgs = (contentApi.getNodeChildren as jasmine.Spy).calls.mostRecent().args[1];
|
||||
expect(callArgs.include).toEqual(['aspectNames']);
|
||||
expect(callArgs.fields).toContain('aspectNames');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -111,13 +111,18 @@ export class ViewerService {
|
||||
return [];
|
||||
}
|
||||
const orderBy = isClient ? null : ['isFolder desc', `${sortKey} ${sortDirection}`];
|
||||
nodes = await this.contentApi
|
||||
const result = await this.contentApi
|
||||
.getNodeChildren(folderId, {
|
||||
orderBy: orderBy,
|
||||
fields: this.getFields(sortKey, previousSortKey),
|
||||
include: ['aspectNames'],
|
||||
fields: [...this.getFields(sortKey, previousSortKey), 'aspectNames'],
|
||||
where: '(isFile=true)'
|
||||
})
|
||||
.toPromise();
|
||||
if (result) {
|
||||
result.list.entries = result.list.entries.filter((e) => !e.entry.aspectNames?.includes('cm:checkedOut'));
|
||||
}
|
||||
nodes = result;
|
||||
}
|
||||
|
||||
if (source === 'favorites') {
|
||||
|
||||
Reference in New Issue
Block a user