-
Notifications
You must be signed in to change notification settings - Fork 148
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* ACS-8706 split context menu to allow injecting actions * ACS-8706 fix class naming, add context menu components unit tests * ACS-8706 add context menu service, effects and directive unit tests * ACS-8706 review remarks - redundant condition, directive unit tests * ACS-8706 improve unit testing approach, remove unnecessary class attributes * ACS-8706 documentation * ACS-8706 fix sonar issues * ACS-8706 replace takeUntil with takeUntilDestroyed * ACS-8706 fix sonar lint issue * ACS-8706 change incorrect import path
- Loading branch information
1 parent
38e667b
commit 71764b0
Showing
18 changed files
with
642 additions
and
95 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
--- | ||
Title: Context Menu Actions | ||
--- | ||
|
||
# Context Menu Actions | ||
|
||
Context Menu Component, appearing on right-clicking a document list item, contains Actions executable on particular file or folder. This entry describes two ways of populating Context Menu. | ||
|
||
**Important:** Those two ways are ***mutually exclusive***. | ||
|
||
## Default behavior | ||
|
||
When using `acaContextActions` directive as shown below, Context Menu actions are loaded from `app.extensions.json` by default. | ||
|
||
```html | ||
<adf-document-list | ||
#documentList | ||
acaContextActions> | ||
</adf-document-list> | ||
``` | ||
|
||
*Note:* To learn more, see [Extensibility features](../extending/extensibility-features.md) and [Extension format](../extending/extension-format.md). | ||
|
||
## Injecting Context Menu Actions | ||
|
||
In order to inject custom actions into Context Menu, assign an array of rules, formatted as described in [Extension format](../extending/extension-format.md), to an attribute of a Component using [Document List Component](https://github.com/Alfresco/alfresco-ng2-components/blob/develop/docs/content-services/components/document-list.component.md). | ||
|
||
```ts | ||
const contextMenuAction = [ | ||
{ | ||
"id": "custom.action.id", | ||
"title": "CUSTOM_ACTION", | ||
"order": 1, | ||
"icon": "adf:custom-icon", | ||
"actions": { | ||
"click": "CUSTOM_ACTION" | ||
}, | ||
"rules": { | ||
"visible": "show.custom.action" | ||
} | ||
}, | ||
{ | ||
"id": "another.custom.action.id" | ||
|
||
... | ||
} | ||
] | ||
|
||
... | ||
|
||
@Component({...}) | ||
export class ComponentWithDocumentList { | ||
customContextMenuActions = contextMenuActions; | ||
|
||
... | ||
} | ||
``` | ||
|
||
Next, pass them to `customActions` input of `acaContextActions` directive inside component's template. | ||
|
||
```html | ||
<adf-document-list | ||
#documentList | ||
acaContextActions | ||
customActions="customContextMenuActions"> | ||
</adf-document-list> | ||
``` | ||
|
||
*Note:* Refer to [Application Actions](../extending/application-actions.md) and [Rules](../extending/rules.md) for information on creating custom *"actions"* and *"rules"* for Context Menu actions. |
108 changes: 108 additions & 0 deletions
108
projects/aca-content/src/lib/components/context-menu/base-context-menu.directive.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
/*! | ||
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. | ||
* | ||
* Alfresco Example Content Application | ||
* | ||
* 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 | ||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
import { ContextMenuOverlayRef } from './context-menu-overlay'; | ||
import { ContentActionType } from '@alfresco/adf-extensions'; | ||
import { AppExtensionService } from '@alfresco/aca-shared'; | ||
import { BaseContextMenuDirective } from './base-context-menu.directive'; | ||
import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||
import { Component } from '@angular/core'; | ||
import { AppTestingModule } from '../../testing/app-testing.module'; | ||
import { OutsideEventDirective } from './context-menu-outside-event.directive'; | ||
import { By } from '@angular/platform-browser'; | ||
|
||
@Component({ | ||
selector: 'app-test-component', | ||
template: '<div acaContextMenuOutsideEvent (clickOutside)="onClickOutsideEvent()"></div>', | ||
standalone: true, | ||
imports: [OutsideEventDirective] | ||
}) | ||
class TestComponent extends BaseContextMenuDirective {} | ||
|
||
describe('BaseContextMenuComponent', () => { | ||
let contextMenuOverlayRef: ContextMenuOverlayRef; | ||
let extensionsService: AppExtensionService; | ||
let fixture: ComponentFixture<TestComponent>; | ||
let component: TestComponent; | ||
|
||
const contextItem = { | ||
type: ContentActionType.button, | ||
id: 'action-button', | ||
title: 'Test Button', | ||
actions: { | ||
click: 'TEST_EVENT' | ||
} | ||
}; | ||
|
||
beforeEach(() => { | ||
TestBed.configureTestingModule({ | ||
imports: [AppTestingModule, TestComponent], | ||
providers: [ | ||
{ | ||
provide: ContextMenuOverlayRef, | ||
useValue: { | ||
close: jasmine.createSpy('close') | ||
} | ||
}, | ||
BaseContextMenuDirective, | ||
OutsideEventDirective | ||
] | ||
}); | ||
|
||
fixture = TestBed.createComponent(TestComponent); | ||
component = fixture.componentInstance; | ||
contextMenuOverlayRef = TestBed.inject(ContextMenuOverlayRef); | ||
extensionsService = TestBed.inject(AppExtensionService); | ||
|
||
fixture.detectChanges(); | ||
}); | ||
|
||
it('should close context menu on Escape event', () => { | ||
fixture.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' })); | ||
|
||
expect(contextMenuOverlayRef.close).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should close context menu on click outside event', () => { | ||
fixture.debugElement.query(By.directive(OutsideEventDirective)).injector.get(OutsideEventDirective).clickOutside.emit(); | ||
fixture.detectChanges(); | ||
|
||
expect(contextMenuOverlayRef.close).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should run action with provided action id and correct payload', () => { | ||
spyOn(extensionsService, 'runActionById'); | ||
|
||
component.runAction(contextItem); | ||
|
||
expect(extensionsService.runActionById).toHaveBeenCalledWith(contextItem.actions.click, { | ||
focusedElementOnCloseSelector: '.adf-context-menu-source' | ||
}); | ||
}); | ||
|
||
it('should return action id on trackByActionId', () => { | ||
const actionId = component.trackByActionId(0, contextItem); | ||
expect(actionId).toBe(contextItem.id); | ||
}); | ||
}); |
68 changes: 68 additions & 0 deletions
68
projects/aca-content/src/lib/components/context-menu/base-context-menu.directive.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/*! | ||
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. | ||
* | ||
* Alfresco Example Content Application | ||
* | ||
* 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 | ||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
import { HostListener, ViewChild, Inject, Directive } from '@angular/core'; | ||
import { MatMenuTrigger } from '@angular/material/menu'; | ||
import { ContentActionRef } from '@alfresco/adf-extensions'; | ||
import { ContextMenuOverlayRef } from './context-menu-overlay'; | ||
import { CONTEXT_MENU_DIRECTION } from './direction.token'; | ||
import { Direction } from '@angular/cdk/bidi'; | ||
import { AppExtensionService } from '@alfresco/aca-shared'; | ||
|
||
@Directive() | ||
export class BaseContextMenuDirective { | ||
actions: Array<ContentActionRef> = []; | ||
|
||
@ViewChild(MatMenuTrigger) | ||
trigger: MatMenuTrigger; | ||
|
||
@HostListener('keydown.escape', ['$event']) | ||
handleKeydownEscape(event: KeyboardEvent) { | ||
if (event && this.contextMenuOverlayRef) { | ||
this.contextMenuOverlayRef.close(); | ||
} | ||
} | ||
|
||
constructor( | ||
private readonly contextMenuOverlayRef: ContextMenuOverlayRef, | ||
protected extensions: AppExtensionService, | ||
@Inject(CONTEXT_MENU_DIRECTION) public direction: Direction | ||
) {} | ||
|
||
onClickOutsideEvent() { | ||
if (this.contextMenuOverlayRef) { | ||
this.contextMenuOverlayRef.close(); | ||
} | ||
} | ||
|
||
runAction(contentActionRef: ContentActionRef) { | ||
this.extensions.runActionById(contentActionRef.actions.click, { | ||
focusedElementOnCloseSelector: '.adf-context-menu-source' | ||
}); | ||
} | ||
|
||
trackByActionId(_: number, obj: ContentActionRef): string { | ||
return obj.id; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.