mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-07-24 17:31:52 +00:00
[ACS-8036] [Bulk update] [Many files to 1 Hold flow] "Manage Holds" dialog with Manage Existing Holds/Apply New Hold tabs (#4019)
* [ACS-8325] [Bulk Legal Hold] Create Bulk Actions Dropdown (#3956) * ACS-8036 create bulk-actions-dropdown * ACS-8325 update names and add unit tests * ACS-8325 added icon and unit tests * ACS-8325 fix translation * ACS-8325 add and refactor tests in app extension service * ACS-8325 resolve conversations: remove loadBulkActions, rename bulk schema, add translations * ACS-8325 update state * ACS-8325 temporary remove disabled state as it doesn't work after Angular migration * ACS-8325 add formControl and tests * ACS-8325 clean code * ACS-8325 place create component to one place * ACS-8325 add condition to use title if no description provided and cover with test * ACS-8325 add tooltip and update Badge interface * ACS-8325 rename class names and mockItem object * [ACS-8326] enable running actions from bulk dropdown and resetting selection (#3971) * ACS-8036 create bulk-actions-dropdown * ACS-8325 update names and add unit tests * ACS-8325 fix translation * ACS-8325 resolve conversations: remove loadBulkActions, rename bulk schema, add translations * ACS-8325 temporary remove disabled state as it doesn't work after Angular migration * ACS-8325 add formControl and tests * ACS-8325 add condition to use title if no description provided and cover with test * ACS-8325 add tooltip and update Badge interface * ACS-8326 enable running actions from bulk dropdown and resetting dropdown selection * ACS-8326 review remarks - use select control, fix naming * ACS-8326 fix unit test selectors * ACS-8326 review remarks - change property name to more universal, adjust unit tests --------- Co-authored-by: Darya Balvanovich <darya.balvanovich@hyland.com> * [ACS-8424][Bulk Legal Hold] Add Badge for items (#3985) * [ACS-8424] display badges in search result * [ACS-8424] display badges in search result * ACS-8424 create separate badge component, add/move unit tests, undo highlight change failing tests * ACS-8424 template cleanup * ACS-8424 template cleanup cleanup * ACS-8424 revert single deletion in template * ACS-8424 rename new component, change property order --------- Co-authored-by: g-jaskowski <grzegorz.jaskowski@hyland.com> * ACS-8458 refactor styles (#4018) * [ACS-8489] Legal Holds keyboard accessibility (#4009) * ACS-8489 handle keyboard accessibility * ACS-8489 wording fix * ACS-8489 change function name * ACS-8489 fix typo * ACS-8489 review remarks - simplify keyboard event handling, improve unit tests * ACS-8489 move duplicated code to method * ACS-8489 change type name to more precise * [ACS-8036] fix icon visibility in mat-select * ACS-8036 fix styles and import * ACS-8036 remove async from test * ACS-8036 handle event when dropdown closed * ACS-8036 fix rebase issues * ACS-8036 fix rebase issues * ACS-8036 fix rebase --------- Co-authored-by: Grzegorz Jaśkowski <138671284+g-jaskowski@users.noreply.github.com> Co-authored-by: tamaragruszka <156320606+tamaragruszka@users.noreply.github.com> Co-authored-by: g-jaskowski <grzegorz.jaskowski@hyland.com> Co-authored-by: tamaragruszka <tamara.gruszka@hyland.com>
This commit is contained in:
committed by
GitHub
parent
068f6bb8e9
commit
53e90312b0
@@ -0,0 +1,19 @@
|
||||
<div class="aca-datatable-cell-badges-container">
|
||||
<ng-container *ngFor="let badge of badges">
|
||||
<adf-dynamic-component
|
||||
*ngIf="badge.component; else iconBadge"
|
||||
[id]="badge.component"
|
||||
[data]="{ node }"
|
||||
></adf-dynamic-component>
|
||||
<ng-template #iconBadge>
|
||||
<adf-icon
|
||||
class="adf-datatable-cell-badge"
|
||||
[title]="badge.tooltip | translate"
|
||||
[value]="badge.icon"
|
||||
(click)="onBadgeClick(badge)"
|
||||
(keypress.enter)="onKeyPress(badge)"
|
||||
tabindex="0"
|
||||
></adf-icon>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
@@ -0,0 +1,7 @@
|
||||
.aca-datatable-cell-badges-container {
|
||||
display: flex;
|
||||
|
||||
.adf-datatable-cell-badge {
|
||||
color: var(--theme-secondary-text);
|
||||
}
|
||||
}
|
@@ -0,0 +1,128 @@
|
||||
/*!
|
||||
* 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 { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { DatatableCellBadgesComponent } from './datatable-cell-badges.component';
|
||||
import { AppExtensionService } from '@alfresco/aca-shared';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { AuthModule } from '@alfresco/adf-core';
|
||||
import { Actions } from '@ngrx/effects';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
import { of } from 'rxjs';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { ContentActionType } from '@alfresco/adf-extensions';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
|
||||
const mockNode = {
|
||||
entry: {
|
||||
isFile: true,
|
||||
id: 'nodeId'
|
||||
}
|
||||
} as NodeEntry;
|
||||
|
||||
const mockGetBadgesResponse = {
|
||||
id: 'test',
|
||||
type: ContentActionType.custom,
|
||||
icon: 'warning',
|
||||
tooltip: 'test tooltip'
|
||||
};
|
||||
|
||||
describe('DatatableCellBadgesComponent', () => {
|
||||
let fixture: ComponentFixture<DatatableCellBadgesComponent>;
|
||||
let component: DatatableCellBadgesComponent;
|
||||
let appExtensionService: AppExtensionService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
AuthModule.forRoot(),
|
||||
HttpClientModule,
|
||||
StoreModule.forRoot(
|
||||
{ app: (state) => state },
|
||||
{
|
||||
initialState: {
|
||||
app: {
|
||||
selection: {
|
||||
nodes: [],
|
||||
libraries: [],
|
||||
isEmpty: true,
|
||||
count: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
],
|
||||
providers: [Actions]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(DatatableCellBadgesComponent);
|
||||
component = fixture.componentInstance;
|
||||
appExtensionService = TestBed.inject(AppExtensionService);
|
||||
component.node = mockNode;
|
||||
});
|
||||
|
||||
it('should get badges when component initializes', () => {
|
||||
spyOn(appExtensionService, 'getBadges').and.returnValue(of([mockGetBadgesResponse]));
|
||||
component.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
const badges = fixture.debugElement.queryAll(By.css('.adf-datatable-cell-badge')).map((badge) => badge.nativeElement);
|
||||
expect(appExtensionService.getBadges).toHaveBeenCalled();
|
||||
expect(badges.length).toBe(1);
|
||||
expect(badges[0].innerText).toBe('warning');
|
||||
expect(badges[0].attributes['title'].value).toBe('test tooltip');
|
||||
});
|
||||
|
||||
it('should render dynamic component when badge has one provided', () => {
|
||||
spyOn(appExtensionService, 'getBadges').and.returnValue(of([{ ...mockGetBadgesResponse, component: 'test-id' }]));
|
||||
component.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
const dynamicComponent = fixture.debugElement.query(By.css('adf-dynamic-component')).nativeElement;
|
||||
expect(dynamicComponent).toBeDefined();
|
||||
});
|
||||
|
||||
describe('mouse and keyboard events', () => {
|
||||
let badges: HTMLElement[];
|
||||
let runActionSpy: jasmine.Spy;
|
||||
beforeEach(() => {
|
||||
spyOn(appExtensionService, 'getBadges').and.returnValue(of([{ ...mockGetBadgesResponse, actions: { click: 'test' } }]));
|
||||
component.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
badges = fixture.debugElement.queryAll(By.css('.adf-datatable-cell-badge')).map((badge) => badge.nativeElement);
|
||||
runActionSpy = spyOn(appExtensionService, 'runActionById');
|
||||
});
|
||||
|
||||
it('should call provided handler on click', () => {
|
||||
badges[0].click();
|
||||
expect(runActionSpy).toHaveBeenCalledWith('test', component.node);
|
||||
});
|
||||
|
||||
it('should call provided handler on keypress event', () => {
|
||||
badges[0].dispatchEvent(new KeyboardEvent('keypress.enter'));
|
||||
expect(runActionSpy).toHaveBeenCalledWith('test', component.node);
|
||||
});
|
||||
});
|
||||
});
|
@@ -0,0 +1,76 @@
|
||||
/*!
|
||||
* 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 { AppExtensionService, Badge } from '@alfresco/aca-shared';
|
||||
import { IconComponent } from '@alfresco/adf-core';
|
||||
import { DynamicExtensionComponent } from '@alfresco/adf-extensions';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'aca-datatable-cell-badges',
|
||||
templateUrl: './datatable-cell-badges.component.html',
|
||||
styleUrls: ['./datatable-cell-badges.component.scss'],
|
||||
host: { class: 'aca-datatable-cell-badges' },
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
imports: [CommonModule, TranslateModule, DynamicExtensionComponent, IconComponent],
|
||||
standalone: true
|
||||
})
|
||||
export class DatatableCellBadgesComponent implements OnInit, OnDestroy {
|
||||
@Input() node: NodeEntry;
|
||||
|
||||
badges: Badge[];
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(private appExtensionService: AppExtensionService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.appExtensionService
|
||||
.getBadges(this.node)
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((badges) => {
|
||||
this.badges = badges;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next(true);
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
|
||||
onBadgeClick(badge: Badge) {
|
||||
if (badge.actions?.click) {
|
||||
this.appExtensionService.runActionById(badge.actions?.click, this.node);
|
||||
}
|
||||
}
|
||||
|
||||
onKeyPress(badge: Badge) {
|
||||
this.onBadgeClick(badge);
|
||||
}
|
||||
}
|
@@ -19,12 +19,5 @@
|
||||
<aca-locked-by [node]="context.row.node"></aca-locked-by>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="aca-name-column-badges">
|
||||
<ng-container *ngFor="let badge of badges">
|
||||
<adf-dynamic-component *ngIf="badge.component; else iconBadge" [id]="badge.component" [data]="{ node }"></adf-dynamic-component>
|
||||
<ng-template #iconBadge>
|
||||
<adf-icon class="adf-datatable-cell-badge" [title]="badge.tooltip | translate" [value]="badge.icon" (click)="onBadgeClick(badge)"></adf-icon>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
<aca-datatable-cell-badges [node]="node"></aca-datatable-cell-badges>
|
||||
</div>
|
||||
|
@@ -4,14 +4,6 @@
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
|
||||
.aca-name-column-badges {
|
||||
display: flex;
|
||||
|
||||
.adf-datatable-cell-badge {
|
||||
color: var(--theme-secondary-text);
|
||||
}
|
||||
}
|
||||
|
||||
.aca-name-column-container {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@@ -36,6 +28,6 @@
|
||||
position: unset;
|
||||
}
|
||||
|
||||
.adf-datatable-list .adf-datatable-link:hover .aca-name-column-badges {
|
||||
.adf-datatable-list .adf-datatable-link:hover .aca-datatable-cell-badges {
|
||||
color: var(--adf-theme-foreground-text-color);
|
||||
}
|
||||
|
@@ -28,16 +28,23 @@ import { StoreModule } from '@ngrx/store';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { AppExtensionService } from '@alfresco/aca-shared';
|
||||
import { of } from 'rxjs';
|
||||
import { ContentActionType } from '@alfresco/adf-extensions';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { AuthModule } from '@alfresco/adf-core';
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
|
||||
@Component({
|
||||
selector: 'aca-datatable-cell-badges',
|
||||
standalone: true,
|
||||
template: ''
|
||||
})
|
||||
class MockDatatableCellBadgesComponent {
|
||||
@Input() node: NodeEntry;
|
||||
}
|
||||
|
||||
describe('CustomNameColumnComponent', () => {
|
||||
let fixture: ComponentFixture<CustomNameColumnComponent>;
|
||||
let component: CustomNameColumnComponent;
|
||||
let appExtensionService: AppExtensionService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -45,6 +52,7 @@ describe('CustomNameColumnComponent', () => {
|
||||
HttpClientModule,
|
||||
TranslateModule.forRoot(),
|
||||
CustomNameColumnComponent,
|
||||
MockDatatableCellBadgesComponent,
|
||||
AuthModule.forRoot(),
|
||||
StoreModule.forRoot(
|
||||
{ app: (state) => state },
|
||||
@@ -67,7 +75,6 @@ describe('CustomNameColumnComponent', () => {
|
||||
|
||||
fixture = TestBed.createComponent(CustomNameColumnComponent);
|
||||
component = fixture.componentInstance;
|
||||
appExtensionService = TestBed.inject(AppExtensionService);
|
||||
});
|
||||
|
||||
it('should not render lock element if file is not locked', () => {
|
||||
@@ -142,54 +149,9 @@ describe('CustomNameColumnComponent', () => {
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('Name column badges', () => {
|
||||
beforeEach(() => {
|
||||
component.context = {
|
||||
row: {
|
||||
node: {
|
||||
entry: {
|
||||
isFile: true,
|
||||
id: 'nodeId'
|
||||
}
|
||||
},
|
||||
getValue: (key: string) => key
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
it('should get badges when component initializes', () => {
|
||||
spyOn(appExtensionService, 'getBadges').and.returnValue(
|
||||
of([{ id: 'test', type: ContentActionType.custom, icon: 'warning', tooltip: 'test tooltip' }])
|
||||
);
|
||||
component.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
const badges = fixture.debugElement.queryAll(By.css('.adf-datatable-cell-badge')).map((badge) => badge.nativeElement);
|
||||
expect(appExtensionService.getBadges).toHaveBeenCalled();
|
||||
expect(badges.length).toBe(1);
|
||||
expect(badges[0].innerText).toBe('warning');
|
||||
expect(badges[0].attributes['title'].value).toBe('test tooltip');
|
||||
});
|
||||
|
||||
it('should call provided handler on click', () => {
|
||||
spyOn(appExtensionService, 'runActionById');
|
||||
spyOn(appExtensionService, 'getBadges').and.returnValue(
|
||||
of([{ id: 'test', type: ContentActionType.custom, icon: 'warning', tooltip: 'test tooltip', actions: { click: 'test' } }])
|
||||
);
|
||||
component.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
const badges = fixture.debugElement.queryAll(By.css('.adf-datatable-cell-badge')).map((badge) => badge.nativeElement);
|
||||
badges[0].click();
|
||||
expect(appExtensionService.runActionById).toHaveBeenCalledWith('test', component.context.row.node);
|
||||
});
|
||||
|
||||
it('should render dynamic component when badge has one provided', () => {
|
||||
spyOn(appExtensionService, 'getBadges').and.returnValue(
|
||||
of([{ id: 'test', type: ContentActionType.custom, icon: 'warning', tooltip: 'test tooltip', component: 'test-id' }])
|
||||
);
|
||||
component.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
const dynamicComponent = fixture.debugElement.query(By.css('adf-dynamic-component')).nativeElement;
|
||||
expect(dynamicComponent).toBeDefined();
|
||||
});
|
||||
it('should pass node to badge component', () => {
|
||||
const badgeElement = fixture.debugElement.query(By.css('aca-datatable-cell-badges'));
|
||||
expect(badgeElement).not.toBe(null);
|
||||
expect(badgeElement.componentInstance.node).toBe(component.node);
|
||||
});
|
||||
});
|
||||
|
@@ -28,15 +28,24 @@ import { Actions, ofType } from '@ngrx/effects';
|
||||
import { Subject } from 'rxjs';
|
||||
import { filter, takeUntil } from 'rxjs/operators';
|
||||
import { NodeActionTypes } from '@alfresco/aca-shared/store';
|
||||
import { LockedByComponent, isLocked, AppExtensionService, Badge } from '@alfresco/aca-shared';
|
||||
import { LockedByComponent, isLocked } from '@alfresco/aca-shared';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { IconComponent } from '@alfresco/adf-core';
|
||||
import { DynamicExtensionComponent } from '@alfresco/adf-extensions';
|
||||
import { DatatableCellBadgesComponent } from '../datatable-cell-badges/datatable-cell-badges.component';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [CommonModule, TranslateModule, LockedByComponent, IconComponent, NodeNameTooltipPipe, DynamicExtensionComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
TranslateModule,
|
||||
LockedByComponent,
|
||||
IconComponent,
|
||||
NodeNameTooltipPipe,
|
||||
DynamicExtensionComponent,
|
||||
DatatableCellBadgesComponent
|
||||
],
|
||||
selector: 'aca-custom-name-column',
|
||||
templateUrl: './name-column.component.html',
|
||||
styleUrls: ['./name-column.component.scss'],
|
||||
@@ -50,15 +59,8 @@ export class CustomNameColumnComponent extends NameColumnComponent implements On
|
||||
|
||||
isFile: boolean;
|
||||
isFileWriteLocked: boolean;
|
||||
badges: Badge[];
|
||||
|
||||
constructor(
|
||||
element: ElementRef,
|
||||
private cd: ChangeDetectorRef,
|
||||
private actions$: Actions,
|
||||
private nodesService: NodesApiService,
|
||||
private appExtensionService: AppExtensionService
|
||||
) {
|
||||
constructor(element: ElementRef, private cd: ChangeDetectorRef, private actions$: Actions, private nodesService: NodesApiService) {
|
||||
super(element, nodesService);
|
||||
}
|
||||
|
||||
@@ -95,13 +97,6 @@ export class CustomNameColumnComponent extends NameColumnComponent implements On
|
||||
this.isFileWriteLocked = isLocked(this.node);
|
||||
this.cd.detectChanges();
|
||||
});
|
||||
|
||||
this.appExtensionService
|
||||
.getBadges(this.node)
|
||||
.pipe(takeUntil(this.onDestroy$$))
|
||||
.subscribe((badges) => {
|
||||
this.badges = badges;
|
||||
});
|
||||
}
|
||||
|
||||
onLinkClick(event: Event) {
|
||||
@@ -115,10 +110,4 @@ export class CustomNameColumnComponent extends NameColumnComponent implements On
|
||||
this.onDestroy$$.next(true);
|
||||
this.onDestroy$$.complete();
|
||||
}
|
||||
|
||||
onBadgeClick(badge: Badge) {
|
||||
if (badge.actions?.click) {
|
||||
this.appExtensionService.runActionById(badge.actions?.click, this.node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user