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="selection$ | async as selection">
|
||||||
<ng-container *ngIf="!data.iconButton">
|
<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>
|
<mat-icon>link</mat-icon>
|
||||||
<ng-container *ngIf="isShared(selection); else not_shared">
|
<ng-container *ngIf="isShared(selection); else not_shared">
|
||||||
<span>{{ 'APP.ACTIONS.SHARE_EDIT' | translate }}</span>
|
<span>{{ 'APP.ACTIONS.SHARE_EDIT' | translate }}</span>
|
||||||
@ -12,9 +12,10 @@
|
|||||||
<button
|
<button
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
data-automation-id="share-action-button"
|
data-automation-id="share-action-button"
|
||||||
(click)="editSharedNode(selection)"
|
(click)="editSharedNode(selection, '#share-action-button')"
|
||||||
[attr.aria-label]="getLabel(selection) | translate"
|
[attr.aria-label]="getLabel(selection) | translate"
|
||||||
[attr.title]="getLabel(selection) | translate"
|
[attr.title]="getLabel(selection) | translate"
|
||||||
|
id="share-action-button"
|
||||||
>
|
>
|
||||||
<mat-icon>link</mat-icon>
|
<mat-icon>link</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
@ -34,7 +34,10 @@ import { AppStore, ShareNodeAction, getAppSelection } from '@alfresco/aca-shared
|
|||||||
templateUrl: './toggle-shared.component.html'
|
templateUrl: './toggle-shared.component.html'
|
||||||
})
|
})
|
||||||
export class ToggleSharedComponent implements OnInit {
|
export class ToggleSharedComponent implements OnInit {
|
||||||
@Input() data: { iconButton?: string };
|
@Input()
|
||||||
|
data: {
|
||||||
|
iconButton?: string;
|
||||||
|
};
|
||||||
|
|
||||||
selection$: Observable<SelectionState>;
|
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'];
|
return selection.first && selection.first.entry && selection.first.entry.properties && !!selection.first.entry.properties['qshare:sharedId'];
|
||||||
}
|
}
|
||||||
|
|
||||||
editSharedNode(selection: SelectionState) {
|
editSharedNode(selection: SelectionState, focusedElementOnCloseSelector: string) {
|
||||||
this.store.dispatch(new ShareNodeAction(selection.first));
|
this.store.dispatch(
|
||||||
|
new ShareNodeAction({
|
||||||
|
...selection.first,
|
||||||
|
focusedElementOnCloseSelector
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getLabel(selection: SelectionState): string {
|
getLabel(selection: SelectionState): string {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<mat-menu #rootMenu="matMenu" class="aca-context-menu" hasBackdrop="false" acaContextMenuOutsideEvent (clickOutside)="onClickOutsideEvent()">
|
<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 *ngFor="let entry of actions; trackBy: trackByActionId" [ngSwitch]="entry.type">
|
||||||
<ng-container *ngSwitchDefault>
|
<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>
|
<adf-icon [value]="entry.icon"></adf-icon>
|
||||||
<span>{{ entry.title | translate }}</span>
|
<span>{{ entry.title | translate }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
@ -96,11 +96,13 @@ describe('ContextMenuComponent', () => {
|
|||||||
expect(contextMenuElements[0].querySelector('span').innerText).toBe(contextItem.title);
|
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');
|
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) {
|
runAction(contentActionRef: ContentActionRef) {
|
||||||
this.extensions.runActionById(actionId);
|
this.extensions.runActionById(contentActionRef.actions.click, {
|
||||||
|
focusedElementOnCloseSelector: '.adf-context-menu-source'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { TestBed, fakeAsync, tick, flush } from '@angular/core/testing';
|
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 { Actions, ofType, EffectsModule } from '@ngrx/effects';
|
||||||
import {
|
import {
|
||||||
AppStore,
|
AppStore,
|
||||||
@ -56,7 +56,7 @@ import { NodeActionsService } from './node-actions.service';
|
|||||||
import { TranslationService, AlfrescoApiService, FileModel, NotificationService } from '@alfresco/adf-core';
|
import { TranslationService, AlfrescoApiService, FileModel, NotificationService } from '@alfresco/adf-core';
|
||||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { MatSnackBarRef, SimpleSnackBar } from '@angular/material/snack-bar';
|
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';
|
import { NewVersionUploaderDataAction, NewVersionUploaderService, NodeAspectService, ViewVersion } from '@alfresco/adf-content-services';
|
||||||
|
|
||||||
describe('ContentManagementService', () => {
|
describe('ContentManagementService', () => {
|
||||||
@ -1410,30 +1410,79 @@ describe('ContentManagementService', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should update node selection after dialog is closed', fakeAsync(() => {
|
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;
|
const node = { entry: { id: '1', name: 'name1' } } as NodeEntry;
|
||||||
spyOn(store, 'dispatch').and.callThrough();
|
spyOn(store, 'dispatch').and.callThrough();
|
||||||
spyOn(dialog, 'open').and.returnValue({
|
spyOn(dialog, 'open').and.returnValue({
|
||||||
afterClosed: () => of(null)
|
afterClosed: () => of(null)
|
||||||
} as MatDialogRef<MatDialog>);
|
} as MatDialogRef<MatDialog>);
|
||||||
|
const payload = {
|
||||||
store.dispatch(new ShareNodeAction(node));
|
...node,
|
||||||
|
...{
|
||||||
expect(store.dispatch['calls'].argsFor(1)[0]).toEqual(new SetSelectedNodesAction([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(() => {
|
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;
|
const node = { entry: { id: '1', name: 'name1' } } as NodeEntry;
|
||||||
spyOn(appHookService.linksUnshared, 'next').and.callThrough();
|
spyOn(appHookService.linksUnshared, 'next').and.callThrough();
|
||||||
spyOn(dialog, 'open').and.returnValue({
|
spyOn(dialog, 'open').and.returnValue({
|
||||||
afterClosed: () => of(node)
|
afterClosed: () => of(node)
|
||||||
} as MatDialogRef<MatDialog>);
|
} as MatDialogRef<MatDialog>);
|
||||||
|
store.dispatch(
|
||||||
store.dispatch(new ShareNodeAction(node));
|
new ShareNodeAction({
|
||||||
|
...node,
|
||||||
|
...{
|
||||||
|
focusedElementOnCloseSelector: 'some-selector'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
tick();
|
tick();
|
||||||
flush();
|
flush();
|
||||||
|
|
||||||
expect(appHookService.linksUnshared.next).toHaveBeenCalled();
|
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', () => {
|
describe('Unlock Node', () => {
|
||||||
@ -1544,8 +1593,10 @@ describe('ContentManagementService', () => {
|
|||||||
showVersionsOnly: true,
|
showVersionsOnly: true,
|
||||||
title: 'VERSION.DIALOG.TITLE'
|
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)[0]).toEqual(expectedArgument);
|
||||||
|
expect(spyOnOpenUploadNewVersionDialog['calls'].argsFor(0)[2]).toEqual(elementToFocusSelector);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should dispatch ReloadDocumentListAction if dialog emit refresh action', () => {
|
it('should dispatch ReloadDocumentListAction if dialog emit refresh action', () => {
|
||||||
@ -1615,6 +1666,37 @@ describe('ContentManagementService', () => {
|
|||||||
|
|
||||||
expect(alfrescoApiService.nodeUpdated.next).toHaveBeenCalledWith(newNode);
|
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', () => {
|
describe('aspect list dialog', () => {
|
||||||
@ -1633,21 +1715,50 @@ describe('ContentManagementService', () => {
|
|||||||
createdAt: null,
|
createdAt: null,
|
||||||
createdByUser: null
|
createdByUser: null
|
||||||
};
|
};
|
||||||
|
const elementToFocusSelector = 'some-selector';
|
||||||
|
|
||||||
spyOn(contentApi, 'getNodeInfo').and.returnValue(of(responseNode));
|
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', () => {
|
it('should open dialog for managing the aspects', () => {
|
||||||
spyOn(nodeAspectService, 'updateNodeAspects').and.stub();
|
spyOn(nodeAspectService, 'updateNodeAspects').and.stub();
|
||||||
const fakeNode = { entry: { id: 'fake-node-id' } };
|
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'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class ContentManagementService {
|
export class ContentManagementService {
|
||||||
|
private readonly createMenuButtonSelector = 'app-create-menu button';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private alfrescoApiService: AlfrescoApiService,
|
private alfrescoApiService: AlfrescoApiService,
|
||||||
private store: Store<AppStore>,
|
private store: Store<AppStore>,
|
||||||
@ -128,32 +130,32 @@ export class ContentManagementService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
manageVersions(node: any) {
|
manageVersions(node: any, focusedElementOnCloseSelector?: string) {
|
||||||
if (node && node.entry) {
|
if (node && node.entry) {
|
||||||
// shared and favorite
|
// shared and favorite
|
||||||
const id = node.entry.nodeId || (node as any).entry.guid;
|
const id = node.entry.nodeId || (node as any).entry.guid;
|
||||||
|
|
||||||
if (id) {
|
if (id) {
|
||||||
this.contentApi.getNodeInfo(id).subscribe((entry) => {
|
this.contentApi.getNodeInfo(id).subscribe((entry) => {
|
||||||
this.openVersionManagerDialog(entry);
|
this.openVersionManagerDialog(entry, focusedElementOnCloseSelector);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.openVersionManagerDialog(node.entry);
|
this.openVersionManagerDialog(node.entry, focusedElementOnCloseSelector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
manageAspects(node: any) {
|
manageAspects(node: any, focusedElementOnCloseSelector?: string) {
|
||||||
if (node && node.entry) {
|
if (node && node.entry) {
|
||||||
// shared and favorite
|
// shared and favorite
|
||||||
const id = node.entry.nodeId || (node as any).entry.guid;
|
const id = node.entry.nodeId || (node as any).entry.guid;
|
||||||
|
|
||||||
if (id) {
|
if (id) {
|
||||||
this.contentApi.getNodeInfo(id).subscribe((entry) => {
|
this.contentApi.getNodeInfo(id).subscribe((entry) => {
|
||||||
this.openAspectListDialog(entry);
|
this.openAspectListDialog(entry, focusedElementOnCloseSelector);
|
||||||
});
|
});
|
||||||
} else {
|
} 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) {
|
if (node && node.entry) {
|
||||||
// shared and favorite
|
// shared and favorite
|
||||||
const id = node.entry.nodeId || (node as any).entry.guid;
|
const id = node.entry.nodeId || (node as any).entry.guid;
|
||||||
|
|
||||||
if (id) {
|
if (id) {
|
||||||
this.contentApi.getNodeInfo(id).subscribe((entry) => {
|
this.contentApi.getNodeInfo(id).subscribe((entry) => {
|
||||||
this.openShareLinkDialog({ entry });
|
this.openShareLinkDialog({ entry }, focusedElementOnCloseSelector);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.openShareLinkDialog(node);
|
this.openShareLinkDialog(node, focusedElementOnCloseSelector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
openShareLinkDialog(node) {
|
openShareLinkDialog(node, focusedElementOnCloseSelector?: string) {
|
||||||
this.store
|
this.store
|
||||||
.select(getSharedUrl)
|
.select(getSharedUrl)
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
@ -214,6 +216,7 @@ export class ContentManagementService {
|
|||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.store.dispatch(new SetSelectedNodesAction([node]));
|
this.store.dispatch(new SetSelectedNodesAction([node]));
|
||||||
this.appHookService.linksUnshared.next();
|
this.appHookService.linksUnshared.next();
|
||||||
|
this.focusAfterClose(focusedElementOnCloseSelector);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -237,11 +240,11 @@ export class ContentManagementService {
|
|||||||
if (node) {
|
if (node) {
|
||||||
this.store.dispatch(new ReloadDocumentListAction());
|
this.store.dispatch(new ReloadDocumentListAction());
|
||||||
}
|
}
|
||||||
ContentManagementService.focusCreateMenuButton();
|
this.focusAfterClose(this.createMenuButtonSelector);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
editFolder(folder: MinimalNodeEntity) {
|
editFolder(folder: MinimalNodeEntity, focusedElementOnCloseSelector?: string) {
|
||||||
if (!folder) {
|
if (!folder) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -261,6 +264,7 @@ export class ContentManagementService {
|
|||||||
if (node) {
|
if (node) {
|
||||||
this.alfrescoApiService.nodeUpdated.next(node);
|
this.alfrescoApiService.nodeUpdated.next(node);
|
||||||
}
|
}
|
||||||
|
this.focusAfterClose(focusedElementOnCloseSelector);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,7 +282,7 @@ export class ContentManagementService {
|
|||||||
if (node) {
|
if (node) {
|
||||||
this.appHookService.libraryCreated.next(node);
|
this.appHookService.libraryCreated.next(node);
|
||||||
}
|
}
|
||||||
ContentManagementService.focusCreateMenuButton();
|
this.focusAfterClose(this.createMenuButtonSelector);
|
||||||
}),
|
}),
|
||||||
map((node: SiteEntry) => {
|
map((node: SiteEntry) => {
|
||||||
if (node && node.entry && node.entry.guid) {
|
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, {
|
const dialogRef = this.dialogRef.open(ConfirmDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
title: 'APP.DIALOGS.CONFIRM_LEAVE.TITLE',
|
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>) {
|
copyNodes(nodes: Array<MinimalNodeEntity>, focusedElementOnCloseSelector?: string) {
|
||||||
zip(this.nodeActionsService.copyNodes(nodes), this.nodeActionsService.contentCopied).subscribe(
|
zip(this.nodeActionsService.copyNodes(nodes, undefined, focusedElementOnCloseSelector), this.nodeActionsService.contentCopied).subscribe(
|
||||||
(result) => {
|
(result) => {
|
||||||
const [operationResult, newItems] = result;
|
const [operationResult, newItems] = result;
|
||||||
this.showCopyMessage(operationResult, nodes, newItems);
|
this.showCopyMessage(operationResult, nodes, newItems);
|
||||||
@ -433,10 +438,10 @@ export class ContentManagementService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
moveNodes(nodes: Array<MinimalNodeEntity>) {
|
moveNodes(nodes: Array<MinimalNodeEntity>, focusedElementOnCloseSelector?: string) {
|
||||||
const permissionForMove = '!';
|
const permissionForMove = '!';
|
||||||
|
|
||||||
zip(this.nodeActionsService.moveNodes(nodes, permissionForMove), this.nodeActionsService.contentMoved).subscribe(
|
zip(this.nodeActionsService.moveNodes(nodes, permissionForMove, focusedElementOnCloseSelector), this.nodeActionsService.contentMoved).subscribe(
|
||||||
(result) => {
|
(result) => {
|
||||||
const [operationResult, moveResponse] = result;
|
const [operationResult, moveResponse] = result;
|
||||||
this.showMoveMessage(nodes, operationResult, moveResponse);
|
this.showMoveMessage(nodes, operationResult, moveResponse);
|
||||||
@ -570,7 +575,7 @@ export class ContentManagementService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private openVersionManagerDialog(node: any) {
|
private openVersionManagerDialog(node: any, focusedElementOnCloseSelector?: string) {
|
||||||
// workaround Shared
|
// workaround Shared
|
||||||
if (node.isFile || node.nodeId) {
|
if (node.isFile || node.nodeId) {
|
||||||
const newVersionUploaderDialogData: NewVersionUploaderDialogData = {
|
const newVersionUploaderDialogData: NewVersionUploaderDialogData = {
|
||||||
@ -579,21 +584,23 @@ export class ContentManagementService {
|
|||||||
title: 'VERSION.DIALOG.TITLE'
|
title: 'VERSION.DIALOG.TITLE'
|
||||||
};
|
};
|
||||||
this.newVersionUploaderService
|
this.newVersionUploaderService
|
||||||
.openUploadNewVersionDialog(newVersionUploaderDialogData, { width: '630px', role: 'dialog' })
|
.openUploadNewVersionDialog(newVersionUploaderDialogData, { width: '630px', role: 'dialog' }, focusedElementOnCloseSelector)
|
||||||
.subscribe((newVersionUploaderData: NewVersionUploaderData) => {
|
.subscribe({
|
||||||
switch (newVersionUploaderData.action) {
|
next: (newVersionUploaderData: NewVersionUploaderData) => {
|
||||||
case NewVersionUploaderDataAction.refresh:
|
switch (newVersionUploaderData.action) {
|
||||||
this.store.dispatch(new ReloadDocumentListAction());
|
case NewVersionUploaderDataAction.refresh:
|
||||||
break;
|
this.store.dispatch(new ReloadDocumentListAction());
|
||||||
case NewVersionUploaderDataAction.view:
|
break;
|
||||||
this.store.dispatch(
|
case NewVersionUploaderDataAction.view:
|
||||||
new ViewNodeVersionAction(node.id, newVersionUploaderData.versionId, {
|
this.store.dispatch(
|
||||||
location: this.router.url
|
new ViewNodeVersionAction(node.id, newVersionUploaderData.versionId, {
|
||||||
})
|
location: this.router.url
|
||||||
);
|
})
|
||||||
break;
|
);
|
||||||
default:
|
break;
|
||||||
break;
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -601,10 +608,10 @@ export class ContentManagementService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private openAspectListDialog(node: any) {
|
private openAspectListDialog(node: any, focusedElementOnCloseSelector?: string) {
|
||||||
// workaround Shared
|
// workaround Shared
|
||||||
if (node.isFile || node.id) {
|
if (node.isFile || node.id) {
|
||||||
this.nodeAspectService.updateNodeAspects(node.id);
|
this.nodeAspectService.updateNodeAspects(node.id, focusedElementOnCloseSelector);
|
||||||
} else {
|
} else {
|
||||||
this.store.dispatch(new SnackbarErrorAction('APP.MESSAGES.ERRORS.PERMISSION'));
|
this.store.dispatch(new SnackbarErrorAction('APP.MESSAGES.ERRORS.PERMISSION'));
|
||||||
}
|
}
|
||||||
@ -1080,7 +1087,9 @@ export class ContentManagementService {
|
|||||||
.subscribe(() => this.undoMoveNodes(moveResponse, initialParentId));
|
.subscribe(() => this.undoMoveNodes(moveResponse, initialParentId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static focusCreateMenuButton(): void {
|
private focusAfterClose(focusedElementSelector: string): void {
|
||||||
document.querySelector<HTMLElement>('app-create-menu button').focus();
|
if (focusedElementSelector) {
|
||||||
|
document.querySelector<HTMLElement>(focusedElementSelector).focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,9 @@ describe('NodeActionsService', () => {
|
|||||||
|
|
||||||
describe('ContentNodeSelector configuration', () => {
|
describe('ContentNodeSelector configuration', () => {
|
||||||
it('should validate selection when allowableOperation has `create`', () => {
|
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' } }];
|
const contentEntities = [new TestNode(), { entry: { nodeId: '1234' } }];
|
||||||
service.getContentNodeSelection(NodeAction.CHOOSE, contentEntities as NodeEntry[]);
|
service.getContentNodeSelection(NodeAction.CHOOSE, contentEntities as NodeEntry[]);
|
||||||
|
|
||||||
@ -131,7 +133,9 @@ describe('NodeActionsService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should invalidate selection when allowableOperation does not have `create`', () => {
|
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' } }];
|
const contentEntities = [new TestNode(), { entry: { nodeId: '1234' } }];
|
||||||
service.getContentNodeSelection(NodeAction.CHOOSE, contentEntities as NodeEntry[]);
|
service.getContentNodeSelection(NodeAction.CHOOSE, contentEntities as NodeEntry[]);
|
||||||
|
|
||||||
@ -147,7 +151,9 @@ describe('NodeActionsService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should invalidate selection if isSite', () => {
|
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' } }];
|
const contentEntities = [new TestNode(), { entry: { nodeId: '1234' } }];
|
||||||
service.getContentNodeSelection(NodeAction.CHOOSE, contentEntities as NodeEntry[]);
|
service.getContentNodeSelection(NodeAction.CHOOSE, contentEntities as NodeEntry[]);
|
||||||
|
|
||||||
@ -164,7 +170,9 @@ describe('NodeActionsService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should validate selection if not a Site', () => {
|
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' } }];
|
const contentEntities = [new TestNode(), { entry: { nodeId: '1234' } }];
|
||||||
service.getContentNodeSelection(NodeAction.CHOOSE, contentEntities as NodeEntry[]);
|
service.getContentNodeSelection(NodeAction.CHOOSE, contentEntities as NodeEntry[]);
|
||||||
|
|
||||||
@ -280,7 +288,7 @@ describe('NodeActionsService', () => {
|
|||||||
|
|
||||||
spyOn(dialog, 'open').and.callFake((_contentNodeSelectorComponent: any, data: any) => {
|
spyOn(dialog, 'open').and.callFake((_contentNodeSelectorComponent: any, data: any) => {
|
||||||
dialogData = data;
|
dialogData = data;
|
||||||
return { componentInstance: {} } as MatDialogRef<any>;
|
return { componentInstance: {}, afterClosed: of } as MatDialogRef<any>;
|
||||||
});
|
});
|
||||||
|
|
||||||
service.copyNodes([fileToCopy, folderToCopy]);
|
service.copyNodes([fileToCopy, folderToCopy]);
|
||||||
@ -335,7 +343,7 @@ describe('NodeActionsService', () => {
|
|||||||
subject.next([destinationFolder.entry]);
|
subject.next([destinationFolder.entry]);
|
||||||
|
|
||||||
expect(spyOnBatchOperation.calls.count()).toEqual(1);
|
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', () => {
|
it('should use the custom data object with custom rowFilter & imageResolver & title with destination picker', () => {
|
||||||
@ -346,12 +354,12 @@ describe('NodeActionsService', () => {
|
|||||||
let dialogData = null;
|
let dialogData = null;
|
||||||
const spyOnDialog = spyOn(dialog, 'open').and.callFake((_contentNodeSelectorComponent: any, data: any) => {
|
const spyOnDialog = spyOn(dialog, 'open').and.callFake((_contentNodeSelectorComponent: any, data: any) => {
|
||||||
dialogData = data;
|
dialogData = data;
|
||||||
return { componentInstance: {} } as MatDialogRef<any>;
|
return { componentInstance: {}, afterClosed: of } as MatDialogRef<any>;
|
||||||
});
|
});
|
||||||
|
|
||||||
service.copyNodes([fileToCopy, folderToCopy]);
|
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(spyOnDestinationPicker.calls.count()).toEqual(1);
|
||||||
expect(spyOnDialog.calls.count()).toEqual(1);
|
expect(spyOnDialog.calls.count()).toEqual(1);
|
||||||
|
|
||||||
@ -388,7 +396,7 @@ describe('NodeActionsService', () => {
|
|||||||
let dialogData: any;
|
let dialogData: any;
|
||||||
spyOn(dialog, 'open').and.callFake((_contentNodeSelectorComponent: any, data: any) => {
|
spyOn(dialog, 'open').and.callFake((_contentNodeSelectorComponent: any, data: any) => {
|
||||||
dialogData = data;
|
dialogData = data;
|
||||||
return { componentInstance: {} } as MatDialogRef<any>;
|
return { componentInstance: {}, afterClosed: of } as MatDialogRef<any>;
|
||||||
});
|
});
|
||||||
|
|
||||||
service.copyNodes([{ entry: { id: 'entry-id', name: 'entry-name' } }]);
|
service.copyNodes([{ entry: { id: 'entry-id', name: 'entry-name' } }]);
|
||||||
@ -410,7 +418,7 @@ describe('NodeActionsService', () => {
|
|||||||
let dialogData = null;
|
let dialogData = null;
|
||||||
spyOn(dialog, 'open').and.callFake((_contentNodeSelectorComponent: any, data: any) => {
|
spyOn(dialog, 'open').and.callFake((_contentNodeSelectorComponent: any, data: any) => {
|
||||||
dialogData = data;
|
dialogData = data;
|
||||||
return { componentInstance: {} } as MatDialogRef<any>;
|
return { componentInstance: {}, afterClosed: of } as MatDialogRef<any>;
|
||||||
});
|
});
|
||||||
|
|
||||||
service.copyNodes([{ entry: { id: 'entry-id' } }]);
|
service.copyNodes([{ entry: { id: 'entry-id' } }]);
|
||||||
@ -736,7 +744,7 @@ describe('NodeActionsService', () => {
|
|||||||
service.moveNodes([fileToMove, folderToMove], permissionToMove);
|
service.moveNodes([fileToMove, folderToMove], permissionToMove);
|
||||||
subject.next([destinationFolder.entry]);
|
subject.next([destinationFolder.entry]);
|
||||||
|
|
||||||
expect(spyOnBatchOperation).toHaveBeenCalledWith(NodeAction.MOVE, [fileToMove, folderToMove], permissionToMove);
|
expect(spyOnBatchOperation).toHaveBeenCalledWith(NodeAction.MOVE, [fileToMove, folderToMove], permissionToMove, undefined);
|
||||||
expect(spyOnDestinationPicker).toHaveBeenCalled();
|
expect(spyOnDestinationPicker).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -749,7 +757,7 @@ describe('NodeActionsService', () => {
|
|||||||
service.moveNodes([fileToMove, folderToMove], permissionToMove);
|
service.moveNodes([fileToMove, folderToMove], permissionToMove);
|
||||||
subject.next([destinationFolder.entry]);
|
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();
|
expect(spyOnDestinationPicker).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -78,9 +78,10 @@ export class NodeActionsService {
|
|||||||
*
|
*
|
||||||
* @param contentEntities nodes to copy
|
* @param contentEntities nodes to copy
|
||||||
* @param permission permission which is needed to apply the action
|
* @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> {
|
copyNodes(contentEntities: any[], permission?: string, focusedElementOnCloseSelector?: string): Subject<string> {
|
||||||
return this.doBatchOperation(NodeAction.COPY, contentEntities, permission);
|
return this.doBatchOperation(NodeAction.COPY, contentEntities, permission, focusedElementOnCloseSelector);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,9 +89,10 @@ export class NodeActionsService {
|
|||||||
*
|
*
|
||||||
* @param contentEntities nodes to move
|
* @param contentEntities nodes to move
|
||||||
* @param permission permission which is needed to apply the action
|
* @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> {
|
moveNodes(contentEntities: any[], permission?: string, focusedElementOnCloseSelector?: string): Subject<string> {
|
||||||
return this.doBatchOperation(NodeAction.MOVE, contentEntities, permission);
|
return this.doBatchOperation(NodeAction.MOVE, contentEntities, permission, focusedElementOnCloseSelector);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -99,14 +101,15 @@ export class NodeActionsService {
|
|||||||
* @param action the action to perform (copy|move)
|
* @param action the action to perform (copy|move)
|
||||||
* @param contentEntities the contentEntities which have to have the action performed on
|
* @param contentEntities the contentEntities which have to have the action performed on
|
||||||
* @param permission permission which is needed to apply the action
|
* @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>();
|
const observable: Subject<string> = new Subject<string>();
|
||||||
|
|
||||||
if (!this.isEntryEntitiesArray(contentEntities)) {
|
if (!this.isEntryEntitiesArray(contentEntities)) {
|
||||||
observable.error(new Error(JSON.stringify({ error: { statusCode: 400 } })));
|
observable.error(new Error(JSON.stringify({ error: { statusCode: 400 } })));
|
||||||
} else if (this.checkPermission(action, contentEntities, permission)) {
|
} else if (this.checkPermission(action, contentEntities, permission)) {
|
||||||
const destinationSelection = this.getContentNodeSelection(action, contentEntities);
|
const destinationSelection = this.getContentNodeSelection(action, contentEntities, focusedElementOnCloseSelector);
|
||||||
destinationSelection.subscribe((selections: MinimalNodeEntryEntity[]) => {
|
destinationSelection.subscribe((selections: MinimalNodeEntryEntity[]) => {
|
||||||
const contentEntry = contentEntities[0].entry;
|
const contentEntry = contentEntities[0].entry;
|
||||||
// Check if there's nodeId for Shared Files
|
// Check if there's nodeId for Shared Files
|
||||||
@ -171,7 +174,11 @@ export class NodeActionsService {
|
|||||||
return entryParentId;
|
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 currentParentFolderId = this.getEntryParentId(contentEntities[0].entry);
|
||||||
|
|
||||||
const customDropdown = new SitePaging({
|
const customDropdown = new SitePaging({
|
||||||
@ -211,12 +218,15 @@ export class NodeActionsService {
|
|||||||
excludeSiteContent: ContentNodeDialogService.nonDocumentSiteContent
|
excludeSiteContent: ContentNodeDialogService.nonDocumentSiteContent
|
||||||
};
|
};
|
||||||
|
|
||||||
this.dialog.open(ContentNodeSelectorComponent, {
|
this.dialog
|
||||||
data,
|
.open(ContentNodeSelectorComponent, {
|
||||||
panelClass: 'adf-content-node-selector-dialog',
|
data,
|
||||||
width: '630px',
|
panelClass: 'adf-content-node-selector-dialog',
|
||||||
role: 'dialog'
|
width: '630px',
|
||||||
});
|
role: 'dialog'
|
||||||
|
})
|
||||||
|
.afterClosed()
|
||||||
|
.subscribe(() => this.focusAfterClose(focusedElementOnCloseSelector));
|
||||||
|
|
||||||
data.select.subscribe({
|
data.select.subscribe({
|
||||||
complete: this.close.bind(this)
|
complete: this.close.bind(this)
|
||||||
@ -687,4 +697,10 @@ export class NodeActionsService {
|
|||||||
return moveStatus;
|
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 { Actions, ofType, createEffect } from '@ngrx/effects';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { map, take } from 'rxjs/operators';
|
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';
|
import { ContentUrlService } from '../../services/content-url.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -49,7 +49,7 @@ export class DownloadEffects {
|
|||||||
this.actions$.pipe(
|
this.actions$.pipe(
|
||||||
ofType<DownloadNodesAction>(NodeActionTypes.Download),
|
ofType<DownloadNodesAction>(NodeActionTypes.Download),
|
||||||
map((action) => {
|
map((action) => {
|
||||||
if (action.payload && action.payload.length > 0) {
|
if (Array.isArray(action.payload) && action.payload?.length > 0) {
|
||||||
this.downloadNodes(action.payload);
|
this.downloadNodes(action.payload);
|
||||||
} else {
|
} else {
|
||||||
this.store
|
this.store
|
||||||
@ -64,7 +64,7 @@ export class DownloadEffects {
|
|||||||
if (version) {
|
if (version) {
|
||||||
this.downloadFileVersion(selection.nodes[0].entry, version.entry);
|
this.downloadFileVersion(selection.nodes[0].entry, version.entry);
|
||||||
} else {
|
} else {
|
||||||
this.downloadNodes(selection.nodes);
|
this.downloadNodes(selection.nodes, (action.payload as ModalConfiguration)?.focusedElementOnCloseSelector);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -75,7 +75,7 @@ export class DownloadEffects {
|
|||||||
{ dispatch: false }
|
{ dispatch: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
private downloadNodes(toDownload: Array<MinimalNodeEntity>) {
|
private downloadNodes(toDownload: Array<MinimalNodeEntity>, focusedElementSelector?: string) {
|
||||||
const nodes = toDownload.map((node) => {
|
const nodes = toDownload.map((node) => {
|
||||||
const { id, nodeId, name, isFile, isFolder } = node.entry as any;
|
const { id, nodeId, name, isFile, isFolder } = node.entry as any;
|
||||||
|
|
||||||
@ -92,16 +92,16 @@ export class DownloadEffects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nodes.length === 1) {
|
if (nodes.length === 1) {
|
||||||
this.downloadNode(nodes[0]);
|
this.downloadNode(nodes[0], focusedElementSelector);
|
||||||
} else {
|
} else {
|
||||||
this.downloadZip(nodes);
|
this.downloadZip(nodes, focusedElementSelector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private downloadNode(node: NodeInfo) {
|
private downloadNode(node: NodeInfo, focusedElementSelector?: string) {
|
||||||
if (node) {
|
if (node) {
|
||||||
if (node.isFolder) {
|
if (node.isFolder) {
|
||||||
this.downloadZip([node]);
|
this.downloadZip([node], focusedElementSelector);
|
||||||
} else {
|
} else {
|
||||||
this.downloadFile(node);
|
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) {
|
if (nodes && nodes.length > 0) {
|
||||||
const nodeIds = nodes.map((node) => node.id);
|
const nodeIds = nodes.map((node) => node.id);
|
||||||
|
|
||||||
this.dialog.open(DownloadZipDialogComponent, {
|
this.dialog
|
||||||
width: '600px',
|
.open(DownloadZipDialogComponent, {
|
||||||
disableClose: true,
|
width: '600px',
|
||||||
data: {
|
disableClose: true,
|
||||||
nodeIds
|
data: {
|
||||||
}
|
nodeIds
|
||||||
});
|
}
|
||||||
|
})
|
||||||
|
.afterClosed()
|
||||||
|
.subscribe(() => this.focusAfterClose(focusedElementSelector));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,4 +162,10 @@ export class DownloadEffects {
|
|||||||
private get isSharedLinkPreview() {
|
private get isSharedLinkPreview() {
|
||||||
return location.href.includes('/preview/s/');
|
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 { Actions, ofType, createEffect } from '@ngrx/effects';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { map, mergeMap, take } from 'rxjs/operators';
|
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';
|
import { ContentManagementService } from '../../services/content-management.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -56,7 +56,7 @@ export class LibraryEffects {
|
|||||||
this.actions$.pipe(
|
this.actions$.pipe(
|
||||||
ofType<DeleteLibraryAction>(LibraryActionTypes.Delete),
|
ofType<DeleteLibraryAction>(LibraryActionTypes.Delete),
|
||||||
map((action) => {
|
map((action) => {
|
||||||
if (action.payload) {
|
if (typeof action?.payload === 'string') {
|
||||||
this.content.deleteLibrary(action.payload);
|
this.content.deleteLibrary(action.payload);
|
||||||
} else {
|
} else {
|
||||||
this.store
|
this.store
|
||||||
@ -78,7 +78,7 @@ export class LibraryEffects {
|
|||||||
this.actions$.pipe(
|
this.actions$.pipe(
|
||||||
ofType<LeaveLibraryAction>(LibraryActionTypes.Leave),
|
ofType<LeaveLibraryAction>(LibraryActionTypes.Leave),
|
||||||
map((action) => {
|
map((action) => {
|
||||||
if (action.payload) {
|
if (typeof action.payload === 'string') {
|
||||||
this.content.leaveLibrary(action.payload);
|
this.content.leaveLibrary(action.payload);
|
||||||
} else {
|
} else {
|
||||||
this.store
|
this.store
|
||||||
@ -86,7 +86,7 @@ export class LibraryEffects {
|
|||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe((selection) => {
|
.subscribe((selection) => {
|
||||||
if (selection && selection.library) {
|
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', () => {
|
it('should share node from payload', () => {
|
||||||
spyOn(contentService, 'shareNode').and.stub();
|
spyOn(contentService, 'shareNode').and.stub();
|
||||||
|
|
||||||
const node: any = {};
|
const node: any = {
|
||||||
|
entry: {}
|
||||||
|
};
|
||||||
store.dispatch(new ShareNodeAction(node));
|
store.dispatch(new ShareNodeAction(node));
|
||||||
|
|
||||||
expect(contentService.shareNode).toHaveBeenCalledWith(node);
|
expect(contentService.shareNode).toHaveBeenCalledWith(node, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should share node from active selection', fakeAsync(() => {
|
it('should share node from active selection', fakeAsync(() => {
|
||||||
@ -94,7 +96,7 @@ describe('NodeEffects', () => {
|
|||||||
tick(100);
|
tick(100);
|
||||||
|
|
||||||
store.dispatch(new ShareNodeAction(null));
|
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', () => {
|
it('should do nothing if invoking share with no data', () => {
|
||||||
@ -300,7 +302,7 @@ describe('NodeEffects', () => {
|
|||||||
tick(100);
|
tick(100);
|
||||||
|
|
||||||
store.dispatch(new EditFolderAction(null));
|
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', () => {
|
it('should do nothing if editing folder with no selection and payload', () => {
|
||||||
@ -332,7 +334,7 @@ describe('NodeEffects', () => {
|
|||||||
|
|
||||||
store.dispatch(new CopyNodesAction(null));
|
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', () => {
|
it('should do nothing if invoking copy with no data', () => {
|
||||||
@ -364,7 +366,7 @@ describe('NodeEffects', () => {
|
|||||||
|
|
||||||
store.dispatch(new MoveNodesAction(null));
|
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', () => {
|
it('should do nothing if invoking move with no data', () => {
|
||||||
@ -488,7 +490,7 @@ describe('NodeEffects', () => {
|
|||||||
|
|
||||||
store.dispatch(new ManageAspectsAction(null));
|
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(() => {
|
it('should call aspect dialog from the active folder selection', fakeAsync(() => {
|
||||||
@ -501,7 +503,7 @@ describe('NodeEffects', () => {
|
|||||||
|
|
||||||
store.dispatch(new ManageAspectsAction(null));
|
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';
|
} from '@alfresco/aca-shared/store';
|
||||||
import { ContentManagementService } from '../../services/content-management.service';
|
import { ContentManagementService } from '../../services/content-management.service';
|
||||||
import { ViewUtilService } from '@alfresco/adf-core';
|
import { ViewUtilService } from '@alfresco/adf-core';
|
||||||
|
import { ModalConfiguration } from '@alfresco/aca-shared';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NodeEffects {
|
export class NodeEffects {
|
||||||
@ -69,15 +70,15 @@ export class NodeEffects {
|
|||||||
this.actions$.pipe(
|
this.actions$.pipe(
|
||||||
ofType<ShareNodeAction>(NodeActionTypes.Share),
|
ofType<ShareNodeAction>(NodeActionTypes.Share),
|
||||||
map((action) => {
|
map((action) => {
|
||||||
if (action.payload) {
|
if (action.payload?.entry) {
|
||||||
this.contentService.shareNode(action.payload);
|
this.contentService.shareNode(action.payload, action.payload?.focusedElementOnCloseSelector);
|
||||||
} else {
|
} else {
|
||||||
this.store
|
this.store
|
||||||
.select(getAppSelection)
|
.select(getAppSelection)
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe((selection) => {
|
.subscribe((selection) => {
|
||||||
if (selection && selection.file) {
|
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(
|
this.actions$.pipe(
|
||||||
ofType<EditFolderAction>(NodeActionTypes.EditFolder),
|
ofType<EditFolderAction>(NodeActionTypes.EditFolder),
|
||||||
map((action) => {
|
map((action) => {
|
||||||
if (action.payload) {
|
if (action.payload?.entry) {
|
||||||
this.contentService.editFolder(action.payload);
|
this.contentService.editFolder(action.payload);
|
||||||
} else {
|
} else {
|
||||||
this.store
|
this.store
|
||||||
@ -223,7 +224,7 @@ export class NodeEffects {
|
|||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe((selection) => {
|
.subscribe((selection) => {
|
||||||
if (selection && selection.folder) {
|
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(
|
this.actions$.pipe(
|
||||||
ofType<CopyNodesAction>(NodeActionTypes.Copy),
|
ofType<CopyNodesAction>(NodeActionTypes.Copy),
|
||||||
map((action) => {
|
map((action) => {
|
||||||
if (action.payload && action.payload.length > 0) {
|
if (Array.isArray(action.payload) && action.payload?.length > 0) {
|
||||||
this.contentService.copyNodes(action.payload);
|
this.contentService.copyNodes(action.payload);
|
||||||
} else {
|
} else {
|
||||||
this.store
|
this.store
|
||||||
@ -245,7 +246,7 @@ export class NodeEffects {
|
|||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe((selection) => {
|
.subscribe((selection) => {
|
||||||
if (selection && !selection.isEmpty) {
|
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(
|
this.actions$.pipe(
|
||||||
ofType<MoveNodesAction>(NodeActionTypes.Move),
|
ofType<MoveNodesAction>(NodeActionTypes.Move),
|
||||||
map((action) => {
|
map((action) => {
|
||||||
if (action.payload && action.payload.length > 0) {
|
if (Array.isArray(action.payload) && action.payload?.length > 0) {
|
||||||
this.contentService.moveNodes(action.payload);
|
this.contentService.moveNodes(action.payload);
|
||||||
} else {
|
} else {
|
||||||
this.store
|
this.store
|
||||||
@ -267,7 +268,7 @@ export class NodeEffects {
|
|||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe((selection) => {
|
.subscribe((selection) => {
|
||||||
if (selection && !selection.isEmpty) {
|
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(
|
this.actions$.pipe(
|
||||||
ofType<ManagePermissionsAction>(NodeActionTypes.ManagePermissions),
|
ofType<ManagePermissionsAction>(NodeActionTypes.ManagePermissions),
|
||||||
map((action) => {
|
map((action) => {
|
||||||
if (action && action.payload) {
|
if (action?.payload?.entry) {
|
||||||
const route = 'personal-files/details';
|
const route = 'personal-files/details';
|
||||||
this.store.dispatch(new NavigateRouteAction([route, action.payload.entry.id, 'permissions']));
|
this.store.dispatch(new NavigateRouteAction([route, action.payload.entry.id, 'permissions']));
|
||||||
} else {
|
} else {
|
||||||
@ -305,7 +306,7 @@ export class NodeEffects {
|
|||||||
this.actions$.pipe(
|
this.actions$.pipe(
|
||||||
ofType<ExpandInfoDrawerAction>(NodeActionTypes.ExpandInfoDrawer),
|
ofType<ExpandInfoDrawerAction>(NodeActionTypes.ExpandInfoDrawer),
|
||||||
map((action) => {
|
map((action) => {
|
||||||
if (action && action.payload) {
|
if (action?.payload?.entry) {
|
||||||
const route = 'personal-files/details';
|
const route = 'personal-files/details';
|
||||||
this.store.dispatch(new NavigateRouteAction([route, action.payload.entry.id]));
|
this.store.dispatch(new NavigateRouteAction([route, action.payload.entry.id]));
|
||||||
} else {
|
} else {
|
||||||
@ -329,7 +330,7 @@ export class NodeEffects {
|
|||||||
this.actions$.pipe(
|
this.actions$.pipe(
|
||||||
ofType<ManageVersionsAction>(NodeActionTypes.ManageVersions),
|
ofType<ManageVersionsAction>(NodeActionTypes.ManageVersions),
|
||||||
map((action) => {
|
map((action) => {
|
||||||
if (action && action.payload) {
|
if (action?.payload?.entry) {
|
||||||
this.contentService.manageVersions(action.payload);
|
this.contentService.manageVersions(action.payload);
|
||||||
} else {
|
} else {
|
||||||
this.store
|
this.store
|
||||||
@ -337,7 +338,7 @@ export class NodeEffects {
|
|||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe((selection) => {
|
.subscribe((selection) => {
|
||||||
if (selection && selection.file) {
|
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(
|
this.actions$.pipe(
|
||||||
ofType<ManageAspectsAction>(NodeActionTypes.ChangeAspects),
|
ofType<ManageAspectsAction>(NodeActionTypes.ChangeAspects),
|
||||||
map((action) => {
|
map((action) => {
|
||||||
if (action && action.payload) {
|
if (action?.payload?.entry) {
|
||||||
this.contentService.manageAspects(action.payload);
|
this.contentService.manageAspects(action.payload);
|
||||||
} else {
|
} else {
|
||||||
this.store
|
this.store
|
||||||
@ -403,7 +404,7 @@ export class NodeEffects {
|
|||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe((selection) => {
|
.subscribe((selection) => {
|
||||||
if (selection && !selection.isEmpty) {
|
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(
|
this.actions$.pipe(
|
||||||
ofType<ManageRulesAction>(NodeActionTypes.ManageRules),
|
ofType<ManageRulesAction>(NodeActionTypes.ManageRules),
|
||||||
map((action) => {
|
map((action) => {
|
||||||
if (action && action.payload) {
|
if (action?.payload?.entry) {
|
||||||
this.store.dispatch(new NavigateRouteAction(['nodes', action.payload.entry.id, 'rules']));
|
this.store.dispatch(new NavigateRouteAction(['nodes', action.payload.entry.id, 'rules']));
|
||||||
} else {
|
} else {
|
||||||
this.store
|
this.store
|
||||||
|
@ -41,12 +41,14 @@ import { of } from 'rxjs';
|
|||||||
import { catchError, map, take } from 'rxjs/operators';
|
import { catchError, map, take } from 'rxjs/operators';
|
||||||
import { ContentManagementService } from '../../services/content-management.service';
|
import { ContentManagementService } from '../../services/content-management.service';
|
||||||
import { MinimalNodeEntryEntity } from '@alfresco/js-api';
|
import { MinimalNodeEntryEntity } from '@alfresco/js-api';
|
||||||
|
import { ModalConfiguration } from '@alfresco/aca-shared';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UploadEffects {
|
export class UploadEffects {
|
||||||
private fileInput: HTMLInputElement;
|
private fileInput: HTMLInputElement;
|
||||||
private folderInput: HTMLInputElement;
|
private folderInput: HTMLInputElement;
|
||||||
private fileVersionInput: HTMLInputElement;
|
private fileVersionInput: HTMLInputElement;
|
||||||
|
private readonly createMenuButtonSelector = 'app-create-menu button';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<AppStore>,
|
private store: Store<AppStore>,
|
||||||
@ -90,7 +92,7 @@ export class UploadEffects {
|
|||||||
this.actions$.pipe(
|
this.actions$.pipe(
|
||||||
ofType<UploadFilesAction>(UploadActionTypes.UploadFiles),
|
ofType<UploadFilesAction>(UploadActionTypes.UploadFiles),
|
||||||
map(() => {
|
map(() => {
|
||||||
this.registerFocusingCreateMenuButton(this.fileInput);
|
this.registerFocusingElementAfterModalClose(this.fileInput, this.createMenuButtonSelector);
|
||||||
this.fileInput.click();
|
this.fileInput.click();
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
@ -102,7 +104,7 @@ export class UploadEffects {
|
|||||||
this.actions$.pipe(
|
this.actions$.pipe(
|
||||||
ofType<UploadFolderAction>(UploadActionTypes.UploadFolder),
|
ofType<UploadFolderAction>(UploadActionTypes.UploadFolder),
|
||||||
map(() => {
|
map(() => {
|
||||||
this.registerFocusingCreateMenuButton(this.folderInput);
|
this.registerFocusingElementAfterModalClose(this.folderInput, this.createMenuButtonSelector);
|
||||||
this.folderInput.click();
|
this.folderInput.click();
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
@ -114,11 +116,15 @@ export class UploadEffects {
|
|||||||
this.actions$.pipe(
|
this.actions$.pipe(
|
||||||
ofType<UploadFileVersionAction>(UploadActionTypes.UploadFileVersion),
|
ofType<UploadFileVersionAction>(UploadActionTypes.UploadFileVersion),
|
||||||
map((action) => {
|
map((action) => {
|
||||||
if (action?.payload) {
|
if (action?.payload instanceof CustomEvent) {
|
||||||
const node = action?.payload?.detail?.data?.node?.entry;
|
const node = action?.payload?.detail?.data?.node?.entry;
|
||||||
const file: any = action?.payload?.detail?.files[0]?.file;
|
const file: any = action?.payload?.detail?.files[0]?.file;
|
||||||
this.contentService.versionUpdateDialog(node, 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();
|
this.fileVersionInput.click();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -199,18 +205,18 @@ export class UploadEffects {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private registerFocusingCreateMenuButton(input: HTMLInputElement): void {
|
private registerFocusingElementAfterModalClose(input: HTMLInputElement, focusedElementSelector: string): void {
|
||||||
input.addEventListener(
|
input.addEventListener(
|
||||||
'click',
|
'click',
|
||||||
() => {
|
() => {
|
||||||
window.addEventListener(
|
window.addEventListener(
|
||||||
'focus',
|
'focus',
|
||||||
() => {
|
() => {
|
||||||
const createMenuButton = document.querySelector<HTMLElement>('app-create-menu button');
|
const elementToFocus = document.querySelector<HTMLElement>(focusedElementSelector);
|
||||||
createMenuButton.addEventListener('focus', () => createMenuButton.classList.add('cdk-program-focused'), {
|
elementToFocus.addEventListener('focus', () => elementToFocus.classList.add('cdk-program-focused'), {
|
||||||
once: true
|
once: true
|
||||||
});
|
});
|
||||||
createMenuButton.focus();
|
elementToFocus.focus();
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
once: true
|
once: true
|
||||||
|
88
package-lock.json
generated
88
package-lock.json
generated
@ -11,9 +11,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@alfresco/adf-cli": {
|
"@alfresco/adf-cli": {
|
||||||
"version": "6.0.0-A.1-37352",
|
"version": "6.0.0-A.1-37376",
|
||||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-cli/-/adf-cli-6.0.0-A.1-37352.tgz",
|
"resolved": "https://registry.npmjs.org/@alfresco/adf-cli/-/adf-cli-6.0.0-A.1-37376.tgz",
|
||||||
"integrity": "sha512-lM//JUPyBmyO9PVDd628VFyumMJElBKNDvy6E0Yv/iKZmj2S/93pCFhkjnnbG/hOMNAIy5HePOvwOHQ9+vQAgg==",
|
"integrity": "sha512-sEKwZ9DS4CAzub6oKOmJGFoLzc4esMW4859GnbLVU9V8pBZ+KPIfRECY3AsCrRvbuK7dSM8EQgsrT8KDb9IZDg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@alfresco/js-api": "5.2.0",
|
"@alfresco/js-api": "5.2.0",
|
||||||
@ -28,17 +28,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@alfresco/adf-content-services": {
|
"@alfresco/adf-content-services": {
|
||||||
"version": "6.0.0-A.1-37352",
|
"version": "6.0.0-A.1-37376",
|
||||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-6.0.0-A.1-37352.tgz",
|
"resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-6.0.0-A.1-37376.tgz",
|
||||||
"integrity": "sha512-vKtVJDl7WE19WkbB9KHfeka5lnSBOUFAEwjBsSr/UGhNFkQn0zSS1I4CXhjY5h0o+X31JVuIzVLfPqAWiEOZkA==",
|
"integrity": "sha512-QrwadBgJFG4n7iaUJfirhYPEWCO+BD1YiPBlo3+gK9LJvnaHiAiiAFbnXqaa2FY1RlFm6Td6NH0yoHJtwQH+sQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@alfresco/adf-core": {
|
"@alfresco/adf-core": {
|
||||||
"version": "6.0.0-A.1-37352",
|
"version": "6.0.0-A.1-37376",
|
||||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-6.0.0-A.1-37352.tgz",
|
"resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-6.0.0-A.1-37376.tgz",
|
||||||
"integrity": "sha512-zGvZkpIYTaUgZLzyGWBK17MCA+HOQbEEefr3V3KisuLFgCXWwD2GyGn1xSba+kp6CDbabGjfTG/2pG0oDk8NeA==",
|
"integrity": "sha512-NryzWdDie9eyrp0a7lC1P+6R0nXp7KzoHfIVrWO1rNhPWBhYgJlRHPP44KBO0/Ydgbio3jvnwZlX15+Kq0/Awg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@editorjs/code": "2.7.0",
|
"@editorjs/code": "2.7.0",
|
||||||
"@editorjs/editorjs": "2.25.0",
|
"@editorjs/editorjs": "2.25.0",
|
||||||
@ -56,20 +56,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@alfresco/adf-extensions": {
|
"@alfresco/adf-extensions": {
|
||||||
"version": "6.0.0-A.1-37352",
|
"version": "6.0.0-A.1-37376",
|
||||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-6.0.0-A.1-37352.tgz",
|
"resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-6.0.0-A.1-37376.tgz",
|
||||||
"integrity": "sha512-OcalA6Jl9tr1ynFj9SPbH+i+h4faMpqdFzDza6ZjT2Hquq2Thk5ylzMz+LIHW1FB2wsfKssy9a/409sRHyy1Uw==",
|
"integrity": "sha512-amPdYFRlctYGfKIf1IKt9+SSsVcXOhvOxMsccbN9jI6ShlXBvhBTK+jtItqoJp3GDfWWGU/7RJ0anbZbbQQxTw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@alfresco/adf-testing": {
|
"@alfresco/adf-testing": {
|
||||||
"version": "6.0.0-A.1-37352",
|
"version": "6.0.0-A.1-37376",
|
||||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-testing/-/adf-testing-6.0.0-A.1-37352.tgz",
|
"resolved": "https://registry.npmjs.org/@alfresco/adf-testing/-/adf-testing-6.0.0-A.1-37376.tgz",
|
||||||
"integrity": "sha512-0T18iLgKq76YzCK+iJwpRie8xrJXmGBM/YZ/OqMwAmyHPt5nUY7Uzy+stBlh/TDC9bULCejf3aZByMP82lT7hg==",
|
"integrity": "sha512-WXbpfnKgRHCk7yb/OiWOkJuCvldxRa4vBlP4sRQ4ggoywS85V1yRtJqespoDV/MmYZQ0/ZNXZtVFW8GHzQPOcQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@alfresco/js-api": "5.3.0-466",
|
"@alfresco/js-api": "5.3.0-475",
|
||||||
"@angular/compiler": "14.1.3",
|
"@angular/compiler": "14.1.3",
|
||||||
"@angular/core": "14.1.3",
|
"@angular/core": "14.1.3",
|
||||||
"rxjs": "6.6.6",
|
"rxjs": "6.6.6",
|
||||||
@ -78,9 +78,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alfresco/js-api": {
|
"@alfresco/js-api": {
|
||||||
"version": "5.3.0-466",
|
"version": "5.3.0-475",
|
||||||
"resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-5.3.0-466.tgz",
|
"resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-5.3.0-475.tgz",
|
||||||
"integrity": "sha512-ArBqTqEDbzR/jD6YtJTrPQG3Wz69WXURjnzZE8Os+JWUacJS1n/xEqncJY+xDoILuT1EtaEjogOWNYZixUqXlg==",
|
"integrity": "sha512-oNx3f6c7UlEhAry4pOSoXfZV5E53EM10dBXO2O2PrNS1hNJyT/XiWzeFT3szF8pMQWKyHc3fR5JRVThnTnR++A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"event-emitter": "^0.3.5",
|
"event-emitter": "^0.3.5",
|
||||||
@ -7548,14 +7548,6 @@
|
|||||||
"color-convert": "^2.0.1"
|
"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": {
|
"chalk": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||||
@ -11343,16 +11335,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimatch": "^5.0.1"
|
"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": {
|
"image-size": {
|
||||||
@ -13770,14 +13752,6 @@
|
|||||||
"picomatch": "^2.0.4"
|
"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": {
|
"cacache": {
|
||||||
"version": "16.1.3",
|
"version": "16.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz",
|
||||||
@ -14277,14 +14251,6 @@
|
|||||||
"humanize-ms": "^1.2.1"
|
"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": {
|
"cacache": {
|
||||||
"version": "16.1.2",
|
"version": "16.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.2.tgz",
|
||||||
@ -14642,14 +14608,6 @@
|
|||||||
"npm-normalize-package-bin": "^1.0.1"
|
"npm-normalize-package-bin": "^1.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"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": {
|
"glob": {
|
||||||
"version": "8.0.3",
|
"version": "8.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz",
|
||||||
@ -15162,14 +15120,6 @@
|
|||||||
"humanize-ms": "^1.2.1"
|
"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": {
|
"builtins": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
|
||||||
|
10
package.json
10
package.json
@ -26,9 +26,9 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alfresco/adf-content-services": "6.0.0-A.1-37352",
|
"@alfresco/adf-content-services": "6.0.0-A.1-37376",
|
||||||
"@alfresco/adf-core": "6.0.0-A.1-37352",
|
"@alfresco/adf-core": "6.0.0-A.1-37376",
|
||||||
"@alfresco/adf-extensions": "6.0.0-A.1-37352",
|
"@alfresco/adf-extensions": "6.0.0-A.1-37376",
|
||||||
"@alfresco/js-api": "5.2.0",
|
"@alfresco/js-api": "5.2.0",
|
||||||
"@angular/animations": "14.1.2",
|
"@angular/animations": "14.1.2",
|
||||||
"@angular/cdk": "14.1.2",
|
"@angular/cdk": "14.1.2",
|
||||||
@ -58,8 +58,8 @@
|
|||||||
"zone.js": "0.11.8"
|
"zone.js": "0.11.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@alfresco/adf-cli": "6.0.0-A.1-37352",
|
"@alfresco/adf-cli": "6.0.0-A.1-37376",
|
||||||
"@alfresco/adf-testing": "6.0.0-A.1-37352",
|
"@alfresco/adf-testing": "6.0.0-A.1-37376",
|
||||||
"@angular-custom-builders/lite-serve": "^0.2.3",
|
"@angular-custom-builders/lite-serve": "^0.2.3",
|
||||||
"@angular-devkit/build-angular": "14.1.2",
|
"@angular-devkit/build-angular": "14.1.2",
|
||||||
"@angular-eslint/builder": "^14.1.2",
|
"@angular-eslint/builder": "^14.1.2",
|
||||||
|
@ -53,7 +53,9 @@ export class ToolbarButtonComponent {
|
|||||||
|
|
||||||
runAction() {
|
runAction() {
|
||||||
if (this.hasClickAction(this.actionRef)) {
|
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 {
|
export class ToolbarMenuItemComponent {
|
||||||
@Input()
|
@Input()
|
||||||
actionRef: ContentActionRef;
|
actionRef: ContentActionRef;
|
||||||
|
@Input()
|
||||||
|
menuId?: string;
|
||||||
|
|
||||||
@ViewChild(MatMenuItem)
|
@ViewChild(MatMenuItem)
|
||||||
menuItem: MatMenuItem;
|
menuItem: MatMenuItem;
|
||||||
@ -52,7 +54,14 @@ export class ToolbarMenuItemComponent {
|
|||||||
|
|
||||||
runAction() {
|
runAction() {
|
||||||
if (this.hasClickAction(this.actionRef)) {
|
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>
|
<adf-dynamic-component [id]="child.component" [data]="child.data"></adf-dynamic-component>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngSwitchDefault>
|
<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>
|
</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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
runActionById(id: string) {
|
runActionById(id: string, additionalPayload?: { [key: string]: any }) {
|
||||||
const action = this.extensions.getActionById(id);
|
const action = this.extensions.getActionById(id);
|
||||||
if (action) {
|
if (action) {
|
||||||
const { type, payload } = action;
|
const { type, payload } = action;
|
||||||
@ -507,9 +507,21 @@ export class AppExtensionService implements RuleContext {
|
|||||||
};
|
};
|
||||||
const expression = this.extensions.runExpression(payload, context);
|
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 {
|
} 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/types';
|
||||||
export * from './lib/models/viewer.rules';
|
export * from './lib/models/viewer.rules';
|
||||||
|
export * from './lib/models/modal-configuration';
|
||||||
|
|
||||||
export * from './lib/routing/shared.guard';
|
export * from './lib/routing/shared.guard';
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
import { Action } from '@ngrx/store';
|
import { Action } from '@ngrx/store';
|
||||||
import { SiteBody } from '@alfresco/js-api';
|
import { SiteBody } from '@alfresco/js-api';
|
||||||
|
import { ModalConfiguration } from '@alfresco/aca-shared';
|
||||||
|
|
||||||
export enum LibraryActionTypes {
|
export enum LibraryActionTypes {
|
||||||
Delete = 'DELETE_LIBRARY',
|
Delete = 'DELETE_LIBRARY',
|
||||||
@ -59,5 +60,5 @@ export class UpdateLibraryAction implements Action {
|
|||||||
export class LeaveLibraryAction implements Action {
|
export class LeaveLibraryAction implements Action {
|
||||||
readonly type = LibraryActionTypes.Leave;
|
readonly type = LibraryActionTypes.Leave;
|
||||||
|
|
||||||
constructor(public payload?: string) {}
|
constructor(public payload?: string | ModalConfiguration) {}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
import { Action } from '@ngrx/store';
|
import { Action } from '@ngrx/store';
|
||||||
import { MinimalNodeEntity } from '@alfresco/js-api';
|
import { MinimalNodeEntity } from '@alfresco/js-api';
|
||||||
|
import { ModalConfiguration } from '@alfresco/aca-shared';
|
||||||
|
|
||||||
export enum NodeActionTypes {
|
export enum NodeActionTypes {
|
||||||
SetSelection = 'SET_SELECTED_NODES',
|
SetSelection = 'SET_SELECTED_NODES',
|
||||||
@ -84,7 +85,7 @@ export class PurgeDeletedNodesAction implements Action {
|
|||||||
export class DownloadNodesAction implements Action {
|
export class DownloadNodesAction implements Action {
|
||||||
readonly type = NodeActionTypes.Download;
|
readonly type = NodeActionTypes.Download;
|
||||||
|
|
||||||
constructor(public payload: MinimalNodeEntity[] = []) {}
|
constructor(public payload: MinimalNodeEntity[] | ModalConfiguration = []) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CreateFolderAction implements Action {
|
export class CreateFolderAction implements Action {
|
||||||
@ -96,13 +97,13 @@ export class CreateFolderAction implements Action {
|
|||||||
export class EditFolderAction implements Action {
|
export class EditFolderAction implements Action {
|
||||||
readonly type = NodeActionTypes.EditFolder;
|
readonly type = NodeActionTypes.EditFolder;
|
||||||
|
|
||||||
constructor(public payload: MinimalNodeEntity) {}
|
constructor(public payload: MinimalNodeEntity & ModalConfiguration) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ShareNodeAction implements Action {
|
export class ShareNodeAction implements Action {
|
||||||
readonly type = NodeActionTypes.Share;
|
readonly type = NodeActionTypes.Share;
|
||||||
|
|
||||||
constructor(public payload: MinimalNodeEntity) {}
|
constructor(public payload: MinimalNodeEntity & ModalConfiguration) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UnshareNodesAction implements Action {
|
export class UnshareNodesAction implements Action {
|
||||||
@ -114,13 +115,13 @@ export class UnshareNodesAction implements Action {
|
|||||||
export class CopyNodesAction implements Action {
|
export class CopyNodesAction implements Action {
|
||||||
readonly type = NodeActionTypes.Copy;
|
readonly type = NodeActionTypes.Copy;
|
||||||
|
|
||||||
constructor(public payload: Array<MinimalNodeEntity>) {}
|
constructor(public payload: Array<MinimalNodeEntity> | ModalConfiguration) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MoveNodesAction implements Action {
|
export class MoveNodesAction implements Action {
|
||||||
readonly type = NodeActionTypes.Move;
|
readonly type = NodeActionTypes.Move;
|
||||||
|
|
||||||
constructor(public payload: Array<MinimalNodeEntity>) {}
|
constructor(public payload: Array<MinimalNodeEntity> | ModalConfiguration) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ManagePermissionsAction implements Action {
|
export class ManagePermissionsAction implements Action {
|
||||||
@ -143,7 +144,7 @@ export class PrintFileAction implements Action {
|
|||||||
export class ManageVersionsAction implements Action {
|
export class ManageVersionsAction implements Action {
|
||||||
readonly type = NodeActionTypes.ManageVersions;
|
readonly type = NodeActionTypes.ManageVersions;
|
||||||
|
|
||||||
constructor(public payload: MinimalNodeEntity) {}
|
constructor(public payload: MinimalNodeEntity & ModalConfiguration) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class EditOfflineAction implements Action {
|
export class EditOfflineAction implements Action {
|
||||||
@ -172,7 +173,7 @@ export class RemoveFavoriteAction implements Action {
|
|||||||
export class ManageAspectsAction implements Action {
|
export class ManageAspectsAction implements Action {
|
||||||
readonly type = NodeActionTypes.ChangeAspects;
|
readonly type = NodeActionTypes.ChangeAspects;
|
||||||
|
|
||||||
constructor(public payload: MinimalNodeEntity) {}
|
constructor(public payload: MinimalNodeEntity & ModalConfiguration) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ManageRulesAction implements Action {
|
export class ManageRulesAction implements Action {
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Action } from '@ngrx/store';
|
import { Action } from '@ngrx/store';
|
||||||
|
import { ModalConfiguration } from '@alfresco/aca-shared';
|
||||||
|
|
||||||
export enum UploadActionTypes {
|
export enum UploadActionTypes {
|
||||||
UploadFiles = 'UPLOAD_FILES',
|
UploadFiles = 'UPLOAD_FILES',
|
||||||
@ -46,5 +47,5 @@ export class UploadFolderAction implements Action {
|
|||||||
export class UploadFileVersionAction implements Action {
|
export class UploadFileVersionAction implements Action {
|
||||||
readonly type = UploadActionTypes.UploadFileVersion;
|
readonly type = UploadActionTypes.UploadFileVersion;
|
||||||
|
|
||||||
constructor(public payload: CustomEvent) {}
|
constructor(public payload: CustomEvent | ModalConfiguration) {}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user