mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-06-30 18:15:11 +00:00
[ACS-4592] missing right click menu on row and left click is only allow on indicator rotate (#8327)
* ACS-4592 Displaying context menu for tree list row and allow to expand row by clicking at label * ACS-4592 Added clicking on label for load more button * ACS-4592 Unit tests * ACS-4592 Added documentation for context menu for tree component and fixed lint issues * ACS-4592 Trigger stuck check
This commit is contained in:
parent
41f9974919
commit
9863149a28
@ -28,7 +28,7 @@ Shows the nodes in tree structure, each node containing children is collapsible/
|
||||
### Properties
|
||||
|
||||
| Name | Type | Default value | Description |
|
||||
| ---- | ---- | ------------- | ----------- |
|
||||
| ---- |---------------| --------- | ----------- |
|
||||
| emptyContentTemplate | `TemplateRef` | | Template that will be rendered when no nodes are loaded. |
|
||||
| nodeActionsMenuTemplate | `TemplateRef` | | Template that will be rendered when context menu for given node is opened. |
|
||||
| stickyHeader | `boolean` | false | If set to true header will be sticky. |
|
||||
@ -37,13 +37,15 @@ Shows the nodes in tree structure, each node containing children is collapsible/
|
||||
| loadMoreSuffix | `string` | | Suffix added to `Load more` string inside load more node. |
|
||||
| expandIcon | `string` | `chevron_right` | Icon shown when node is collapsed. |
|
||||
| collapseIcon | `string` | `expand_more` | Icon showed when node is expanded. |
|
||||
| contextMenuOptions | `any[]` | | Array of context menu options which should be displayed for each row. |
|
||||
|
||||
|
||||
### Events
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| ---- |----------------------------------------------------------------------------------------|------------------------------------------------------------------|
|
||||
| paginationChanged | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<PaginationModel>` | Emitted when during loading additional nodes pagination changes. |
|
||||
| contextMenuOptionSelected | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<TreeContextMenuResult<T>>` | Emitted when any context menu option is selected. |
|
||||
|
||||
## Details
|
||||
|
||||
|
@ -33,7 +33,9 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="adf-tree-cell">
|
||||
<span class="adf-tree-cell-value">
|
||||
<span
|
||||
class="adf-tree-cell-value"
|
||||
(click)="loadMoreSubnodes(node)">
|
||||
{{ 'ADF-TREE.LOAD-MORE-BUTTON' | translate: { name: loadMoreSuffix } }}
|
||||
</span>
|
||||
</div>
|
||||
@ -42,7 +44,10 @@
|
||||
class="adf-tree-row"
|
||||
[attr.data-automation-id]="'node_' + node.id"
|
||||
*matTreeNodeDef="let node"
|
||||
matTreeNodePadding>
|
||||
matTreeNodePadding
|
||||
[adf-context-menu]="contextMenuOptions"
|
||||
[adf-context-menu-enabled]="!!contextMenuOptions"
|
||||
(contextmenu)="contextMenuSource = node">
|
||||
<div class="adf-tree-expand-collapse-container">
|
||||
<button *ngIf="node.hasChildren"
|
||||
class="adf-tree-expand-collapse-button"
|
||||
@ -80,7 +85,10 @@
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
<div class="adf-tree-cell">
|
||||
<span class="adf-tree-cell-value">
|
||||
<span
|
||||
class="adf-tree-cell-value"
|
||||
[class.adf-tree-clickable-cell-value]="node.hasChildren"
|
||||
(click)="expandCollapseNode(node)">
|
||||
{{ node.nodeName }}
|
||||
</span>
|
||||
</div>
|
||||
|
@ -11,6 +11,11 @@ $tree-header-font-size: 12px !default;
|
||||
}
|
||||
}
|
||||
|
||||
.adf-tree-load-more-row .adf-tree-cell-value,
|
||||
.adf-tree-clickable-cell-value {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.adf-tree-row,
|
||||
.adf-tree-load-more-row {
|
||||
transition: all 0.3s ease;
|
||||
@ -21,7 +26,6 @@ $tree-header-font-size: 12px !default;
|
||||
transition-property: background-color;
|
||||
border-bottom: 1px solid var(--theme-border-color);
|
||||
min-height: $tree-row-height;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
.adf-tree-expand-collapse-container {
|
||||
@ -55,7 +59,7 @@ $tree-header-font-size: 12px !default;
|
||||
width: 100%;
|
||||
|
||||
.adf-tree-cell-value {
|
||||
display: block;
|
||||
display: inline-block;
|
||||
padding: 10px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
@ -17,32 +17,41 @@
|
||||
|
||||
import { TreeComponent } from './tree.component';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CoreTestingModule, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { ContextMenuDirective, CoreTestingModule, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { MatTreeModule } from '@angular/material/tree';
|
||||
import { TreeNode, TreeNodeType } from '../models/tree-node.interface';
|
||||
import { singleNode, treeNodesChildrenMockExpanded, treeNodesMock, treeNodesMockExpanded } from '../mock/tree-node.mock';
|
||||
import { of } from 'rxjs';
|
||||
import {
|
||||
singleNode,
|
||||
treeNodesChildrenMockExpanded,
|
||||
treeNodesMock,
|
||||
treeNodesMockExpanded,
|
||||
treeNodesNoChildrenMock
|
||||
} from '../mock/tree-node.mock';
|
||||
import { of, Subject } from 'rxjs';
|
||||
import { TreeService } from '../services/tree.service';
|
||||
import { TreeServiceMock } from '../mock/tree-service.service.mock';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { SelectionChange } from '@angular/cdk/collections';
|
||||
import { DebugElement } from '@angular/core';
|
||||
|
||||
describe('TreeComponent', () => {
|
||||
let fixture: ComponentFixture<TreeComponent<TreeNode>>;
|
||||
let component: TreeComponent<TreeNode>;
|
||||
let userPreferenceService: UserPreferencesService;
|
||||
|
||||
const getDisplayNameValue = (nodeId: string) =>
|
||||
fixture.nativeElement.querySelector(`.mat-tree-node[data-automation-id="node_${nodeId}"] .adf-tree-cell-value`).innerText.trim();
|
||||
const composeNodeSelector = (nodeId: string) => `.mat-tree-node[data-automation-id="node_${nodeId}"]`;
|
||||
|
||||
const getNodePadding = (nodeId: string) => {
|
||||
const element = fixture.nativeElement.querySelector(`.mat-tree-node[data-automation-id="node_${nodeId}"]`);
|
||||
return parseInt(window.getComputedStyle(element).paddingLeft, 10);
|
||||
};
|
||||
const getNode = (nodeId: string) => fixture.debugElement.query(By.css(composeNodeSelector(nodeId)));
|
||||
|
||||
const getNodeSpinner = (nodeId: string) => fixture.nativeElement.querySelector(`.mat-tree-node[data-automation-id="node_${nodeId}"] .mat-progress-spinner`);
|
||||
const getDisplayNameElement = (nodeId: string) => fixture.nativeElement.querySelector(`${composeNodeSelector(nodeId)} .adf-tree-cell-value`);
|
||||
|
||||
const getExpandCollapseBtn = (nodeId: string) => fixture.nativeElement.querySelector(`.mat-tree-node[data-automation-id="node_${nodeId}"] .adf-icon`);
|
||||
const getDisplayNameValue = (nodeId: string) => getDisplayNameElement(nodeId).innerText.trim();
|
||||
|
||||
const getNodePadding = (nodeId: string) => parseInt(getComputedStyle(getNode(nodeId).nativeElement).paddingLeft, 10);
|
||||
|
||||
const getNodeSpinner = (nodeId: string) => fixture.nativeElement.querySelector(`${composeNodeSelector(nodeId)} .mat-progress-spinner`);
|
||||
|
||||
const getExpandCollapseBtn = (nodeId: string) => fixture.nativeElement.querySelector(`${composeNodeSelector(nodeId)} .adf-icon`);
|
||||
|
||||
const tickCheckbox = (index: number) => {
|
||||
const nodeCheckboxes = fixture.debugElement.queryAll(By.css('mat-checkbox'));
|
||||
@ -179,6 +188,56 @@ describe('TreeComponent', () => {
|
||||
expect(collapseSpy).toHaveBeenCalledWith(component.treeService.treeNodes[0], treeNodesMockExpanded);
|
||||
});
|
||||
|
||||
it('should call collapseNode on TreeService when collapsing node by clicking at node label and node has children', () => {
|
||||
component.refreshTree();
|
||||
fixture.detectChanges();
|
||||
spyOn(component.treeService, 'collapseNode');
|
||||
spyOn(component.treeService.treeControl, 'isExpanded').and.returnValue(true);
|
||||
getDisplayNameElement(component.treeService.treeNodes[0].id).dispatchEvent(new Event('click'));
|
||||
expect(component.treeService.collapseNode).toHaveBeenCalledWith(component.treeService.treeNodes[0]);
|
||||
});
|
||||
|
||||
it('should call expandNode on TreeService when expanding node by clicking at node label and node has children', () => {
|
||||
component.refreshTree();
|
||||
fixture.detectChanges();
|
||||
spyOn(component.treeService, 'expandNode');
|
||||
spyOn(component.treeService.treeControl, 'isExpanded').and.returnValue(false);
|
||||
getDisplayNameElement(component.treeService.treeNodes[0].id).dispatchEvent(new Event('click'));
|
||||
expect(component.treeService.expandNode).toHaveBeenCalledWith(component.treeService.treeNodes[0], treeNodesMockExpanded);
|
||||
});
|
||||
|
||||
it('should not call collapseNode on TreeService when collapsing node and node has not children', () => {
|
||||
spyOn(component.treeService, 'getSubNodes').and.returnValue(of({
|
||||
pagination: {
|
||||
skipCount: 0,
|
||||
maxItems: 25
|
||||
},
|
||||
entries: Array.from(treeNodesNoChildrenMock)
|
||||
}));
|
||||
component.refreshTree();
|
||||
fixture.detectChanges();
|
||||
spyOn(component.treeService, 'collapseNode');
|
||||
spyOn(component.treeService.treeControl, 'isExpanded').and.returnValue(true);
|
||||
getDisplayNameElement(component.treeService.treeNodes[0].id).dispatchEvent(new Event('click'));
|
||||
expect(component.treeService.collapseNode).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not call expandNode on TreeService when expanding node by clicking at node label and node has not children', () => {
|
||||
spyOn(component.treeService, 'getSubNodes').and.returnValue(of({
|
||||
pagination: {
|
||||
skipCount: 0,
|
||||
maxItems: 25
|
||||
},
|
||||
entries: Array.from(treeNodesNoChildrenMock)
|
||||
}));
|
||||
component.refreshTree();
|
||||
fixture.detectChanges();
|
||||
spyOn(component.treeService, 'expandNode');
|
||||
spyOn(component.treeService.treeControl, 'isExpanded').and.returnValue(false);
|
||||
getDisplayNameElement(component.treeService.treeNodes[0].id).dispatchEvent(new Event('click'));
|
||||
expect(component.treeService.expandNode).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should load more subnodes and remove load more button when load more button is clicked', () => {
|
||||
component.refreshTree();
|
||||
fixture.detectChanges();
|
||||
@ -193,6 +252,22 @@ describe('TreeComponent', () => {
|
||||
expect(loadMoreNodes).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should load more subnodes and remove load more button when label of load more button is clicked', () => {
|
||||
component.refreshTree();
|
||||
fixture.detectChanges();
|
||||
spyOn(component.treeService, 'getSubNodes').and.returnValue(of({
|
||||
pagination: {},
|
||||
entries: Array.from(singleNode)
|
||||
}));
|
||||
spyOn(component.treeService, 'appendNodes');
|
||||
fixture.debugElement.query(By.css('.adf-tree-load-more-row .adf-tree-cell-value')).nativeElement.click();
|
||||
fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
expect(component.treeService.appendNodes).toHaveBeenCalledWith(component.treeService.treeNodes[0], Array.from(singleNode));
|
||||
expect(component.treeService.treeNodes.find((node) => node.nodeType === TreeNodeType.LoadMoreNode))
|
||||
.toBeUndefined();
|
||||
});
|
||||
|
||||
it('selection should be disabled by default, no checkboxes should be displayed', () => {
|
||||
component.refreshTree();
|
||||
fixture.detectChanges();
|
||||
@ -257,4 +332,96 @@ describe('TreeComponent', () => {
|
||||
fixture.detectChanges();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Context menu', () => {
|
||||
let contextMenu: ContextMenuDirective;
|
||||
let contextMenuOption1: any;
|
||||
let contextMenuOption2: any;
|
||||
let node: DebugElement;
|
||||
|
||||
const optionTitle1 = 'option 1';
|
||||
const optionTitle2 = 'option 2';
|
||||
|
||||
beforeEach(() => {
|
||||
fixture.detectChanges();
|
||||
node = getNode('testId1');
|
||||
contextMenu = node.injector.get(ContextMenuDirective);
|
||||
contextMenuOption1 = {
|
||||
title: optionTitle1,
|
||||
subject: new Subject()
|
||||
};
|
||||
contextMenuOption2 = {
|
||||
title: optionTitle2,
|
||||
subject: new Subject()
|
||||
};
|
||||
});
|
||||
|
||||
it('should have assigned correct value to links property of context menu for row', () => {
|
||||
component.contextMenuOptions = [contextMenuOption1, contextMenuOption2];
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(contextMenu.links).toEqual(component.contextMenuOptions);
|
||||
});
|
||||
|
||||
it('should have assigned default subject to each context menu option', () => {
|
||||
contextMenuOption1.subject = undefined;
|
||||
contextMenuOption2.subject = undefined;
|
||||
component.contextMenuOptions = [contextMenuOption1, contextMenuOption2];
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(contextMenu.links).toEqual([{
|
||||
title: optionTitle1,
|
||||
subject: jasmine.any(Subject)
|
||||
}, {
|
||||
title: optionTitle2,
|
||||
subject: jasmine.any(Subject)
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should have assigned false to enabled property of context menu for row by default', () => {
|
||||
expect(contextMenu.enabled).toBeFalse();
|
||||
});
|
||||
|
||||
it('should have assigned true to enabled property of context menu for row if contextMenuOptions is set', () => {
|
||||
component.contextMenuOptions = [contextMenuOption1, contextMenuOption2];
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(contextMenu.enabled).toBeTrue();
|
||||
});
|
||||
|
||||
it('should have assigned false to enabled property of context menu for row if contextMenuOptions is not set', () => {
|
||||
component.contextMenuOptions = [contextMenuOption1, contextMenuOption2];
|
||||
fixture.detectChanges();
|
||||
component.contextMenuOptions = null;
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(contextMenu.enabled).toBeFalse();
|
||||
});
|
||||
|
||||
it('should emit contextMenuOptionSelected with correct parameters when any context menu option has been selected', () => {
|
||||
spyOn(component.contextMenuOptionSelected, 'emit');
|
||||
component.contextMenuOptions = [contextMenuOption1, contextMenuOption2];
|
||||
|
||||
const option = component.contextMenuOptions[0];
|
||||
component.contextMenuOptions[0].subject.next(option);
|
||||
expect(component.contextMenuOptionSelected.emit).toHaveBeenCalledWith({
|
||||
contextMenuOption: option,
|
||||
row: undefined
|
||||
});
|
||||
});
|
||||
|
||||
it('should emit contextMenuOptionSelected including row when any context menu option has been selected and contextmenu event has been triggered earlier', () => {
|
||||
spyOn(component.contextMenuOptionSelected, 'emit');
|
||||
component.contextMenuOptions = [contextMenuOption1, contextMenuOption2];
|
||||
fixture.detectChanges();
|
||||
node.nativeElement.dispatchEvent(new MouseEvent('contextmenu'));
|
||||
|
||||
const option = component.contextMenuOptions[0];
|
||||
component.contextMenuOptions[0].subject.next(option);
|
||||
expect(component.contextMenuOptionSelected.emit).toHaveBeenCalledWith({
|
||||
contextMenuOption: option,
|
||||
row: treeNodesMockExpanded[0]
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -15,14 +15,28 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, HostBinding, Input, OnInit, Output, QueryList, TemplateRef, ViewChildren, ViewEncapsulation } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
HostBinding,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
QueryList,
|
||||
TemplateRef,
|
||||
ViewChildren,
|
||||
ViewEncapsulation
|
||||
} from '@angular/core';
|
||||
import { BehaviorSubject, merge, Observable, Subject } from 'rxjs';
|
||||
import { TreeNode, TreeNodeType } from '../models/tree-node.interface';
|
||||
import { TreeService } from '../services/tree.service';
|
||||
import { PaginationModel, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { SelectionChange, SelectionModel } from '@angular/cdk/collections';
|
||||
import { TreeResponse } from '../models/tree-response.interface';
|
||||
import { MatCheckbox } from '@angular/material/checkbox';
|
||||
import { TreeContextMenuResult } from '../models/tree-context-menu-result.interface';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-tree',
|
||||
@ -31,7 +45,7 @@ import { MatCheckbox } from '@angular/material/checkbox';
|
||||
host: { class: 'adf-tree' },
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class TreeComponent<T extends TreeNode> implements OnInit {
|
||||
export class TreeComponent<T extends TreeNode> implements OnInit, OnDestroy {
|
||||
|
||||
/** TemplateRef to provide empty template when no nodes are loaded */
|
||||
@Input()
|
||||
@ -70,16 +84,57 @@ export class TreeComponent<T extends TreeNode> implements OnInit {
|
||||
@Output()
|
||||
public paginationChanged: EventEmitter<PaginationModel> = new EventEmitter();
|
||||
|
||||
/** Emitted when any context menu option is selected */
|
||||
@Output()
|
||||
public contextMenuOptionSelected = new EventEmitter<TreeContextMenuResult<T>>();
|
||||
|
||||
@ViewChildren(MatCheckbox)
|
||||
public nodeCheckboxes: QueryList<MatCheckbox>;
|
||||
|
||||
private loadingRootSource = new BehaviorSubject<boolean>(false);
|
||||
private _contextMenuSource: T;
|
||||
private _contextMenuOptions: any[];
|
||||
private contextMenuOptionsChanged$ = new Subject<void>();
|
||||
public loadingRoot$: Observable<boolean>;
|
||||
public treeNodesSelection = new SelectionModel<T>(true, [], true, (node1: T, node2: T) => node1.id === node2.id);
|
||||
|
||||
constructor(public treeService: TreeService<T>,
|
||||
private userPreferenceService: UserPreferencesService) {}
|
||||
|
||||
set contextMenuSource(contextMenuSource: T) {
|
||||
this._contextMenuSource = contextMenuSource;
|
||||
}
|
||||
|
||||
/** Array of context menu options which should be displayed for each row. */
|
||||
@Input()
|
||||
set contextMenuOptions(contextMenuOptions: any[]) {
|
||||
this.contextMenuOptionsChanged$.next();
|
||||
if (contextMenuOptions) {
|
||||
this._contextMenuOptions = contextMenuOptions.map((option) => {
|
||||
if (!option.subject) {
|
||||
option = {
|
||||
...option,
|
||||
subject: new Subject()
|
||||
};
|
||||
}
|
||||
return option;
|
||||
});
|
||||
merge(...this.contextMenuOptions.map((option) => option.subject)).pipe(takeUntil(this.contextMenuOptionsChanged$))
|
||||
.subscribe((option) => {
|
||||
this.contextMenuOptionSelected.emit({
|
||||
row: this._contextMenuSource,
|
||||
contextMenuOption: option
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this._contextMenuOptions = contextMenuOptions;
|
||||
}
|
||||
}
|
||||
|
||||
get contextMenuOptions(): any[] {
|
||||
return this._contextMenuOptions;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadingRoot$ = this.loadingRootSource.asObservable();
|
||||
this.refreshTree(0, this.userPreferenceService.paginationSize);
|
||||
@ -88,6 +143,11 @@ export class TreeComponent<T extends TreeNode> implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.contextMenuOptionsChanged$.next();
|
||||
this.contextMenuOptionsChanged$.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if node is LoadMoreNode node
|
||||
*
|
||||
@ -141,6 +201,7 @@ export class TreeComponent<T extends TreeNode> implements OnInit {
|
||||
* @param node node to be collapsed/expanded
|
||||
*/
|
||||
public expandCollapseNode(node: T): void {
|
||||
if (node.hasChildren) {
|
||||
if (this.treeService.treeControl.isExpanded(node)) {
|
||||
this.treeService.collapseNode(node);
|
||||
} else {
|
||||
@ -158,6 +219,7 @@ export class TreeComponent<T extends TreeNode> implements OnInit {
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads more subnode for a given parent node
|
||||
|
@ -0,0 +1,21 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2019 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export interface TreeContextMenuResult<T> {
|
||||
row: T;
|
||||
contextMenuOption: any;
|
||||
}
|
@ -18,5 +18,6 @@
|
||||
export * from './tree.module';
|
||||
export * from './models/tree-response.interface';
|
||||
export * from './models/tree-node.interface';
|
||||
export * from './models/tree-context-menu-result.interface';
|
||||
export * from './services/tree.service';
|
||||
export * from './components/tree.component';
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { CoreModule } from '@alfresco/adf-core';
|
||||
import { ContextMenuModule, CoreModule } from '@alfresco/adf-core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
@ -27,7 +27,8 @@ import { TreeComponent } from './components/tree.component';
|
||||
CommonModule,
|
||||
CoreModule,
|
||||
MaterialModule,
|
||||
TranslateModule
|
||||
TranslateModule,
|
||||
ContextMenuModule
|
||||
],
|
||||
declarations: [
|
||||
TreeComponent
|
||||
|
Loading…
x
Reference in New Issue
Block a user