mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
[ACS-3757] returning focus to element from which they were opened (#2837)
* ACS-3757 Return focus to More Actions button after closing modals opened from that button * ACS-3757 Return focus to specific row from personal files after closing modal opened from context menu from row * ACS-3757 Fixed issue that sometimes node was undefined * ACS-3757 Return focus after closing upload new version modal * ACS-3757 Added restore focus on list of libraries, restoring focus to correct row when multi rows are selected, little refactoring * ACS-3757 Use runActionById function instead of runAction * ACS-3757 Fixed unit tests * ACS-3757 Updated description * ACS-3757 Adrressing comments for static and for selectors in jsons * ACS-3757 Remove boolean flag from jsons * ACS-3757 Added some unit tests * ACS-3757 Resolved conflicts * ACS-3757 Created ModalConfiguration interface * ACS-3757 Increase version of ADF * ACS-3757 Fix for e2e * ACS-3757 Fix some more e2e * ACS-3757 Removed log
This commit is contained in:
parent
e58a0c81ba
commit
b609a9cd33
@ -1,6 +1,6 @@
|
||||
<ng-container *ngIf="selection$ | async as selection">
|
||||
<ng-container *ngIf="!data.iconButton">
|
||||
<button mat-menu-item data-automation-id="share-action-button" (click)="editSharedNode(selection)">
|
||||
<button mat-menu-item data-automation-id="share-action-button" (click)="editSharedNode(selection, '.adf-context-menu-source')">
|
||||
<mat-icon>link</mat-icon>
|
||||
<ng-container *ngIf="isShared(selection); else not_shared">
|
||||
<span>{{ 'APP.ACTIONS.SHARE_EDIT' | translate }}</span>
|
||||
@ -12,9 +12,10 @@
|
||||
<button
|
||||
mat-icon-button
|
||||
data-automation-id="share-action-button"
|
||||
(click)="editSharedNode(selection)"
|
||||
(click)="editSharedNode(selection, '#share-action-button')"
|
||||
[attr.aria-label]="getLabel(selection) | translate"
|
||||
[attr.title]="getLabel(selection) | translate"
|
||||
id="share-action-button"
|
||||
>
|
||||
<mat-icon>link</mat-icon>
|
||||
</button>
|
||||
|
@ -34,7 +34,10 @@ import { AppStore, ShareNodeAction, getAppSelection } from '@alfresco/aca-shared
|
||||
templateUrl: './toggle-shared.component.html'
|
||||
})
|
||||
export class ToggleSharedComponent implements OnInit {
|
||||
@Input() data: { iconButton?: string };
|
||||
@Input()
|
||||
data: {
|
||||
iconButton?: string;
|
||||
};
|
||||
|
||||
selection$: Observable<SelectionState>;
|
||||
|
||||
@ -53,8 +56,13 @@ export class ToggleSharedComponent implements OnInit {
|
||||
return selection.first && selection.first.entry && selection.first.entry.properties && !!selection.first.entry.properties['qshare:sharedId'];
|
||||
}
|
||||
|
||||
editSharedNode(selection: SelectionState) {
|
||||
this.store.dispatch(new ShareNodeAction(selection.first));
|
||||
editSharedNode(selection: SelectionState, focusedElementOnCloseSelector: string) {
|
||||
this.store.dispatch(
|
||||
new ShareNodeAction({
|
||||
...selection.first,
|
||||
focusedElementOnCloseSelector
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
getLabel(selection: SelectionState): string {
|
||||
|
@ -4,7 +4,7 @@
|
||||
<mat-menu #rootMenu="matMenu" class="aca-context-menu" hasBackdrop="false" acaContextMenuOutsideEvent (clickOutside)="onClickOutsideEvent()">
|
||||
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId" [ngSwitch]="entry.type">
|
||||
<ng-container *ngSwitchDefault>
|
||||
<button mat-menu-item [id]="entry.id" (click)="runAction(entry.actions.click)">
|
||||
<button mat-menu-item [id]="entry.id" (click)="runAction(entry)">
|
||||
<adf-icon [value]="entry.icon"></adf-icon>
|
||||
<span>{{ entry.title | translate }}</span>
|
||||
</button>
|
||||
|
@ -96,11 +96,13 @@ describe('ContextMenuComponent', () => {
|
||||
expect(contextMenuElements[0].querySelector('span').innerText).toBe(contextItem.title);
|
||||
});
|
||||
|
||||
it('should run action with provided action id', () => {
|
||||
it('should run action with provided action id and correct payload', () => {
|
||||
spyOn(extensionsService, 'runActionById');
|
||||
|
||||
component.runAction(contextItem.actions.click);
|
||||
component.runAction(contextItem);
|
||||
|
||||
expect(extensionsService.runActionById).toHaveBeenCalledWith(contextItem.actions.click);
|
||||
expect(extensionsService.runActionById).toHaveBeenCalledWith(contextItem.actions.click, {
|
||||
focusedElementOnCloseSelector: '.adf-context-menu-source'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -69,8 +69,10 @@ export class ContextMenuComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
}
|
||||
}
|
||||
|
||||
runAction(actionId: string) {
|
||||
this.extensions.runActionById(actionId);
|
||||
runAction(contentActionRef: ContentActionRef) {
|
||||
this.extensions.runActionById(contentActionRef.actions.click, {
|
||||
focusedElementOnCloseSelector: '.adf-context-menu-source'
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
@ -24,7 +24,7 @@
|
||||
*/
|
||||
|
||||
import { TestBed, fakeAsync, tick, flush } from '@angular/core/testing';
|
||||
import { of, throwError, Subject } from 'rxjs';
|
||||
import { of, throwError, Subject, BehaviorSubject, EMPTY } from 'rxjs';
|
||||
import { Actions, ofType, EffectsModule } from '@ngrx/effects';
|
||||
import {
|
||||
AppStore,
|
||||
@ -56,7 +56,7 @@ import { NodeActionsService } from './node-actions.service';
|
||||
import { TranslationService, AlfrescoApiService, FileModel, NotificationService } from '@alfresco/adf-core';
|
||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { MatSnackBarRef, SimpleSnackBar } from '@angular/material/snack-bar';
|
||||
import { NodeEntry, Node, VersionPaging } from '@alfresco/js-api';
|
||||
import { NodeEntry, Node, VersionPaging, MinimalNodeEntity } from '@alfresco/js-api';
|
||||
import { NewVersionUploaderDataAction, NewVersionUploaderService, NodeAspectService, ViewVersion } from '@alfresco/adf-content-services';
|
||||
|
||||
describe('ContentManagementService', () => {
|
||||
@ -1410,30 +1410,79 @@ describe('ContentManagementService', () => {
|
||||
}));
|
||||
|
||||
it('should update node selection after dialog is closed', fakeAsync(() => {
|
||||
spyOn(document, 'querySelector').and.returnValue(document.createElement('button'));
|
||||
const node = { entry: { id: '1', name: 'name1' } } as NodeEntry;
|
||||
spyOn(store, 'dispatch').and.callThrough();
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => of(null)
|
||||
} as MatDialogRef<MatDialog>);
|
||||
|
||||
store.dispatch(new ShareNodeAction(node));
|
||||
|
||||
expect(store.dispatch['calls'].argsFor(1)[0]).toEqual(new SetSelectedNodesAction([node]));
|
||||
const payload = {
|
||||
...node,
|
||||
...{
|
||||
focusedElementOnCloseSelector: 'some-selector'
|
||||
}
|
||||
};
|
||||
store.dispatch(new ShareNodeAction(payload));
|
||||
expect(store.dispatch['calls'].argsFor(1)[0]).toEqual(new SetSelectedNodesAction([payload]));
|
||||
}));
|
||||
|
||||
it('should emit event when node is un-shared', fakeAsync(() => {
|
||||
spyOn(document, 'querySelector').and.returnValue(document.createElement('button'));
|
||||
const node = { entry: { id: '1', name: 'name1' } } as NodeEntry;
|
||||
spyOn(appHookService.linksUnshared, 'next').and.callThrough();
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => of(node)
|
||||
} as MatDialogRef<MatDialog>);
|
||||
|
||||
store.dispatch(new ShareNodeAction(node));
|
||||
store.dispatch(
|
||||
new ShareNodeAction({
|
||||
...node,
|
||||
...{
|
||||
focusedElementOnCloseSelector: 'some-selector'
|
||||
}
|
||||
})
|
||||
);
|
||||
tick();
|
||||
flush();
|
||||
|
||||
expect(appHookService.linksUnshared.next).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should focus element indicated by passed selector after closing modal', () => {
|
||||
const elementToFocusSelector = 'button';
|
||||
const afterClosed$ = new Subject<void>();
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => afterClosed$.asObservable()
|
||||
} as MatDialogRef<any>);
|
||||
const elementToFocus = document.createElement(elementToFocusSelector);
|
||||
spyOn(elementToFocus, 'focus');
|
||||
spyOn(document, 'querySelector').withArgs(elementToFocusSelector).and.returnValue(elementToFocus);
|
||||
spyOn(store, 'select').and.returnValue(new BehaviorSubject(''));
|
||||
contentManagementService.shareNode(
|
||||
{
|
||||
entry: {}
|
||||
},
|
||||
elementToFocusSelector
|
||||
);
|
||||
afterClosed$.next();
|
||||
expect(elementToFocus.focus).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not looking for element to focus if passed selector is empty string', () => {
|
||||
const afterClosed$ = new Subject<void>();
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => afterClosed$.asObservable()
|
||||
} as MatDialogRef<any>);
|
||||
spyOn(document, 'querySelector');
|
||||
spyOn(store, 'select').and.returnValue(new BehaviorSubject(''));
|
||||
contentManagementService.shareNode(
|
||||
{
|
||||
entry: {}
|
||||
},
|
||||
''
|
||||
);
|
||||
afterClosed$.next();
|
||||
expect(document.querySelector).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Unlock Node', () => {
|
||||
@ -1544,8 +1593,10 @@ describe('ContentManagementService', () => {
|
||||
showVersionsOnly: true,
|
||||
title: 'VERSION.DIALOG.TITLE'
|
||||
};
|
||||
contentManagementService.manageVersions(fakeNodeIsFile);
|
||||
const elementToFocusSelector = 'some-selector';
|
||||
contentManagementService.manageVersions(fakeNodeIsFile, elementToFocusSelector);
|
||||
expect(spyOnOpenUploadNewVersionDialog['calls'].argsFor(0)[0]).toEqual(expectedArgument);
|
||||
expect(spyOnOpenUploadNewVersionDialog['calls'].argsFor(0)[2]).toEqual(elementToFocusSelector);
|
||||
});
|
||||
|
||||
it('should dispatch ReloadDocumentListAction if dialog emit refresh action', () => {
|
||||
@ -1615,6 +1666,37 @@ describe('ContentManagementService', () => {
|
||||
|
||||
expect(alfrescoApiService.nodeUpdated.next).toHaveBeenCalledWith(newNode);
|
||||
}));
|
||||
|
||||
it('should focus element indicated by passed selector after closing modal', () => {
|
||||
const elementToFocusSelector = 'button';
|
||||
const afterClosed$ = new Subject<void>();
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => afterClosed$.asObservable(),
|
||||
componentInstance: {
|
||||
error: EMPTY
|
||||
}
|
||||
} as MatDialogRef<any>);
|
||||
const elementToFocus = document.createElement(elementToFocusSelector);
|
||||
spyOn(elementToFocus, 'focus');
|
||||
spyOn(document, 'querySelector').withArgs(elementToFocusSelector).and.returnValue(elementToFocus);
|
||||
contentManagementService.editFolder({} as MinimalNodeEntity, elementToFocusSelector);
|
||||
afterClosed$.next();
|
||||
expect(elementToFocus.focus).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not looking for element to focus if passed selector is empty string', () => {
|
||||
const afterClosed$ = new Subject<void>();
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => afterClosed$.asObservable(),
|
||||
componentInstance: {
|
||||
error: EMPTY
|
||||
}
|
||||
} as MatDialogRef<any>);
|
||||
spyOn(document, 'querySelector');
|
||||
contentManagementService.editFolder({} as MinimalNodeEntity, '');
|
||||
afterClosed$.next();
|
||||
expect(document.querySelector).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('aspect list dialog', () => {
|
||||
@ -1633,21 +1715,50 @@ describe('ContentManagementService', () => {
|
||||
createdAt: null,
|
||||
createdByUser: null
|
||||
};
|
||||
const elementToFocusSelector = 'some-selector';
|
||||
|
||||
spyOn(contentApi, 'getNodeInfo').and.returnValue(of(responseNode));
|
||||
|
||||
contentManagementService.manageAspects(fakeNode);
|
||||
contentManagementService.manageAspects(fakeNode, elementToFocusSelector);
|
||||
|
||||
expect(nodeAspectService.updateNodeAspects).toHaveBeenCalledWith('real-node-ghostbuster');
|
||||
expect(nodeAspectService.updateNodeAspects).toHaveBeenCalledWith('real-node-ghostbuster', elementToFocusSelector);
|
||||
});
|
||||
|
||||
it('should open dialog for managing the aspects', () => {
|
||||
spyOn(nodeAspectService, 'updateNodeAspects').and.stub();
|
||||
const fakeNode = { entry: { id: 'fake-node-id' } };
|
||||
const elementToFocusSelector = 'some-selector';
|
||||
|
||||
contentManagementService.manageAspects(fakeNode);
|
||||
contentManagementService.manageAspects(fakeNode, elementToFocusSelector);
|
||||
|
||||
expect(nodeAspectService.updateNodeAspects).toHaveBeenCalledWith('fake-node-id');
|
||||
expect(nodeAspectService.updateNodeAspects).toHaveBeenCalledWith('fake-node-id', elementToFocusSelector);
|
||||
});
|
||||
});
|
||||
|
||||
describe('leaveLibrary', () => {
|
||||
it('should focus element indicated by passed selector after closing modal', () => {
|
||||
const elementToFocusSelector = 'button';
|
||||
const afterClosed$ = new Subject<void>();
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => afterClosed$.asObservable()
|
||||
} as MatDialogRef<any>);
|
||||
const elementToFocus = document.createElement(elementToFocusSelector);
|
||||
spyOn(elementToFocus, 'focus');
|
||||
spyOn(document, 'querySelector').withArgs(elementToFocusSelector).and.returnValue(elementToFocus);
|
||||
contentManagementService.leaveLibrary('', elementToFocusSelector);
|
||||
afterClosed$.next();
|
||||
expect(elementToFocus.focus).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not looking for element to focus if passed selector is empty string', () => {
|
||||
const afterClosed$ = new Subject<void>();
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => afterClosed$.asObservable()
|
||||
} as MatDialogRef<any>);
|
||||
spyOn(document, 'querySelector');
|
||||
contentManagementService.leaveLibrary('', '');
|
||||
afterClosed$.next();
|
||||
expect(document.querySelector).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -85,6 +85,8 @@ interface RestoredNode {
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ContentManagementService {
|
||||
private readonly createMenuButtonSelector = 'app-create-menu button';
|
||||
|
||||
constructor(
|
||||
private alfrescoApiService: AlfrescoApiService,
|
||||
private store: Store<AppStore>,
|
||||
@ -128,32 +130,32 @@ export class ContentManagementService {
|
||||
}
|
||||
}
|
||||
|
||||
manageVersions(node: any) {
|
||||
manageVersions(node: any, focusedElementOnCloseSelector?: string) {
|
||||
if (node && node.entry) {
|
||||
// shared and favorite
|
||||
const id = node.entry.nodeId || (node as any).entry.guid;
|
||||
|
||||
if (id) {
|
||||
this.contentApi.getNodeInfo(id).subscribe((entry) => {
|
||||
this.openVersionManagerDialog(entry);
|
||||
this.openVersionManagerDialog(entry, focusedElementOnCloseSelector);
|
||||
});
|
||||
} else {
|
||||
this.openVersionManagerDialog(node.entry);
|
||||
this.openVersionManagerDialog(node.entry, focusedElementOnCloseSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
manageAspects(node: any) {
|
||||
manageAspects(node: any, focusedElementOnCloseSelector?: string) {
|
||||
if (node && node.entry) {
|
||||
// shared and favorite
|
||||
const id = node.entry.nodeId || (node as any).entry.guid;
|
||||
|
||||
if (id) {
|
||||
this.contentApi.getNodeInfo(id).subscribe((entry) => {
|
||||
this.openAspectListDialog(entry);
|
||||
this.openAspectListDialog(entry, focusedElementOnCloseSelector);
|
||||
});
|
||||
} else {
|
||||
this.openAspectListDialog(node.entry);
|
||||
this.openAspectListDialog(node.entry, focusedElementOnCloseSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -180,22 +182,22 @@ export class ContentManagementService {
|
||||
});
|
||||
}
|
||||
|
||||
shareNode(node: any): void {
|
||||
shareNode(node: any, focusedElementOnCloseSelector?: string): void {
|
||||
if (node && node.entry) {
|
||||
// shared and favorite
|
||||
const id = node.entry.nodeId || (node as any).entry.guid;
|
||||
|
||||
if (id) {
|
||||
this.contentApi.getNodeInfo(id).subscribe((entry) => {
|
||||
this.openShareLinkDialog({ entry });
|
||||
this.openShareLinkDialog({ entry }, focusedElementOnCloseSelector);
|
||||
});
|
||||
} else {
|
||||
this.openShareLinkDialog(node);
|
||||
this.openShareLinkDialog(node, focusedElementOnCloseSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openShareLinkDialog(node) {
|
||||
openShareLinkDialog(node, focusedElementOnCloseSelector?: string) {
|
||||
this.store
|
||||
.select(getSharedUrl)
|
||||
.pipe(take(1))
|
||||
@ -214,6 +216,7 @@ export class ContentManagementService {
|
||||
.subscribe(() => {
|
||||
this.store.dispatch(new SetSelectedNodesAction([node]));
|
||||
this.appHookService.linksUnshared.next();
|
||||
this.focusAfterClose(focusedElementOnCloseSelector);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -237,11 +240,11 @@ export class ContentManagementService {
|
||||
if (node) {
|
||||
this.store.dispatch(new ReloadDocumentListAction());
|
||||
}
|
||||
ContentManagementService.focusCreateMenuButton();
|
||||
this.focusAfterClose(this.createMenuButtonSelector);
|
||||
});
|
||||
}
|
||||
|
||||
editFolder(folder: MinimalNodeEntity) {
|
||||
editFolder(folder: MinimalNodeEntity, focusedElementOnCloseSelector?: string) {
|
||||
if (!folder) {
|
||||
return;
|
||||
}
|
||||
@ -261,6 +264,7 @@ export class ContentManagementService {
|
||||
if (node) {
|
||||
this.alfrescoApiService.nodeUpdated.next(node);
|
||||
}
|
||||
this.focusAfterClose(focusedElementOnCloseSelector);
|
||||
});
|
||||
}
|
||||
|
||||
@ -278,7 +282,7 @@ export class ContentManagementService {
|
||||
if (node) {
|
||||
this.appHookService.libraryCreated.next(node);
|
||||
}
|
||||
ContentManagementService.focusCreateMenuButton();
|
||||
this.focusAfterClose(this.createMenuButtonSelector);
|
||||
}),
|
||||
map((node: SiteEntry) => {
|
||||
if (node && node.entry && node.entry.guid) {
|
||||
@ -301,7 +305,7 @@ export class ContentManagementService {
|
||||
);
|
||||
}
|
||||
|
||||
leaveLibrary(siteId: string): void {
|
||||
leaveLibrary(siteId: string, focusedElementOnCloseSelector?: string): void {
|
||||
const dialogRef = this.dialogRef.open(ConfirmDialogComponent, {
|
||||
data: {
|
||||
title: 'APP.DIALOGS.CONFIRM_LEAVE.TITLE',
|
||||
@ -324,6 +328,7 @@ export class ContentManagementService {
|
||||
}
|
||||
);
|
||||
}
|
||||
this.focusAfterClose(focusedElementOnCloseSelector);
|
||||
});
|
||||
}
|
||||
|
||||
@ -421,8 +426,8 @@ export class ContentManagementService {
|
||||
});
|
||||
}
|
||||
|
||||
copyNodes(nodes: Array<MinimalNodeEntity>) {
|
||||
zip(this.nodeActionsService.copyNodes(nodes), this.nodeActionsService.contentCopied).subscribe(
|
||||
copyNodes(nodes: Array<MinimalNodeEntity>, focusedElementOnCloseSelector?: string) {
|
||||
zip(this.nodeActionsService.copyNodes(nodes, undefined, focusedElementOnCloseSelector), this.nodeActionsService.contentCopied).subscribe(
|
||||
(result) => {
|
||||
const [operationResult, newItems] = result;
|
||||
this.showCopyMessage(operationResult, nodes, newItems);
|
||||
@ -433,10 +438,10 @@ export class ContentManagementService {
|
||||
);
|
||||
}
|
||||
|
||||
moveNodes(nodes: Array<MinimalNodeEntity>) {
|
||||
moveNodes(nodes: Array<MinimalNodeEntity>, focusedElementOnCloseSelector?: string) {
|
||||
const permissionForMove = '!';
|
||||
|
||||
zip(this.nodeActionsService.moveNodes(nodes, permissionForMove), this.nodeActionsService.contentMoved).subscribe(
|
||||
zip(this.nodeActionsService.moveNodes(nodes, permissionForMove, focusedElementOnCloseSelector), this.nodeActionsService.contentMoved).subscribe(
|
||||
(result) => {
|
||||
const [operationResult, moveResponse] = result;
|
||||
this.showMoveMessage(nodes, operationResult, moveResponse);
|
||||
@ -570,7 +575,7 @@ export class ContentManagementService {
|
||||
);
|
||||
}
|
||||
|
||||
private openVersionManagerDialog(node: any) {
|
||||
private openVersionManagerDialog(node: any, focusedElementOnCloseSelector?: string) {
|
||||
// workaround Shared
|
||||
if (node.isFile || node.nodeId) {
|
||||
const newVersionUploaderDialogData: NewVersionUploaderDialogData = {
|
||||
@ -579,8 +584,9 @@ export class ContentManagementService {
|
||||
title: 'VERSION.DIALOG.TITLE'
|
||||
};
|
||||
this.newVersionUploaderService
|
||||
.openUploadNewVersionDialog(newVersionUploaderDialogData, { width: '630px', role: 'dialog' })
|
||||
.subscribe((newVersionUploaderData: NewVersionUploaderData) => {
|
||||
.openUploadNewVersionDialog(newVersionUploaderDialogData, { width: '630px', role: 'dialog' }, focusedElementOnCloseSelector)
|
||||
.subscribe({
|
||||
next: (newVersionUploaderData: NewVersionUploaderData) => {
|
||||
switch (newVersionUploaderData.action) {
|
||||
case NewVersionUploaderDataAction.refresh:
|
||||
this.store.dispatch(new ReloadDocumentListAction());
|
||||
@ -595,16 +601,17 @@ export class ContentManagementService {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.store.dispatch(new SnackbarErrorAction('APP.MESSAGES.ERRORS.PERMISSION'));
|
||||
}
|
||||
}
|
||||
|
||||
private openAspectListDialog(node: any) {
|
||||
private openAspectListDialog(node: any, focusedElementOnCloseSelector?: string) {
|
||||
// workaround Shared
|
||||
if (node.isFile || node.id) {
|
||||
this.nodeAspectService.updateNodeAspects(node.id);
|
||||
this.nodeAspectService.updateNodeAspects(node.id, focusedElementOnCloseSelector);
|
||||
} else {
|
||||
this.store.dispatch(new SnackbarErrorAction('APP.MESSAGES.ERRORS.PERMISSION'));
|
||||
}
|
||||
@ -1080,7 +1087,9 @@ export class ContentManagementService {
|
||||
.subscribe(() => this.undoMoveNodes(moveResponse, initialParentId));
|
||||
}
|
||||
|
||||
private static focusCreateMenuButton(): void {
|
||||
document.querySelector<HTMLElement>('app-create-menu button').focus();
|
||||
private focusAfterClose(focusedElementSelector: string): void {
|
||||
if (focusedElementSelector) {
|
||||
document.querySelector<HTMLElement>(focusedElementSelector).focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,9 @@ describe('NodeActionsService', () => {
|
||||
|
||||
describe('ContentNodeSelector configuration', () => {
|
||||
it('should validate selection when allowableOperation has `create`', () => {
|
||||
spyOn(dialog, 'open');
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: of
|
||||
} as MatDialogRef<any>);
|
||||
const contentEntities = [new TestNode(), { entry: { nodeId: '1234' } }];
|
||||
service.getContentNodeSelection(NodeAction.CHOOSE, contentEntities as NodeEntry[]);
|
||||
|
||||
@ -131,7 +133,9 @@ describe('NodeActionsService', () => {
|
||||
});
|
||||
|
||||
it('should invalidate selection when allowableOperation does not have `create`', () => {
|
||||
spyOn(dialog, 'open');
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: of
|
||||
} as MatDialogRef<any>);
|
||||
const contentEntities = [new TestNode(), { entry: { nodeId: '1234' } }];
|
||||
service.getContentNodeSelection(NodeAction.CHOOSE, contentEntities as NodeEntry[]);
|
||||
|
||||
@ -147,7 +151,9 @@ describe('NodeActionsService', () => {
|
||||
});
|
||||
|
||||
it('should invalidate selection if isSite', () => {
|
||||
spyOn(dialog, 'open');
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: of
|
||||
} as MatDialogRef<any>);
|
||||
const contentEntities = [new TestNode(), { entry: { nodeId: '1234' } }];
|
||||
service.getContentNodeSelection(NodeAction.CHOOSE, contentEntities as NodeEntry[]);
|
||||
|
||||
@ -164,7 +170,9 @@ describe('NodeActionsService', () => {
|
||||
});
|
||||
|
||||
it('should validate selection if not a Site', () => {
|
||||
spyOn(dialog, 'open');
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: of
|
||||
} as MatDialogRef<any>);
|
||||
const contentEntities = [new TestNode(), { entry: { nodeId: '1234' } }];
|
||||
service.getContentNodeSelection(NodeAction.CHOOSE, contentEntities as NodeEntry[]);
|
||||
|
||||
@ -280,7 +288,7 @@ describe('NodeActionsService', () => {
|
||||
|
||||
spyOn(dialog, 'open').and.callFake((_contentNodeSelectorComponent: any, data: any) => {
|
||||
dialogData = data;
|
||||
return { componentInstance: {} } as MatDialogRef<any>;
|
||||
return { componentInstance: {}, afterClosed: of } as MatDialogRef<any>;
|
||||
});
|
||||
|
||||
service.copyNodes([fileToCopy, folderToCopy]);
|
||||
@ -335,7 +343,7 @@ describe('NodeActionsService', () => {
|
||||
subject.next([destinationFolder.entry]);
|
||||
|
||||
expect(spyOnBatchOperation.calls.count()).toEqual(1);
|
||||
expect(spyOnBatchOperation).toHaveBeenCalledWith(NodeAction.COPY, [fileToCopy, folderToCopy], undefined);
|
||||
expect(spyOnBatchOperation).toHaveBeenCalledWith(NodeAction.COPY, [fileToCopy, folderToCopy], undefined, undefined);
|
||||
});
|
||||
|
||||
it('should use the custom data object with custom rowFilter & imageResolver & title with destination picker', () => {
|
||||
@ -346,12 +354,12 @@ describe('NodeActionsService', () => {
|
||||
let dialogData = null;
|
||||
const spyOnDialog = spyOn(dialog, 'open').and.callFake((_contentNodeSelectorComponent: any, data: any) => {
|
||||
dialogData = data;
|
||||
return { componentInstance: {} } as MatDialogRef<any>;
|
||||
return { componentInstance: {}, afterClosed: of } as MatDialogRef<any>;
|
||||
});
|
||||
|
||||
service.copyNodes([fileToCopy, folderToCopy]);
|
||||
|
||||
expect(spyOnBatchOperation).toHaveBeenCalledWith(NodeAction.COPY, [fileToCopy, folderToCopy], undefined);
|
||||
expect(spyOnBatchOperation).toHaveBeenCalledWith(NodeAction.COPY, [fileToCopy, folderToCopy], undefined, undefined);
|
||||
expect(spyOnDestinationPicker.calls.count()).toEqual(1);
|
||||
expect(spyOnDialog.calls.count()).toEqual(1);
|
||||
|
||||
@ -388,7 +396,7 @@ describe('NodeActionsService', () => {
|
||||
let dialogData: any;
|
||||
spyOn(dialog, 'open').and.callFake((_contentNodeSelectorComponent: any, data: any) => {
|
||||
dialogData = data;
|
||||
return { componentInstance: {} } as MatDialogRef<any>;
|
||||
return { componentInstance: {}, afterClosed: of } as MatDialogRef<any>;
|
||||
});
|
||||
|
||||
service.copyNodes([{ entry: { id: 'entry-id', name: 'entry-name' } }]);
|
||||
@ -410,7 +418,7 @@ describe('NodeActionsService', () => {
|
||||
let dialogData = null;
|
||||
spyOn(dialog, 'open').and.callFake((_contentNodeSelectorComponent: any, data: any) => {
|
||||
dialogData = data;
|
||||
return { componentInstance: {} } as MatDialogRef<any>;
|
||||
return { componentInstance: {}, afterClosed: of } as MatDialogRef<any>;
|
||||
});
|
||||
|
||||
service.copyNodes([{ entry: { id: 'entry-id' } }]);
|
||||
@ -736,7 +744,7 @@ describe('NodeActionsService', () => {
|
||||
service.moveNodes([fileToMove, folderToMove], permissionToMove);
|
||||
subject.next([destinationFolder.entry]);
|
||||
|
||||
expect(spyOnBatchOperation).toHaveBeenCalledWith(NodeAction.MOVE, [fileToMove, folderToMove], permissionToMove);
|
||||
expect(spyOnBatchOperation).toHaveBeenCalledWith(NodeAction.MOVE, [fileToMove, folderToMove], permissionToMove, undefined);
|
||||
expect(spyOnDestinationPicker).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -749,7 +757,7 @@ describe('NodeActionsService', () => {
|
||||
service.moveNodes([fileToMove, folderToMove], permissionToMove);
|
||||
subject.next([destinationFolder.entry]);
|
||||
|
||||
expect(spyOnBatchOperation).toHaveBeenCalledWith(NodeAction.MOVE, [fileToMove, folderToMove], permissionToMove);
|
||||
expect(spyOnBatchOperation).toHaveBeenCalledWith(NodeAction.MOVE, [fileToMove, folderToMove], permissionToMove, undefined);
|
||||
expect(spyOnDestinationPicker).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
@ -78,9 +78,10 @@ export class NodeActionsService {
|
||||
*
|
||||
* @param contentEntities nodes to copy
|
||||
* @param permission permission which is needed to apply the action
|
||||
* @param focusedElementOnCloseSelector element's selector which should be autofocused after closing modal
|
||||
*/
|
||||
copyNodes(contentEntities: any[], permission?: string): Subject<string> {
|
||||
return this.doBatchOperation(NodeAction.COPY, contentEntities, permission);
|
||||
copyNodes(contentEntities: any[], permission?: string, focusedElementOnCloseSelector?: string): Subject<string> {
|
||||
return this.doBatchOperation(NodeAction.COPY, contentEntities, permission, focusedElementOnCloseSelector);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,9 +89,10 @@ export class NodeActionsService {
|
||||
*
|
||||
* @param contentEntities nodes to move
|
||||
* @param permission permission which is needed to apply the action
|
||||
* @param focusedElementOnCloseSelector element's selector which should be autofocused after closing modal
|
||||
*/
|
||||
moveNodes(contentEntities: any[], permission?: string): Subject<string> {
|
||||
return this.doBatchOperation(NodeAction.MOVE, contentEntities, permission);
|
||||
moveNodes(contentEntities: any[], permission?: string, focusedElementOnCloseSelector?: string): Subject<string> {
|
||||
return this.doBatchOperation(NodeAction.MOVE, contentEntities, permission, focusedElementOnCloseSelector);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,14 +101,15 @@ export class NodeActionsService {
|
||||
* @param action the action to perform (copy|move)
|
||||
* @param contentEntities the contentEntities which have to have the action performed on
|
||||
* @param permission permission which is needed to apply the action
|
||||
* @param focusedElementOnCloseSelector element's selector which should be autofocused after closing modal
|
||||
*/
|
||||
doBatchOperation(action: BatchOperationType, contentEntities: any[], permission?: string): Subject<string> {
|
||||
doBatchOperation(action: BatchOperationType, contentEntities: any[], permission?: string, focusedElementOnCloseSelector?: string): Subject<string> {
|
||||
const observable: Subject<string> = new Subject<string>();
|
||||
|
||||
if (!this.isEntryEntitiesArray(contentEntities)) {
|
||||
observable.error(new Error(JSON.stringify({ error: { statusCode: 400 } })));
|
||||
} else if (this.checkPermission(action, contentEntities, permission)) {
|
||||
const destinationSelection = this.getContentNodeSelection(action, contentEntities);
|
||||
const destinationSelection = this.getContentNodeSelection(action, contentEntities, focusedElementOnCloseSelector);
|
||||
destinationSelection.subscribe((selections: MinimalNodeEntryEntity[]) => {
|
||||
const contentEntry = contentEntities[0].entry;
|
||||
// Check if there's nodeId for Shared Files
|
||||
@ -171,7 +174,11 @@ export class NodeActionsService {
|
||||
return entryParentId;
|
||||
}
|
||||
|
||||
getContentNodeSelection(action: NodeAction, contentEntities: MinimalNodeEntity[]): Subject<MinimalNodeEntryEntity[]> {
|
||||
getContentNodeSelection(
|
||||
action: NodeAction,
|
||||
contentEntities: MinimalNodeEntity[],
|
||||
focusedElementOnCloseSelector?: string
|
||||
): Subject<MinimalNodeEntryEntity[]> {
|
||||
const currentParentFolderId = this.getEntryParentId(contentEntities[0].entry);
|
||||
|
||||
const customDropdown = new SitePaging({
|
||||
@ -211,12 +218,15 @@ export class NodeActionsService {
|
||||
excludeSiteContent: ContentNodeDialogService.nonDocumentSiteContent
|
||||
};
|
||||
|
||||
this.dialog.open(ContentNodeSelectorComponent, {
|
||||
this.dialog
|
||||
.open(ContentNodeSelectorComponent, {
|
||||
data,
|
||||
panelClass: 'adf-content-node-selector-dialog',
|
||||
width: '630px',
|
||||
role: 'dialog'
|
||||
});
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe(() => this.focusAfterClose(focusedElementOnCloseSelector));
|
||||
|
||||
data.select.subscribe({
|
||||
complete: this.close.bind(this)
|
||||
@ -687,4 +697,10 @@ export class NodeActionsService {
|
||||
return moveStatus;
|
||||
}
|
||||
}
|
||||
|
||||
private focusAfterClose(focusedElementSelector: string): void {
|
||||
if (focusedElementSelector) {
|
||||
document.querySelector<HTMLElement>(focusedElementSelector).focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,115 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { AppTestingModule } from '../../testing/app-testing.module';
|
||||
import { EffectsModule } from '@ngrx/effects';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { BehaviorSubject, Subject } from 'rxjs';
|
||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { DownloadNodesAction } from '@alfresco/aca-shared/store';
|
||||
import { SelectionState } from '@alfresco/adf-extensions';
|
||||
import { VersionEntry } from '@alfresco/js-api';
|
||||
import { DownloadEffects } from './download.effects';
|
||||
|
||||
describe('DownloadEffects', () => {
|
||||
let store: Store;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AppTestingModule, EffectsModule.forRoot([DownloadEffects])]
|
||||
});
|
||||
store = TestBed.inject(Store);
|
||||
});
|
||||
|
||||
describe('downloadNode$', () => {
|
||||
let dialog: MatDialog;
|
||||
|
||||
beforeEach(() => {
|
||||
dialog = TestBed.inject(MatDialog);
|
||||
});
|
||||
|
||||
it('should focus element indicated by passed selector after closing modal', () => {
|
||||
const elementToFocusSelector = 'button';
|
||||
const afterClosed$ = new Subject<void>();
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => afterClosed$.asObservable()
|
||||
} as MatDialogRef<any>);
|
||||
const elementToFocus = document.createElement(elementToFocusSelector);
|
||||
spyOn(elementToFocus, 'focus');
|
||||
spyOn(document, 'querySelector').withArgs(elementToFocusSelector).and.returnValue(elementToFocus);
|
||||
spyOn(store, 'select').and.returnValues(
|
||||
new BehaviorSubject({
|
||||
isEmpty: false,
|
||||
nodes: [
|
||||
{
|
||||
entry: {
|
||||
id: 'someId',
|
||||
isFolder: true
|
||||
}
|
||||
}
|
||||
]
|
||||
} as SelectionState),
|
||||
new BehaviorSubject<VersionEntry>(null)
|
||||
);
|
||||
store.dispatch(
|
||||
new DownloadNodesAction({
|
||||
focusedElementOnCloseSelector: elementToFocusSelector
|
||||
})
|
||||
);
|
||||
afterClosed$.next();
|
||||
expect(elementToFocus.focus).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not looking for element to focus if passed selector is empty string', () => {
|
||||
const afterClosed$ = new Subject<void>();
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => afterClosed$.asObservable()
|
||||
} as MatDialogRef<any>);
|
||||
spyOn(document, 'querySelector');
|
||||
spyOn(store, 'select').and.returnValues(
|
||||
new BehaviorSubject({
|
||||
isEmpty: false,
|
||||
nodes: [
|
||||
{
|
||||
entry: {
|
||||
id: 'someId',
|
||||
isFolder: true
|
||||
}
|
||||
}
|
||||
]
|
||||
} as SelectionState),
|
||||
new BehaviorSubject<VersionEntry>(null)
|
||||
);
|
||||
store.dispatch(
|
||||
new DownloadNodesAction({
|
||||
focusedElementOnCloseSelector: ''
|
||||
})
|
||||
);
|
||||
afterClosed$.next();
|
||||
expect(document.querySelector).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
@ -31,7 +31,7 @@ import { MatDialog } from '@angular/material/dialog';
|
||||
import { Actions, ofType, createEffect } from '@ngrx/effects';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
import { ContentApiService } from '@alfresco/aca-shared';
|
||||
import { ContentApiService, ModalConfiguration } from '@alfresco/aca-shared';
|
||||
import { ContentUrlService } from '../../services/content-url.service';
|
||||
|
||||
@Injectable()
|
||||
@ -49,7 +49,7 @@ export class DownloadEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<DownloadNodesAction>(NodeActionTypes.Download),
|
||||
map((action) => {
|
||||
if (action.payload && action.payload.length > 0) {
|
||||
if (Array.isArray(action.payload) && action.payload?.length > 0) {
|
||||
this.downloadNodes(action.payload);
|
||||
} else {
|
||||
this.store
|
||||
@ -64,7 +64,7 @@ export class DownloadEffects {
|
||||
if (version) {
|
||||
this.downloadFileVersion(selection.nodes[0].entry, version.entry);
|
||||
} else {
|
||||
this.downloadNodes(selection.nodes);
|
||||
this.downloadNodes(selection.nodes, (action.payload as ModalConfiguration)?.focusedElementOnCloseSelector);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -75,7 +75,7 @@ export class DownloadEffects {
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
private downloadNodes(toDownload: Array<MinimalNodeEntity>) {
|
||||
private downloadNodes(toDownload: Array<MinimalNodeEntity>, focusedElementSelector?: string) {
|
||||
const nodes = toDownload.map((node) => {
|
||||
const { id, nodeId, name, isFile, isFolder } = node.entry as any;
|
||||
|
||||
@ -92,16 +92,16 @@ export class DownloadEffects {
|
||||
}
|
||||
|
||||
if (nodes.length === 1) {
|
||||
this.downloadNode(nodes[0]);
|
||||
this.downloadNode(nodes[0], focusedElementSelector);
|
||||
} else {
|
||||
this.downloadZip(nodes);
|
||||
this.downloadZip(nodes, focusedElementSelector);
|
||||
}
|
||||
}
|
||||
|
||||
private downloadNode(node: NodeInfo) {
|
||||
private downloadNode(node: NodeInfo, focusedElementSelector?: string) {
|
||||
if (node) {
|
||||
if (node.isFolder) {
|
||||
this.downloadZip([node]);
|
||||
this.downloadZip([node], focusedElementSelector);
|
||||
} else {
|
||||
this.downloadFile(node);
|
||||
}
|
||||
@ -128,17 +128,20 @@ export class DownloadEffects {
|
||||
}
|
||||
}
|
||||
|
||||
private downloadZip(nodes: Array<NodeInfo>) {
|
||||
private downloadZip(nodes: Array<NodeInfo>, focusedElementSelector?: string) {
|
||||
if (nodes && nodes.length > 0) {
|
||||
const nodeIds = nodes.map((node) => node.id);
|
||||
|
||||
this.dialog.open(DownloadZipDialogComponent, {
|
||||
this.dialog
|
||||
.open(DownloadZipDialogComponent, {
|
||||
width: '600px',
|
||||
disableClose: true,
|
||||
data: {
|
||||
nodeIds
|
||||
}
|
||||
});
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe(() => this.focusAfterClose(focusedElementSelector));
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,4 +162,10 @@ export class DownloadEffects {
|
||||
private get isSharedLinkPreview() {
|
||||
return location.href.includes('/preview/s/');
|
||||
}
|
||||
|
||||
private focusAfterClose(focusedElementSelector: string): void {
|
||||
if (focusedElementSelector) {
|
||||
document.querySelector<HTMLElement>(focusedElementSelector).focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ import { Injectable } from '@angular/core';
|
||||
import { Actions, ofType, createEffect } from '@ngrx/effects';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { map, mergeMap, take } from 'rxjs/operators';
|
||||
import { ContentApiService } from '@alfresco/aca-shared';
|
||||
import { ContentApiService, ModalConfiguration } from '@alfresco/aca-shared';
|
||||
import { ContentManagementService } from '../../services/content-management.service';
|
||||
|
||||
@Injectable()
|
||||
@ -56,7 +56,7 @@ export class LibraryEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<DeleteLibraryAction>(LibraryActionTypes.Delete),
|
||||
map((action) => {
|
||||
if (action.payload) {
|
||||
if (typeof action?.payload === 'string') {
|
||||
this.content.deleteLibrary(action.payload);
|
||||
} else {
|
||||
this.store
|
||||
@ -78,7 +78,7 @@ export class LibraryEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<LeaveLibraryAction>(LibraryActionTypes.Leave),
|
||||
map((action) => {
|
||||
if (action.payload) {
|
||||
if (typeof action.payload === 'string') {
|
||||
this.content.leaveLibrary(action.payload);
|
||||
} else {
|
||||
this.store
|
||||
@ -86,7 +86,7 @@ export class LibraryEffects {
|
||||
.pipe(take(1))
|
||||
.subscribe((selection) => {
|
||||
if (selection && selection.library) {
|
||||
this.content.leaveLibrary(selection.library.entry.id);
|
||||
this.content.leaveLibrary(selection.library.entry.id, (action.payload as ModalConfiguration)?.focusedElementOnCloseSelector);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -79,10 +79,12 @@ describe('NodeEffects', () => {
|
||||
it('should share node from payload', () => {
|
||||
spyOn(contentService, 'shareNode').and.stub();
|
||||
|
||||
const node: any = {};
|
||||
const node: any = {
|
||||
entry: {}
|
||||
};
|
||||
store.dispatch(new ShareNodeAction(node));
|
||||
|
||||
expect(contentService.shareNode).toHaveBeenCalledWith(node);
|
||||
expect(contentService.shareNode).toHaveBeenCalledWith(node, undefined);
|
||||
});
|
||||
|
||||
it('should share node from active selection', fakeAsync(() => {
|
||||
@ -94,7 +96,7 @@ describe('NodeEffects', () => {
|
||||
tick(100);
|
||||
|
||||
store.dispatch(new ShareNodeAction(null));
|
||||
expect(contentService.shareNode).toHaveBeenCalledWith(node);
|
||||
expect(contentService.shareNode).toHaveBeenCalledWith(node, undefined);
|
||||
}));
|
||||
|
||||
it('should do nothing if invoking share with no data', () => {
|
||||
@ -300,7 +302,7 @@ describe('NodeEffects', () => {
|
||||
tick(100);
|
||||
|
||||
store.dispatch(new EditFolderAction(null));
|
||||
expect(contentService.editFolder).toHaveBeenCalledWith(currentFolder);
|
||||
expect(contentService.editFolder).toHaveBeenCalledWith(currentFolder, undefined);
|
||||
}));
|
||||
|
||||
it('should do nothing if editing folder with no selection and payload', () => {
|
||||
@ -332,7 +334,7 @@ describe('NodeEffects', () => {
|
||||
|
||||
store.dispatch(new CopyNodesAction(null));
|
||||
|
||||
expect(contentService.copyNodes).toHaveBeenCalledWith([node]);
|
||||
expect(contentService.copyNodes).toHaveBeenCalledWith([node], undefined);
|
||||
}));
|
||||
|
||||
it('should do nothing if invoking copy with no data', () => {
|
||||
@ -364,7 +366,7 @@ describe('NodeEffects', () => {
|
||||
|
||||
store.dispatch(new MoveNodesAction(null));
|
||||
|
||||
expect(contentService.moveNodes).toHaveBeenCalledWith([node]);
|
||||
expect(contentService.moveNodes).toHaveBeenCalledWith([node], undefined);
|
||||
}));
|
||||
|
||||
it('should do nothing if invoking move with no data', () => {
|
||||
@ -488,7 +490,7 @@ describe('NodeEffects', () => {
|
||||
|
||||
store.dispatch(new ManageAspectsAction(null));
|
||||
|
||||
expect(contentService.manageAspects).toHaveBeenCalledWith({ entry: { isFile: true, id: 'file-node-id' } });
|
||||
expect(contentService.manageAspects).toHaveBeenCalledWith({ entry: { isFile: true, id: 'file-node-id' } }, undefined);
|
||||
}));
|
||||
|
||||
it('should call aspect dialog from the active folder selection', fakeAsync(() => {
|
||||
@ -501,7 +503,7 @@ describe('NodeEffects', () => {
|
||||
|
||||
store.dispatch(new ManageAspectsAction(null));
|
||||
|
||||
expect(contentService.manageAspects).toHaveBeenCalledWith({ entry: { isFile: false, id: 'folder-node-id' } });
|
||||
expect(contentService.manageAspects).toHaveBeenCalledWith({ entry: { isFile: false, id: 'folder-node-id' } }, undefined);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
@ -54,6 +54,7 @@ import {
|
||||
} from '@alfresco/aca-shared/store';
|
||||
import { ContentManagementService } from '../../services/content-management.service';
|
||||
import { ViewUtilService } from '@alfresco/adf-core';
|
||||
import { ModalConfiguration } from '@alfresco/aca-shared';
|
||||
|
||||
@Injectable()
|
||||
export class NodeEffects {
|
||||
@ -69,15 +70,15 @@ export class NodeEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<ShareNodeAction>(NodeActionTypes.Share),
|
||||
map((action) => {
|
||||
if (action.payload) {
|
||||
this.contentService.shareNode(action.payload);
|
||||
if (action.payload?.entry) {
|
||||
this.contentService.shareNode(action.payload, action.payload?.focusedElementOnCloseSelector);
|
||||
} else {
|
||||
this.store
|
||||
.select(getAppSelection)
|
||||
.pipe(take(1))
|
||||
.subscribe((selection) => {
|
||||
if (selection && selection.file) {
|
||||
this.contentService.shareNode(selection.file);
|
||||
this.contentService.shareNode(selection.file, action.payload?.focusedElementOnCloseSelector);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -215,7 +216,7 @@ export class NodeEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<EditFolderAction>(NodeActionTypes.EditFolder),
|
||||
map((action) => {
|
||||
if (action.payload) {
|
||||
if (action.payload?.entry) {
|
||||
this.contentService.editFolder(action.payload);
|
||||
} else {
|
||||
this.store
|
||||
@ -223,7 +224,7 @@ export class NodeEffects {
|
||||
.pipe(take(1))
|
||||
.subscribe((selection) => {
|
||||
if (selection && selection.folder) {
|
||||
this.contentService.editFolder(selection.folder);
|
||||
this.contentService.editFolder(selection.folder, action.payload?.focusedElementOnCloseSelector);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -237,7 +238,7 @@ export class NodeEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<CopyNodesAction>(NodeActionTypes.Copy),
|
||||
map((action) => {
|
||||
if (action.payload && action.payload.length > 0) {
|
||||
if (Array.isArray(action.payload) && action.payload?.length > 0) {
|
||||
this.contentService.copyNodes(action.payload);
|
||||
} else {
|
||||
this.store
|
||||
@ -245,7 +246,7 @@ export class NodeEffects {
|
||||
.pipe(take(1))
|
||||
.subscribe((selection) => {
|
||||
if (selection && !selection.isEmpty) {
|
||||
this.contentService.copyNodes(selection.nodes);
|
||||
this.contentService.copyNodes(selection.nodes, (action.payload as ModalConfiguration)?.focusedElementOnCloseSelector);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -259,7 +260,7 @@ export class NodeEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<MoveNodesAction>(NodeActionTypes.Move),
|
||||
map((action) => {
|
||||
if (action.payload && action.payload.length > 0) {
|
||||
if (Array.isArray(action.payload) && action.payload?.length > 0) {
|
||||
this.contentService.moveNodes(action.payload);
|
||||
} else {
|
||||
this.store
|
||||
@ -267,7 +268,7 @@ export class NodeEffects {
|
||||
.pipe(take(1))
|
||||
.subscribe((selection) => {
|
||||
if (selection && !selection.isEmpty) {
|
||||
this.contentService.moveNodes(selection.nodes);
|
||||
this.contentService.moveNodes(selection.nodes, (action.payload as ModalConfiguration)?.focusedElementOnCloseSelector);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -281,7 +282,7 @@ export class NodeEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<ManagePermissionsAction>(NodeActionTypes.ManagePermissions),
|
||||
map((action) => {
|
||||
if (action && action.payload) {
|
||||
if (action?.payload?.entry) {
|
||||
const route = 'personal-files/details';
|
||||
this.store.dispatch(new NavigateRouteAction([route, action.payload.entry.id, 'permissions']));
|
||||
} else {
|
||||
@ -305,7 +306,7 @@ export class NodeEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<ExpandInfoDrawerAction>(NodeActionTypes.ExpandInfoDrawer),
|
||||
map((action) => {
|
||||
if (action && action.payload) {
|
||||
if (action?.payload?.entry) {
|
||||
const route = 'personal-files/details';
|
||||
this.store.dispatch(new NavigateRouteAction([route, action.payload.entry.id]));
|
||||
} else {
|
||||
@ -329,7 +330,7 @@ export class NodeEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<ManageVersionsAction>(NodeActionTypes.ManageVersions),
|
||||
map((action) => {
|
||||
if (action && action.payload) {
|
||||
if (action?.payload?.entry) {
|
||||
this.contentService.manageVersions(action.payload);
|
||||
} else {
|
||||
this.store
|
||||
@ -337,7 +338,7 @@ export class NodeEffects {
|
||||
.pipe(take(1))
|
||||
.subscribe((selection) => {
|
||||
if (selection && selection.file) {
|
||||
this.contentService.manageVersions(selection.file);
|
||||
this.contentService.manageVersions(selection.file, action.payload?.focusedElementOnCloseSelector);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -395,7 +396,7 @@ export class NodeEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<ManageAspectsAction>(NodeActionTypes.ChangeAspects),
|
||||
map((action) => {
|
||||
if (action && action.payload) {
|
||||
if (action?.payload?.entry) {
|
||||
this.contentService.manageAspects(action.payload);
|
||||
} else {
|
||||
this.store
|
||||
@ -403,7 +404,7 @@ export class NodeEffects {
|
||||
.pipe(take(1))
|
||||
.subscribe((selection) => {
|
||||
if (selection && !selection.isEmpty) {
|
||||
this.contentService.manageAspects(selection.nodes[0]);
|
||||
this.contentService.manageAspects(selection.nodes[0], action.payload?.focusedElementOnCloseSelector);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -429,7 +430,7 @@ export class NodeEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<ManageRulesAction>(NodeActionTypes.ManageRules),
|
||||
map((action) => {
|
||||
if (action && action.payload) {
|
||||
if (action?.payload?.entry) {
|
||||
this.store.dispatch(new NavigateRouteAction(['nodes', action.payload.entry.id, 'rules']));
|
||||
} else {
|
||||
this.store
|
||||
|
@ -41,12 +41,14 @@ import { of } from 'rxjs';
|
||||
import { catchError, map, take } from 'rxjs/operators';
|
||||
import { ContentManagementService } from '../../services/content-management.service';
|
||||
import { MinimalNodeEntryEntity } from '@alfresco/js-api';
|
||||
import { ModalConfiguration } from '@alfresco/aca-shared';
|
||||
|
||||
@Injectable()
|
||||
export class UploadEffects {
|
||||
private fileInput: HTMLInputElement;
|
||||
private folderInput: HTMLInputElement;
|
||||
private fileVersionInput: HTMLInputElement;
|
||||
private readonly createMenuButtonSelector = 'app-create-menu button';
|
||||
|
||||
constructor(
|
||||
private store: Store<AppStore>,
|
||||
@ -90,7 +92,7 @@ export class UploadEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<UploadFilesAction>(UploadActionTypes.UploadFiles),
|
||||
map(() => {
|
||||
this.registerFocusingCreateMenuButton(this.fileInput);
|
||||
this.registerFocusingElementAfterModalClose(this.fileInput, this.createMenuButtonSelector);
|
||||
this.fileInput.click();
|
||||
})
|
||||
),
|
||||
@ -102,7 +104,7 @@ export class UploadEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<UploadFolderAction>(UploadActionTypes.UploadFolder),
|
||||
map(() => {
|
||||
this.registerFocusingCreateMenuButton(this.folderInput);
|
||||
this.registerFocusingElementAfterModalClose(this.folderInput, this.createMenuButtonSelector);
|
||||
this.folderInput.click();
|
||||
})
|
||||
),
|
||||
@ -114,11 +116,15 @@ export class UploadEffects {
|
||||
this.actions$.pipe(
|
||||
ofType<UploadFileVersionAction>(UploadActionTypes.UploadFileVersion),
|
||||
map((action) => {
|
||||
if (action?.payload) {
|
||||
if (action?.payload instanceof CustomEvent) {
|
||||
const node = action?.payload?.detail?.data?.node?.entry;
|
||||
const file: any = action?.payload?.detail?.files[0]?.file;
|
||||
this.contentService.versionUpdateDialog(node, file);
|
||||
} else if (!action?.payload) {
|
||||
} else if (!action?.payload || !(action.payload instanceof CustomEvent)) {
|
||||
this.registerFocusingElementAfterModalClose(
|
||||
this.fileVersionInput,
|
||||
(action?.payload as ModalConfiguration)?.focusedElementOnCloseSelector
|
||||
);
|
||||
this.fileVersionInput.click();
|
||||
}
|
||||
})
|
||||
@ -199,18 +205,18 @@ export class UploadEffects {
|
||||
});
|
||||
}
|
||||
|
||||
private registerFocusingCreateMenuButton(input: HTMLInputElement): void {
|
||||
private registerFocusingElementAfterModalClose(input: HTMLInputElement, focusedElementSelector: string): void {
|
||||
input.addEventListener(
|
||||
'click',
|
||||
() => {
|
||||
window.addEventListener(
|
||||
'focus',
|
||||
() => {
|
||||
const createMenuButton = document.querySelector<HTMLElement>('app-create-menu button');
|
||||
createMenuButton.addEventListener('focus', () => createMenuButton.classList.add('cdk-program-focused'), {
|
||||
const elementToFocus = document.querySelector<HTMLElement>(focusedElementSelector);
|
||||
elementToFocus.addEventListener('focus', () => elementToFocus.classList.add('cdk-program-focused'), {
|
||||
once: true
|
||||
});
|
||||
createMenuButton.focus();
|
||||
elementToFocus.focus();
|
||||
},
|
||||
{
|
||||
once: true
|
||||
|
88
package-lock.json
generated
88
package-lock.json
generated
@ -11,9 +11,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@alfresco/adf-cli": {
|
||||
"version": "6.0.0-A.1-37352",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-cli/-/adf-cli-6.0.0-A.1-37352.tgz",
|
||||
"integrity": "sha512-lM//JUPyBmyO9PVDd628VFyumMJElBKNDvy6E0Yv/iKZmj2S/93pCFhkjnnbG/hOMNAIy5HePOvwOHQ9+vQAgg==",
|
||||
"version": "6.0.0-A.1-37376",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-cli/-/adf-cli-6.0.0-A.1-37376.tgz",
|
||||
"integrity": "sha512-sEKwZ9DS4CAzub6oKOmJGFoLzc4esMW4859GnbLVU9V8pBZ+KPIfRECY3AsCrRvbuK7dSM8EQgsrT8KDb9IZDg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@alfresco/js-api": "5.2.0",
|
||||
@ -28,17 +28,17 @@
|
||||
}
|
||||
},
|
||||
"@alfresco/adf-content-services": {
|
||||
"version": "6.0.0-A.1-37352",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-6.0.0-A.1-37352.tgz",
|
||||
"integrity": "sha512-vKtVJDl7WE19WkbB9KHfeka5lnSBOUFAEwjBsSr/UGhNFkQn0zSS1I4CXhjY5h0o+X31JVuIzVLfPqAWiEOZkA==",
|
||||
"version": "6.0.0-A.1-37376",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-6.0.0-A.1-37376.tgz",
|
||||
"integrity": "sha512-QrwadBgJFG4n7iaUJfirhYPEWCO+BD1YiPBlo3+gK9LJvnaHiAiiAFbnXqaa2FY1RlFm6Td6NH0yoHJtwQH+sQ==",
|
||||
"requires": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"@alfresco/adf-core": {
|
||||
"version": "6.0.0-A.1-37352",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-6.0.0-A.1-37352.tgz",
|
||||
"integrity": "sha512-zGvZkpIYTaUgZLzyGWBK17MCA+HOQbEEefr3V3KisuLFgCXWwD2GyGn1xSba+kp6CDbabGjfTG/2pG0oDk8NeA==",
|
||||
"version": "6.0.0-A.1-37376",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-6.0.0-A.1-37376.tgz",
|
||||
"integrity": "sha512-NryzWdDie9eyrp0a7lC1P+6R0nXp7KzoHfIVrWO1rNhPWBhYgJlRHPP44KBO0/Ydgbio3jvnwZlX15+Kq0/Awg==",
|
||||
"requires": {
|
||||
"@editorjs/code": "2.7.0",
|
||||
"@editorjs/editorjs": "2.25.0",
|
||||
@ -56,20 +56,20 @@
|
||||
}
|
||||
},
|
||||
"@alfresco/adf-extensions": {
|
||||
"version": "6.0.0-A.1-37352",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-6.0.0-A.1-37352.tgz",
|
||||
"integrity": "sha512-OcalA6Jl9tr1ynFj9SPbH+i+h4faMpqdFzDza6ZjT2Hquq2Thk5ylzMz+LIHW1FB2wsfKssy9a/409sRHyy1Uw==",
|
||||
"version": "6.0.0-A.1-37376",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-6.0.0-A.1-37376.tgz",
|
||||
"integrity": "sha512-amPdYFRlctYGfKIf1IKt9+SSsVcXOhvOxMsccbN9jI6ShlXBvhBTK+jtItqoJp3GDfWWGU/7RJ0anbZbbQQxTw==",
|
||||
"requires": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"@alfresco/adf-testing": {
|
||||
"version": "6.0.0-A.1-37352",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-testing/-/adf-testing-6.0.0-A.1-37352.tgz",
|
||||
"integrity": "sha512-0T18iLgKq76YzCK+iJwpRie8xrJXmGBM/YZ/OqMwAmyHPt5nUY7Uzy+stBlh/TDC9bULCejf3aZByMP82lT7hg==",
|
||||
"version": "6.0.0-A.1-37376",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-testing/-/adf-testing-6.0.0-A.1-37376.tgz",
|
||||
"integrity": "sha512-WXbpfnKgRHCk7yb/OiWOkJuCvldxRa4vBlP4sRQ4ggoywS85V1yRtJqespoDV/MmYZQ0/ZNXZtVFW8GHzQPOcQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@alfresco/js-api": "5.3.0-466",
|
||||
"@alfresco/js-api": "5.3.0-475",
|
||||
"@angular/compiler": "14.1.3",
|
||||
"@angular/core": "14.1.3",
|
||||
"rxjs": "6.6.6",
|
||||
@ -78,9 +78,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@alfresco/js-api": {
|
||||
"version": "5.3.0-466",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-5.3.0-466.tgz",
|
||||
"integrity": "sha512-ArBqTqEDbzR/jD6YtJTrPQG3Wz69WXURjnzZE8Os+JWUacJS1n/xEqncJY+xDoILuT1EtaEjogOWNYZixUqXlg==",
|
||||
"version": "5.3.0-475",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-5.3.0-475.tgz",
|
||||
"integrity": "sha512-oNx3f6c7UlEhAry4pOSoXfZV5E53EM10dBXO2O2PrNS1hNJyT/XiWzeFT3szF8pMQWKyHc3fR5JRVThnTnR++A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"event-emitter": "^0.3.5",
|
||||
@ -7548,14 +7548,6 @@
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
@ -11343,16 +11335,6 @@
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimatch": "^5.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"image-size": {
|
||||
@ -13770,14 +13752,6 @@
|
||||
"picomatch": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"cacache": {
|
||||
"version": "16.1.3",
|
||||
"resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz",
|
||||
@ -14277,14 +14251,6 @@
|
||||
"humanize-ms": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"cacache": {
|
||||
"version": "16.1.2",
|
||||
"resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.2.tgz",
|
||||
@ -14642,14 +14608,6 @@
|
||||
"npm-normalize-package-bin": "^1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"glob": {
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz",
|
||||
@ -15162,14 +15120,6 @@
|
||||
"humanize-ms": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"builtins": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
|
||||
|
10
package.json
10
package.json
@ -26,9 +26,9 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@alfresco/adf-content-services": "6.0.0-A.1-37352",
|
||||
"@alfresco/adf-core": "6.0.0-A.1-37352",
|
||||
"@alfresco/adf-extensions": "6.0.0-A.1-37352",
|
||||
"@alfresco/adf-content-services": "6.0.0-A.1-37376",
|
||||
"@alfresco/adf-core": "6.0.0-A.1-37376",
|
||||
"@alfresco/adf-extensions": "6.0.0-A.1-37376",
|
||||
"@alfresco/js-api": "5.2.0",
|
||||
"@angular/animations": "14.1.2",
|
||||
"@angular/cdk": "14.1.2",
|
||||
@ -58,8 +58,8 @@
|
||||
"zone.js": "0.11.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alfresco/adf-cli": "6.0.0-A.1-37352",
|
||||
"@alfresco/adf-testing": "6.0.0-A.1-37352",
|
||||
"@alfresco/adf-cli": "6.0.0-A.1-37376",
|
||||
"@alfresco/adf-testing": "6.0.0-A.1-37376",
|
||||
"@angular-custom-builders/lite-serve": "^0.2.3",
|
||||
"@angular-devkit/build-angular": "14.1.2",
|
||||
"@angular-eslint/builder": "^14.1.2",
|
||||
|
@ -53,7 +53,9 @@ export class ToolbarButtonComponent {
|
||||
|
||||
runAction() {
|
||||
if (this.hasClickAction(this.actionRef)) {
|
||||
this.extensions.runActionById(this.actionRef.actions.click);
|
||||
this.extensions.runActionById(this.actionRef.actions.click, {
|
||||
focusedElementOnCloseSelector: `#${this.actionRef.id.replace(/\./g, '\\.')}`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,8 @@ import { MatMenuItem } from '@angular/material/menu';
|
||||
export class ToolbarMenuItemComponent {
|
||||
@Input()
|
||||
actionRef: ContentActionRef;
|
||||
@Input()
|
||||
menuId?: string;
|
||||
|
||||
@ViewChild(MatMenuItem)
|
||||
menuItem: MatMenuItem;
|
||||
@ -52,7 +54,14 @@ export class ToolbarMenuItemComponent {
|
||||
|
||||
runAction() {
|
||||
if (this.hasClickAction(this.actionRef)) {
|
||||
this.extensions.runActionById(this.actionRef.actions.click);
|
||||
this.extensions.runActionById(
|
||||
this.actionRef.actions.click,
|
||||
this.menuId
|
||||
? {
|
||||
focusedElementOnCloseSelector: `#${this.menuId.replace(/\./g, '\\.')}`
|
||||
}
|
||||
: undefined
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
<adf-dynamic-component [id]="child.component" [data]="child.data"></adf-dynamic-component>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchDefault>
|
||||
<app-toolbar-menu-item [actionRef]="child"></app-toolbar-menu-item>
|
||||
<app-toolbar-menu-item [actionRef]="child" [menuId]="actionRef.id"></app-toolbar-menu-item>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
@ -0,0 +1,3 @@
|
||||
export interface ModalConfiguration {
|
||||
focusedElementOnCloseSelector?: string;
|
||||
}
|
@ -498,7 +498,7 @@ export class AppExtensionService implements RuleContext {
|
||||
return false;
|
||||
}
|
||||
|
||||
runActionById(id: string) {
|
||||
runActionById(id: string, additionalPayload?: { [key: string]: any }) {
|
||||
const action = this.extensions.getActionById(id);
|
||||
if (action) {
|
||||
const { type, payload } = action;
|
||||
@ -507,9 +507,21 @@ export class AppExtensionService implements RuleContext {
|
||||
};
|
||||
const expression = this.extensions.runExpression(payload, context);
|
||||
|
||||
this.store.dispatch({ type, payload: expression });
|
||||
this.store.dispatch({
|
||||
type,
|
||||
payload:
|
||||
typeof expression === 'object'
|
||||
? {
|
||||
...expression,
|
||||
...additionalPayload
|
||||
}
|
||||
: expression
|
||||
});
|
||||
} else {
|
||||
this.store.dispatch({ type: id });
|
||||
this.store.dispatch({
|
||||
type: id,
|
||||
payload: additionalPayload
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,7 @@ export * from './lib/directives/shared.directives.module';
|
||||
|
||||
export * from './lib/models/types';
|
||||
export * from './lib/models/viewer.rules';
|
||||
export * from './lib/models/modal-configuration';
|
||||
|
||||
export * from './lib/routing/shared.guard';
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
import { Action } from '@ngrx/store';
|
||||
import { SiteBody } from '@alfresco/js-api';
|
||||
import { ModalConfiguration } from '@alfresco/aca-shared';
|
||||
|
||||
export enum LibraryActionTypes {
|
||||
Delete = 'DELETE_LIBRARY',
|
||||
@ -59,5 +60,5 @@ export class UpdateLibraryAction implements Action {
|
||||
export class LeaveLibraryAction implements Action {
|
||||
readonly type = LibraryActionTypes.Leave;
|
||||
|
||||
constructor(public payload?: string) {}
|
||||
constructor(public payload?: string | ModalConfiguration) {}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
import { Action } from '@ngrx/store';
|
||||
import { MinimalNodeEntity } from '@alfresco/js-api';
|
||||
import { ModalConfiguration } from '@alfresco/aca-shared';
|
||||
|
||||
export enum NodeActionTypes {
|
||||
SetSelection = 'SET_SELECTED_NODES',
|
||||
@ -84,7 +85,7 @@ export class PurgeDeletedNodesAction implements Action {
|
||||
export class DownloadNodesAction implements Action {
|
||||
readonly type = NodeActionTypes.Download;
|
||||
|
||||
constructor(public payload: MinimalNodeEntity[] = []) {}
|
||||
constructor(public payload: MinimalNodeEntity[] | ModalConfiguration = []) {}
|
||||
}
|
||||
|
||||
export class CreateFolderAction implements Action {
|
||||
@ -96,13 +97,13 @@ export class CreateFolderAction implements Action {
|
||||
export class EditFolderAction implements Action {
|
||||
readonly type = NodeActionTypes.EditFolder;
|
||||
|
||||
constructor(public payload: MinimalNodeEntity) {}
|
||||
constructor(public payload: MinimalNodeEntity & ModalConfiguration) {}
|
||||
}
|
||||
|
||||
export class ShareNodeAction implements Action {
|
||||
readonly type = NodeActionTypes.Share;
|
||||
|
||||
constructor(public payload: MinimalNodeEntity) {}
|
||||
constructor(public payload: MinimalNodeEntity & ModalConfiguration) {}
|
||||
}
|
||||
|
||||
export class UnshareNodesAction implements Action {
|
||||
@ -114,13 +115,13 @@ export class UnshareNodesAction implements Action {
|
||||
export class CopyNodesAction implements Action {
|
||||
readonly type = NodeActionTypes.Copy;
|
||||
|
||||
constructor(public payload: Array<MinimalNodeEntity>) {}
|
||||
constructor(public payload: Array<MinimalNodeEntity> | ModalConfiguration) {}
|
||||
}
|
||||
|
||||
export class MoveNodesAction implements Action {
|
||||
readonly type = NodeActionTypes.Move;
|
||||
|
||||
constructor(public payload: Array<MinimalNodeEntity>) {}
|
||||
constructor(public payload: Array<MinimalNodeEntity> | ModalConfiguration) {}
|
||||
}
|
||||
|
||||
export class ManagePermissionsAction implements Action {
|
||||
@ -143,7 +144,7 @@ export class PrintFileAction implements Action {
|
||||
export class ManageVersionsAction implements Action {
|
||||
readonly type = NodeActionTypes.ManageVersions;
|
||||
|
||||
constructor(public payload: MinimalNodeEntity) {}
|
||||
constructor(public payload: MinimalNodeEntity & ModalConfiguration) {}
|
||||
}
|
||||
|
||||
export class EditOfflineAction implements Action {
|
||||
@ -172,7 +173,7 @@ export class RemoveFavoriteAction implements Action {
|
||||
export class ManageAspectsAction implements Action {
|
||||
readonly type = NodeActionTypes.ChangeAspects;
|
||||
|
||||
constructor(public payload: MinimalNodeEntity) {}
|
||||
constructor(public payload: MinimalNodeEntity & ModalConfiguration) {}
|
||||
}
|
||||
|
||||
export class ManageRulesAction implements Action {
|
||||
|
@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
import { Action } from '@ngrx/store';
|
||||
import { ModalConfiguration } from '@alfresco/aca-shared';
|
||||
|
||||
export enum UploadActionTypes {
|
||||
UploadFiles = 'UPLOAD_FILES',
|
||||
@ -46,5 +47,5 @@ export class UploadFolderAction implements Action {
|
||||
export class UploadFileVersionAction implements Action {
|
||||
readonly type = UploadActionTypes.UploadFileVersion;
|
||||
|
||||
constructor(public payload: CustomEvent) {}
|
||||
constructor(public payload: CustomEvent | ModalConfiguration) {}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user