mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ACS-5483] group details view general info and list of assigned users (#9329)
* ACS-5483 Added possibility to load and update group * ACS-5483 Implemented unsaved changes dialog * ACS-5483 Removed console log * ACS-5483 Made dynamic chip list reusable * ACS-5483 Fix for more than one row chips * ACS-5483 Fix for pagination * ACS-5483 Added some fixes * ACS-5483 Fixed displaying tags for node * ACS-5483 Renamed css classes * ACS-5483 Fixed resizing when chips have pagination * ACS-5483 Clearing code * ACS-5483 Documentation for dynamic chip list component * ACS-5483 Documentation for unsaved changes dialog and guard * ACS-5483 Documentation for group service * ACS-5483 Unit tests for GroupService * ACS-5483 Unit tests for dynamic chip list component * ACS-5483 Changed fdescribe to describe * ACS-5483 Unit tests for tag node list component * ACS-5483 Unit tests for unsaved changes dialog component * ACS-5483 Unit tests for unsaved changes guard * ACS-5483 Added description field to group models * ACS-5483 Correction for updating with description * ACS-5483 Fixed lint issues * ACS-5483 Addressed PR comments * ACS-5483 Reduced complexity * ACS-5483 Reduced complexity * ACS-5483 Addressed PR comments
This commit is contained in:
@@ -67,6 +67,8 @@ import { AdfDateFnsAdapter } from './common/utils/date-fns-adapter';
|
||||
import { MomentDateAdapter } from './common/utils/moment-date-adapter';
|
||||
import { AdfDateTimeFnsAdapter } from './common/utils/datetime-fns-adapter';
|
||||
import { StoragePrefixFactory } from './app-config';
|
||||
import { UnsavedChangesDialogModule } from './dialogs';
|
||||
import { DynamicChipListModule } from './dynamic-chip-list';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -101,6 +103,8 @@ import { StoragePrefixFactory } from './app-config';
|
||||
NotificationHistoryModule,
|
||||
SearchTextModule,
|
||||
BlankPageModule,
|
||||
UnsavedChangesDialogModule,
|
||||
DynamicChipListModule,
|
||||
HttpClientModule,
|
||||
HttpClientXsrfModule.withOptions({
|
||||
cookieName: 'CSRF-TOKEN',
|
||||
@@ -138,7 +142,9 @@ import { StoragePrefixFactory } from './app-config';
|
||||
IconModule,
|
||||
NotificationHistoryModule,
|
||||
SearchTextModule,
|
||||
BlankPageModule
|
||||
BlankPageModule,
|
||||
UnsavedChangesDialogModule,
|
||||
DynamicChipListModule
|
||||
]
|
||||
})
|
||||
export class CoreModule {
|
||||
|
@@ -17,3 +17,6 @@
|
||||
|
||||
export * from './edit-json/edit-json.dialog';
|
||||
export * from './edit-json/edit-json.dialog.module';
|
||||
export * from './unsaved-changes-dialog/unsaved-changes-dialog.component';
|
||||
export * from './unsaved-changes-dialog/unsaved-changes-dialog.module';
|
||||
export * from './unsaved-changes-dialog/unsaved-changes.guard';
|
||||
|
@@ -0,0 +1,29 @@
|
||||
<h1 mat-dialog-title class="adf-unsaved-changes-dialog-title">
|
||||
{{ 'CORE.DIALOG.UNSAVED_CHANGES.TITLE' | translate }}
|
||||
<button
|
||||
data-automation-id="adf-unsaved-changes-dialog-close-button"
|
||||
mat-icon-button
|
||||
[title]="'CLOSE' | translate"
|
||||
[mat-dialog-close]="false">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</h1>
|
||||
<mat-dialog-content>
|
||||
{{ 'CORE.DIALOG.UNSAVED_CHANGES.DESCRIPTION' | translate }}
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button
|
||||
data-automation-id="adf-unsaved-changes-dialog-cancel-button"
|
||||
mat-button
|
||||
[mat-dialog-close]="false"
|
||||
class="adf-unsaved-changes-dialog-cancel-button">
|
||||
{{ 'CANCEL' | translate | titlecase }}
|
||||
</button>
|
||||
<button
|
||||
data-automation-id="adf-unsaved-changes-dialog-discard-changes-button"
|
||||
mat-button
|
||||
[mat-dialog-close]="true"
|
||||
class="adf-unsaved-changes-dialog-discard-changes-button">
|
||||
{{ 'CORE.DIALOG.UNSAVED_CHANGES.DISCARD_CHANGES_BUTTON' | translate }}
|
||||
</button>
|
||||
</mat-dialog-actions>
|
@@ -0,0 +1,32 @@
|
||||
adf-unsaved-changes-dialog {
|
||||
margin-top: -4px;
|
||||
display: block;
|
||||
|
||||
.adf-unsaved-changes-dialog {
|
||||
&-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&-cancel-button {
|
||||
background-color: var(--adf-secondary-button-background);
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
&-discard-changes-button {
|
||||
color: var(--theme-warn-color-default-contrast);
|
||||
background-color: var(--adf-danger-button-background);
|
||||
min-width: 143px;
|
||||
}
|
||||
|
||||
&-cancel-button, &-discard-changes-button {
|
||||
padding: 4px 14px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CoreTestingModule, UnsavedChangesDialogComponent } from '@alfresco/adf-core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { MatDialogClose } from '@angular/material/dialog';
|
||||
|
||||
describe('UnsavedChangesDialog', () => {
|
||||
let fixture: ComponentFixture<UnsavedChangesDialogComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CoreTestingModule]
|
||||
});
|
||||
fixture = TestBed.createComponent(UnsavedChangesDialogComponent);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
describe('Close icon button', () => {
|
||||
let closeIconButton: DebugElement;
|
||||
|
||||
beforeEach(() => {
|
||||
closeIconButton = fixture.debugElement.query(By.css(
|
||||
'[data-automation-id="adf-unsaved-changes-dialog-close-button"]'
|
||||
));
|
||||
});
|
||||
|
||||
it('should have assigned mat-dialog-close with false as result', () => {
|
||||
expect(closeIconButton.injector.get(MatDialogClose).dialogResult).toBeFalse();
|
||||
});
|
||||
|
||||
it('should have displayed correct icon', () => {
|
||||
expect(closeIconButton.nativeElement.textContent).toBe('close');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Cancel button', () => {
|
||||
it('should have assigned mat-dialog-close with false as result', () => {
|
||||
expect(fixture.debugElement.query(By.css(
|
||||
'[data-automation-id="adf-unsaved-changes-dialog-cancel-button"]'
|
||||
)).injector.get(MatDialogClose).dialogResult).toBeFalse();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Discard changes button', () => {
|
||||
it('should have assigned mat-dialog-close with true as result', () => {
|
||||
expect(fixture.debugElement.query(By.css(
|
||||
'[data-automation-id="adf-unsaved-changes-dialog-discard-changes-button"]'
|
||||
)).injector.get(MatDialogClose).dialogResult).toBeTrue();
|
||||
});
|
||||
});
|
||||
});
|
@@ -0,0 +1,29 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { Component, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Dialog which informs about unsaved changes. Allows discard them and proceed or close dialog and stop proceeding.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'adf-unsaved-changes-dialog',
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
templateUrl: './unsaved-changes-dialog.component.html',
|
||||
styleUrls: ['./unsaved-changes-dialog.component.scss']
|
||||
})
|
||||
export class UnsavedChangesDialogComponent {}
|
@@ -0,0 +1,37 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { UnsavedChangesDialogComponent } from './unsaved-changes-dialog.component';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@NgModule({
|
||||
declarations: [UnsavedChangesDialogComponent],
|
||||
imports: [
|
||||
MatDialogModule,
|
||||
TranslateModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
CommonModule
|
||||
],
|
||||
exports: [UnsavedChangesDialogComponent]
|
||||
})
|
||||
export class UnsavedChangesDialogModule {}
|
@@ -0,0 +1,94 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { CoreTestingModule, UnsavedChangesDialogComponent, UnsavedChangesGuard } from '@alfresco/adf-core';
|
||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
|
||||
describe('UnsavedChangesGuard', () => {
|
||||
let guard: UnsavedChangesGuard;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CoreTestingModule]
|
||||
});
|
||||
guard = TestBed.inject(UnsavedChangesGuard);
|
||||
});
|
||||
|
||||
describe('canDeactivate', () => {
|
||||
let dialog: MatDialog;
|
||||
let afterClosed$: Subject<boolean>;
|
||||
|
||||
beforeEach(() => {
|
||||
afterClosed$ = new Subject<boolean>();
|
||||
dialog = TestBed.inject(MatDialog);
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => afterClosed$ as Observable<boolean>
|
||||
} as MatDialogRef<UnsavedChangesDialogComponent>);
|
||||
});
|
||||
|
||||
it('should return true if unsaved is set to false', () => {
|
||||
guard.unsaved = false;
|
||||
expect(guard.canDeactivate()).toBeTrue();
|
||||
});
|
||||
|
||||
it('should return true if unsaved was not set', () => {
|
||||
expect(guard.canDeactivate()).toBeTrue();
|
||||
});
|
||||
|
||||
it('should return true when unsaved is set to true and result of dialog is true', (done) => {
|
||||
guard.unsaved = true;
|
||||
|
||||
(guard.canDeactivate() as Observable<boolean>).subscribe((allowed) => {
|
||||
expect(allowed).toBeTrue();
|
||||
done();
|
||||
});
|
||||
afterClosed$.next(true);
|
||||
});
|
||||
|
||||
it('should return false when unsaved is set to true and result of dialog is false', (done) => {
|
||||
guard.unsaved = true;
|
||||
|
||||
(guard.canDeactivate() as Observable<boolean>).subscribe((allowed) => {
|
||||
expect(allowed).toBeFalse();
|
||||
done();
|
||||
});
|
||||
afterClosed$.next(false);
|
||||
});
|
||||
|
||||
it('should keep unsaved set to true when unsaved was to true and result of dialog is false', (done) => {
|
||||
guard.unsaved = true;
|
||||
|
||||
(guard.canDeactivate() as Observable<boolean>).subscribe(() => {
|
||||
expect(guard.unsaved).toBeTrue();
|
||||
done();
|
||||
});
|
||||
afterClosed$.next(false);
|
||||
});
|
||||
|
||||
it('should set unsaved to false when unsaved is set to true and result of dialog is true', (done) => {
|
||||
guard.unsaved = true;
|
||||
|
||||
(guard.canDeactivate() as Observable<boolean>).subscribe(() => {
|
||||
expect(guard.unsaved).toBeFalse();
|
||||
done();
|
||||
});
|
||||
afterClosed$.next(true);
|
||||
});
|
||||
});
|
||||
});
|
@@ -0,0 +1,47 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CanDeactivate } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { UnsavedChangesDialogComponent } from './unsaved-changes-dialog.component';
|
||||
import { tap } from 'rxjs/operators';
|
||||
|
||||
/**
|
||||
* Guard responsible for protecting leaving page with unsaved changes.
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UnsavedChangesGuard implements CanDeactivate<any> {
|
||||
unsaved = false;
|
||||
|
||||
constructor(private dialog: MatDialog) {}
|
||||
|
||||
/**
|
||||
* Allows to deactivate route when there is no unsaved changes, otherwise displays dialog to confirm discarding changes.
|
||||
*
|
||||
* @returns boolean | Observable<boolean> true when there is no unsaved changes or changes can be discarded, false otherwise.
|
||||
*/
|
||||
canDeactivate(): boolean | Observable<boolean> {
|
||||
return this.unsaved ?
|
||||
this.dialog.open<UnsavedChangesDialogComponent, undefined, boolean>(UnsavedChangesDialogComponent, {
|
||||
maxWidth: 346
|
||||
}).afterClosed().pipe(tap((confirmed) => this.unsaved = !confirmed)) : true;
|
||||
}
|
||||
}
|
21
lib/core/src/lib/dynamic-chip-list/chip.ts
Normal file
21
lib/core/src/lib/dynamic-chip-list/chip.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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 Chip {
|
||||
name: string;
|
||||
id: string;
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
<div
|
||||
class="adf-dynamic-chip-list-container"
|
||||
[class.adf-dynamic-chip-list-flex-column]="limitChipsDisplayed && (!calculationsDone || columnFlexDirection)"
|
||||
[class.adf-dynamic-chip-list-button-in-next-line]="moveLoadMoreButtonToNextRow"
|
||||
[class.adf-dynamic-chip-list-paginated]="paginationData"
|
||||
#nodeListContainer>
|
||||
<mat-chip-list
|
||||
[class.adf-dynamic-chip-list-full-width]="limitChipsDisplayed && !calculationsDone"
|
||||
role="listbox"
|
||||
[attr.aria-label]="'METADATA.BASIC.TAGS' | translate">
|
||||
<mat-chip
|
||||
class="adf-dynamic-chip-list-chip"
|
||||
*ngFor="let chip of chipsToDisplay; let idx = index"
|
||||
(removed)="removedChip.emit(chip.id)">
|
||||
<span id="adf-dynamic-chip-list-chip-name-{{ idx }}">{{ chip.name }}</span>
|
||||
<mat-icon
|
||||
*ngIf="showDelete"
|
||||
id="adf-dynamic-chip-list-delete-{{ chip.name }}"
|
||||
class="adf-dynamic-chip-list-delete-icon"
|
||||
matChipRemove>
|
||||
cancel
|
||||
</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
<button
|
||||
data-automation-id="adf-dynamic-chip-list-view-more-button"
|
||||
mat-button
|
||||
[hidden]="!limitChipsDisplayed"
|
||||
[style.left.px]="viewMoreButtonLeftOffset"
|
||||
[style.top.px]="viewMoreButtonTop"
|
||||
class="adf-dynamic-chip-list-view-more-button"
|
||||
[class.adf-dynamic-chip-list-hidden-btn]="!calculationsDone"
|
||||
(click)="displayNextChips($event)">
|
||||
{{
|
||||
paginationData ? ('DYNAMIC_CHIP_LIST.LOAD_MORE' | translate) :
|
||||
('TAG_NODE_LIST.VIEW_MORE' | translate: { count: undisplayedChipsCount})
|
||||
}}
|
||||
</button>
|
||||
</div>
|
@@ -0,0 +1,82 @@
|
||||
.adf-dynamic-chip-list-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: inherit;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
|
||||
.adf-dynamic-chip-list-view-more-button {
|
||||
color: var(--adf-theme-foreground-text-color-054);
|
||||
position: absolute;
|
||||
|
||||
&[hidden] {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&.adf-dynamic-chip-list-flex-column {
|
||||
flex-direction: column;
|
||||
|
||||
.adf-dynamic-chip-list-view-more-button {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
&.adf-dynamic-chip-list-paginated {
|
||||
mat-chip-list {
|
||||
width: 100%;
|
||||
|
||||
& > div {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.adf-dynamic-chip-list-view-more-button {
|
||||
margin: -2px 4px 4px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
&.adf-dynamic-chip-list-button-in-next-line {
|
||||
align-items: unset;
|
||||
padding-bottom: 54px;
|
||||
|
||||
.adf-dynamic-chip-list-view-more-button {
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.adf-dynamic-chip-list-paginated) {
|
||||
align-items: center;
|
||||
|
||||
&:not(.adf-dynamic-chip-list-flex-column) {
|
||||
.adf-dynamic-chip-list-view-more-button {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.adf-dynamic-chip-list-full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.adf-dynamic-chip-list-hidden-btn {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.adf-dynamic-chip-list-chip {
|
||||
color: var(--theme-primary-color-default-contrast);
|
||||
background-color: var(--theme-primary-color);
|
||||
height: auto;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.adf-dynamic-chip-list-delete-icon {
|
||||
font-size: var(--theme-title-font-size);
|
||||
background-repeat: no-repeat;
|
||||
display: inline-block;
|
||||
fill: currentcolor;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
color: var(--theme-primary-color-default-contrast);
|
||||
}
|
||||
}
|
@@ -0,0 +1,297 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { Chip, CoreTestingModule, DynamicChipListComponent } from '@alfresco/adf-core';
|
||||
import { SimpleChange } from '@angular/core';
|
||||
|
||||
describe('DynamicChipListComponent', () => {
|
||||
let chips: Chip[] = [{
|
||||
name: 'test1',
|
||||
id: '0ee933fa-57fc-4587-8a77-b787e814f1d2'
|
||||
}, {
|
||||
name: 'test2',
|
||||
id: 'fcb92659-1f10-41b4-9b17-851b72a3b597'
|
||||
}, {
|
||||
name: 'test3',
|
||||
id: 'fb4213c0-729d-466c-9a6c-ee2e937273bf'
|
||||
}, {
|
||||
name: 'test4',
|
||||
id: 'as4213c0-729d-466c-9a6c-ee2e937273as'
|
||||
}];
|
||||
let component: DynamicChipListComponent;
|
||||
let fixture: ComponentFixture<DynamicChipListComponent>;
|
||||
let element: HTMLElement;
|
||||
let resizeCallback: ResizeObserverCallback;
|
||||
|
||||
/**
|
||||
* Find 'More' button
|
||||
*
|
||||
* @returns native element
|
||||
*/
|
||||
function findViewMoreButton(): HTMLButtonElement {
|
||||
return element.querySelector('[data-automation-id="adf-dynamic-chip-list-view-more-button"]');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the chips
|
||||
*
|
||||
* @returns native element list
|
||||
*/
|
||||
function findChips(): NodeListOf<Element> {
|
||||
return element.querySelectorAll('.adf-dynamic-chip-list-chip');
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
CoreTestingModule
|
||||
]
|
||||
});
|
||||
const resizeObserverSpy = spyOn(window, 'ResizeObserver').and.callThrough();
|
||||
fixture = TestBed.createComponent(DynamicChipListComponent);
|
||||
element = fixture.nativeElement;
|
||||
component = fixture.componentInstance;
|
||||
component.chips = chips;
|
||||
fixture.detectChanges();
|
||||
resizeCallback = resizeObserverSpy.calls.mostRecent().args[0];
|
||||
});
|
||||
|
||||
describe('Rendering tests', () => {
|
||||
it('should render every chip', async () => {
|
||||
component.ngOnChanges({
|
||||
chips: new SimpleChange(undefined, component.chips, true)
|
||||
});
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(element.querySelector('#adf-dynamic-chip-list-chip-name-0').innerHTML).toBe('test1');
|
||||
expect(element.querySelector('#adf-dynamic-chip-list-chip-name-1').innerHTML).toBe('test2');
|
||||
expect(element.querySelector('#adf-dynamic-chip-list-chip-name-2').innerHTML).toBe('test3');
|
||||
|
||||
expect(element.querySelector('#adf-dynamic-chip-list-delete-test1')).not.toBe(null);
|
||||
expect(element.querySelector('#adf-dynamic-chip-list-delete-test2')).not.toBe(null);
|
||||
expect(element.querySelector('#adf-dynamic-chip-list-delete-test3')).not.toBe(null);
|
||||
});
|
||||
|
||||
it('should emit removedChip event when clicked on delete icon', async () => {
|
||||
spyOn(component.removedChip, 'emit');
|
||||
|
||||
component.ngOnChanges({
|
||||
chips: new SimpleChange(undefined, component.chips, true)
|
||||
});
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const deleteButton: any = element.querySelector('#adf-dynamic-chip-list-delete-test1');
|
||||
deleteButton.click();
|
||||
|
||||
expect(component.removedChip.emit).toHaveBeenCalledWith('0ee933fa-57fc-4587-8a77-b787e814f1d2');
|
||||
});
|
||||
|
||||
it('should not show the delete button if showDelete is false', async () => {
|
||||
component.showDelete = false;
|
||||
|
||||
component.ngOnChanges({
|
||||
chips: new SimpleChange(undefined, component.chips, true)
|
||||
});
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const deleteButton: any = element.querySelector('#adf-dynamic-chip-list-delete-test1');
|
||||
expect(deleteButton).toBeNull();
|
||||
});
|
||||
|
||||
it('should show the delete button if showDelete is true', async () => {
|
||||
component.showDelete = true;
|
||||
|
||||
component.ngOnChanges({
|
||||
chips: new SimpleChange(undefined, component.chips, true)
|
||||
});
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const deleteButton: any = element.querySelector('#adf-dynamic-chip-list-delete-test1');
|
||||
expect(deleteButton).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should not render view more button by default', async () => {
|
||||
component.ngOnChanges({
|
||||
chips: new SimpleChange(undefined, component.chips, true)
|
||||
});
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(findViewMoreButton().hidden).toBeTrue();
|
||||
expect(findChips()).toHaveSize(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Limit chips display', () => {
|
||||
let initialChips: Chip[];
|
||||
|
||||
/**
|
||||
* Render chips
|
||||
*
|
||||
* @param chipsToRender chips to render
|
||||
*/
|
||||
async function renderChips(chipsToRender?: Chip[]) {
|
||||
chips = chipsToRender || initialChips;
|
||||
component.chips = chips;
|
||||
fixture.detectChanges();
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
initialChips = chips;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
component.limitChipsDisplayed = true;
|
||||
component.ngOnInit();
|
||||
element.style.maxWidth = '309px';
|
||||
});
|
||||
|
||||
it('should render view more button when limiting is enabled', fakeAsync(() => {
|
||||
renderChips();
|
||||
component.ngOnChanges({
|
||||
chips: new SimpleChange(undefined, component.chips, true)
|
||||
});
|
||||
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
expect(findViewMoreButton().hidden).toBeFalse();
|
||||
expect(findChips()).toHaveSize(1);
|
||||
}));
|
||||
|
||||
it('should not render view more button when limiting is enabled and all chips fits into container', fakeAsync(() => {
|
||||
renderChips();
|
||||
element.style.maxWidth = '800px';
|
||||
component.ngOnChanges({
|
||||
chips: new SimpleChange(undefined, component.chips, true)
|
||||
});
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(findViewMoreButton().hidden).toBeTrue();
|
||||
expect(findChips()).toHaveSize(4);
|
||||
}));
|
||||
|
||||
it('should emit displayNext event when view more button is clicked', fakeAsync(() => {
|
||||
renderChips();
|
||||
component.ngOnChanges({
|
||||
chips: new SimpleChange(undefined, component.chips, true)
|
||||
});
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
spyOn(component.displayNext, 'emit');
|
||||
|
||||
const viewMoreButton = findViewMoreButton();
|
||||
viewMoreButton.click();
|
||||
fixture.detectChanges();
|
||||
expect(viewMoreButton.hidden).toBeTrue();
|
||||
expect(findChips()).toHaveSize(1);
|
||||
expect(component.displayNext.emit).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should not render view more button when chip takes more than one line and there are no more chips', fakeAsync(() => {
|
||||
renderChips([{
|
||||
name: 'VeryLongTag VeryLongTag VeryLongTag VeryLongTag VeryLongTag VeryLongTag VeryLongTag VeryLongTag',
|
||||
id: '0ee933fa-57fc-4587-8a77-b787e814f1d2'
|
||||
}]);
|
||||
component.ngOnChanges({
|
||||
chips: new SimpleChange(undefined, component.chips, true)
|
||||
});
|
||||
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
expect(findViewMoreButton().hidden).toBeTrue();
|
||||
expect(findChips()).toHaveSize(component.chips.length);
|
||||
}));
|
||||
|
||||
it('should render view more button when chip takes more than one line and there are more chips', fakeAsync(() => {
|
||||
renderChips([{
|
||||
name: 'VeryLongTag VeryLongTag VeryLongTag VeryLongTag VeryLongTag VeryLongTag VeryLongTag VeryLongTag',
|
||||
id: '0ee933fa-57fc-4587-8a77-b787e814f1d2'
|
||||
}, {
|
||||
name: 'Some other tag',
|
||||
id: '0ee933fa-57fc-4587-8a77-b787e814f1d3'
|
||||
}]);
|
||||
component.ngOnChanges({
|
||||
chips: new SimpleChange(undefined, component.chips, true)
|
||||
});
|
||||
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
const viewMoreButton = findViewMoreButton();
|
||||
expect(viewMoreButton.hidden).toBeFalse();
|
||||
expect(viewMoreButton.style.left).toBe('0px');
|
||||
expect(findChips()).toHaveSize(1);
|
||||
}));
|
||||
|
||||
it('should not render view more button when there is enough space after resizing', fakeAsync(() => {
|
||||
renderChips();
|
||||
component.ngOnChanges({
|
||||
chips: new SimpleChange(undefined, component.chips, true)
|
||||
});
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
element.style.maxWidth = '800px';
|
||||
|
||||
resizeCallback([], null);
|
||||
fixture.detectChanges();
|
||||
const viewMoreButton = findViewMoreButton();
|
||||
expect(viewMoreButton.hidden).toBeTrue();
|
||||
expect(findChips()).toHaveSize(4);
|
||||
}));
|
||||
|
||||
it('should render view more button when there is not enough space after resizing', fakeAsync(() => {
|
||||
renderChips();
|
||||
element.style.maxWidth = '800px';
|
||||
|
||||
component.ngOnChanges({
|
||||
chips: new SimpleChange(undefined, component.chips, true)
|
||||
});
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
element.style.maxWidth = '309px';
|
||||
|
||||
resizeCallback([], null);
|
||||
fixture.detectChanges();
|
||||
expect(findViewMoreButton().hidden).toBeFalse();
|
||||
expect(findChips()).toHaveSize(1);
|
||||
}));
|
||||
|
||||
it('should not render view more button again after resizing when there is not enough space if user requested to see all chips', fakeAsync(() => {
|
||||
renderChips();
|
||||
component.ngOnChanges({
|
||||
chips: new SimpleChange(undefined, component.chips, true)
|
||||
});
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
const viewMoreButton = findViewMoreButton();
|
||||
viewMoreButton.click();
|
||||
fixture.detectChanges();
|
||||
element.style.maxWidth = '309px';
|
||||
|
||||
resizeCallback([], null);
|
||||
fixture.detectChanges();
|
||||
expect(viewMoreButton.hidden).toBeTrue();
|
||||
}));
|
||||
});
|
||||
});
|
@@ -0,0 +1,218 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
QueryList,
|
||||
SimpleChanges,
|
||||
ViewChild,
|
||||
ViewChildren,
|
||||
ViewEncapsulation
|
||||
} from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { MatChip } from '@angular/material/chips';
|
||||
import { Chip } from './chip';
|
||||
import { Pagination } from '@alfresco/js-api';
|
||||
|
||||
/**
|
||||
* This component shows dynamic list of chips which render depending on free space.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'adf-dynamic-chip-list',
|
||||
templateUrl: './dynamic-chip-list.component.html',
|
||||
styleUrls: ['./dynamic-chip-list.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class DynamicChipListComponent implements OnChanges, OnInit, AfterViewInit, OnDestroy {
|
||||
/* eslint no-underscore-dangle: ["error", { "allow": ["_elementRef"] }]*/
|
||||
/** Provide if you want to use paginated chips. */
|
||||
@Input()
|
||||
pagination: Pagination;
|
||||
|
||||
/** List of chips to display. */
|
||||
@Input()
|
||||
chips: Chip[];
|
||||
|
||||
/** Show delete button. */
|
||||
@Input()
|
||||
showDelete = true;
|
||||
|
||||
/** Should limit number of chips displayed. */
|
||||
@Input()
|
||||
limitChipsDisplayed = false;
|
||||
|
||||
/** Emitted when button for view more is clicked. */
|
||||
@Output()
|
||||
displayNext = new EventEmitter<void>();
|
||||
|
||||
/** Emitted when any chip is removed. */
|
||||
@Output()
|
||||
removedChip = new EventEmitter<string>();
|
||||
|
||||
@ViewChild('nodeListContainer')
|
||||
containerView: ElementRef;
|
||||
|
||||
@ViewChildren(MatChip)
|
||||
matChips: QueryList<MatChip>;
|
||||
|
||||
chipsToDisplay: Chip[] = [];
|
||||
calculationsDone = false;
|
||||
columnFlexDirection = false;
|
||||
moveLoadMoreButtonToNextRow = false;
|
||||
undisplayedChipsCount = 0;
|
||||
viewMoreButtonLeftOffset: number;
|
||||
viewMoreButtonTop = 0;
|
||||
paginationData: Pagination;
|
||||
|
||||
private initialChips: Chip[] = [];
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
private initialLimitChipsDisplayed: boolean;
|
||||
private viewMoreButtonLeftOffsetBeforeFlexDirection: number;
|
||||
private requestedDisplayingAllChips = false;
|
||||
private resizeObserver = new ResizeObserver(() => {
|
||||
this.calculateChipsToDisplay();
|
||||
this.changeDetectorRef.detectChanges();
|
||||
});
|
||||
|
||||
constructor(private changeDetectorRef: ChangeDetectorRef) {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes.pagination) {
|
||||
this.limitChipsDisplayed = this.pagination?.hasMoreItems;
|
||||
this.paginationData = this.pagination;
|
||||
this.initialLimitChipsDisplayed = this.limitChipsDisplayed;
|
||||
}
|
||||
if (changes.chips) {
|
||||
this.initialChips = this.chips;
|
||||
this.chipsToDisplay = this.initialChips;
|
||||
if (this.limitChipsDisplayed && this.chipsToDisplay.length) {
|
||||
setTimeout(() => {
|
||||
this.calculateChipsToDisplay();
|
||||
this.changeDetectorRef.detectChanges();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.paginationData) {
|
||||
this.limitChipsDisplayed = this.paginationData.hasMoreItems;
|
||||
}
|
||||
this.initialLimitChipsDisplayed = this.limitChipsDisplayed;
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.resizeObserver.observe(this.containerView.nativeElement);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.onDestroy$.next(true);
|
||||
this.onDestroy$.complete();
|
||||
this.resizeObserver.unobserve(this.containerView.nativeElement);
|
||||
}
|
||||
|
||||
displayNextChips(event: Event): void {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (this.paginationData) {
|
||||
this.requestedDisplayingAllChips = !this.paginationData.hasMoreItems;
|
||||
} else {
|
||||
this.limitChipsDisplayed = false;
|
||||
this.requestedDisplayingAllChips = true;
|
||||
}
|
||||
if (this.requestedDisplayingAllChips) {
|
||||
this.resizeObserver.unobserve(this.containerView.nativeElement);
|
||||
}
|
||||
this.displayNext.emit();
|
||||
}
|
||||
|
||||
private calculateChipsToDisplay(): void {
|
||||
if (this.requestedDisplayingAllChips || !this.chips.length) {
|
||||
return;
|
||||
}
|
||||
this.chipsToDisplay = this.initialChips;
|
||||
this.changeDetectorRef.detectChanges();
|
||||
this.undisplayedChipsCount = 0;
|
||||
let chipsToDisplay = 1;
|
||||
const containerWidth: number = this.containerView.nativeElement.clientWidth;
|
||||
const viewMoreButton: HTMLButtonElement = this.containerView.nativeElement.children[1];
|
||||
const viewMoreBtnWidth: number = viewMoreButton.getBoundingClientRect().width;
|
||||
const firstChip = this.matChips.get(0);
|
||||
const chipMargin = firstChip ? this.getChipMargin(firstChip) : 0;
|
||||
let chipsWidth = 0;
|
||||
const chips = this.matChips.toArray();
|
||||
let lastIndex = 0;
|
||||
do {
|
||||
chipsWidth = Math.max(chips.reduce((width, val, index) => {
|
||||
width += val._elementRef.nativeElement.getBoundingClientRect().width + chipMargin;
|
||||
const availableSpace = index && index === chips.length - 1 || !this.paginationData ? containerWidth - viewMoreBtnWidth : containerWidth;
|
||||
if (availableSpace >= width) {
|
||||
chipsToDisplay = (this.paginationData ? chipsToDisplay : index) + 1;
|
||||
lastIndex++;
|
||||
this.viewMoreButtonLeftOffset = width;
|
||||
this.viewMoreButtonLeftOffsetBeforeFlexDirection = width;
|
||||
}
|
||||
return width;
|
||||
}, 0), chipsWidth);
|
||||
chips.splice(0, lastIndex);
|
||||
lastIndex = 0;
|
||||
} while ((chips.length || chipsToDisplay < this.matChips.length && this.matChips.length) && this.paginationData);
|
||||
this.arrangeElements(containerWidth, chipsWidth, viewMoreBtnWidth, chipsToDisplay, viewMoreButton);
|
||||
this.calculationsDone = true;
|
||||
}
|
||||
|
||||
private getChipMargin(chip: MatChip): number {
|
||||
const chipStyles = window.getComputedStyle(chip._elementRef.nativeElement);
|
||||
return parseInt(chipStyles.marginLeft, 10) + parseInt(chipStyles.marginRight, 10);
|
||||
}
|
||||
|
||||
private arrangeElements(containerWidth: number, chipsWidth: number, viewMoreBtnWidth: number, chipsToDisplay: number,
|
||||
viewMoreButton: HTMLButtonElement): void {
|
||||
if ((containerWidth - chipsWidth - viewMoreBtnWidth) <= 0) {
|
||||
const chip = this.paginationData ? this.matChips.last : this.matChips.first;
|
||||
const hasNotEnoughSpaceForMoreButton = (containerWidth < (chip?._elementRef.nativeElement.offsetWidth + chip?._elementRef.nativeElement.offsetLeft + viewMoreBtnWidth));
|
||||
this.columnFlexDirection = chipsToDisplay === 1 && !this.paginationData && hasNotEnoughSpaceForMoreButton;
|
||||
this.moveLoadMoreButtonToNextRow = this.paginationData && hasNotEnoughSpaceForMoreButton;
|
||||
this.undisplayedChipsCount = this.chipsToDisplay.length - chipsToDisplay;
|
||||
this.chipsToDisplay = this.chipsToDisplay.slice(0, chipsToDisplay);
|
||||
} else {
|
||||
this.moveLoadMoreButtonToNextRow = false;
|
||||
}
|
||||
this.limitChipsDisplayed = this.undisplayedChipsCount ? this.initialLimitChipsDisplayed : this.paginationData?.hasMoreItems;
|
||||
if (this.paginationData?.hasMoreItems) {
|
||||
const lastChipTop = this.matChips.last._elementRef.nativeElement.offsetTop;
|
||||
if (this.moveLoadMoreButtonToNextRow) {
|
||||
this.viewMoreButtonLeftOffset = 0;
|
||||
this.viewMoreButtonTop = lastChipTop + viewMoreButton.offsetHeight;
|
||||
} else {
|
||||
this.viewMoreButtonLeftOffset = this.viewMoreButtonLeftOffsetBeforeFlexDirection;
|
||||
this.viewMoreButtonTop = lastChipTop;
|
||||
}
|
||||
} else {
|
||||
this.viewMoreButtonLeftOffset = this.columnFlexDirection ? 0 : this.viewMoreButtonLeftOffsetBeforeFlexDirection;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { DynamicChipListComponent } from './dynamic-chip-list.component';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@NgModule({
|
||||
declarations: [DynamicChipListComponent],
|
||||
imports: [
|
||||
MatChipsModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
TranslateModule,
|
||||
CommonModule
|
||||
],
|
||||
exports: [DynamicChipListComponent]
|
||||
})
|
||||
export class DynamicChipListModule {}
|
18
lib/core/src/lib/dynamic-chip-list/index.ts
Normal file
18
lib/core/src/lib/dynamic-chip-list/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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 * from './public-api';
|
20
lib/core/src/lib/dynamic-chip-list/public-api.ts
Normal file
20
lib/core/src/lib/dynamic-chip-list/public-api.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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 * from './dynamic-chip-list.component';
|
||||
export * from './dynamic-chip-list.module';
|
||||
export * from './chip';
|
@@ -106,6 +106,11 @@
|
||||
"EDIT_JSON": {
|
||||
"CLOSE": "Close",
|
||||
"UPDATE": "Update"
|
||||
},
|
||||
"UNSAVED_CHANGES": {
|
||||
"TITLE": "Unsaved changes",
|
||||
"DESCRIPTION": "You have unsaved changes on this screen. Are you sure want to leave without saving changes?",
|
||||
"DISCARD_CHANGES_BUTTON": "Discard Changes"
|
||||
}
|
||||
},
|
||||
"BREADCRUMBS": {
|
||||
@@ -573,5 +578,8 @@
|
||||
},
|
||||
"INFO_DRAWER": {
|
||||
"ICON": "Node Icon"
|
||||
},
|
||||
"DYNAMIC_CHIP_LIST": {
|
||||
"LOAD_MORE": "Load more"
|
||||
}
|
||||
}
|
||||
|
@@ -96,6 +96,8 @@
|
||||
--adf-header-icon-button-hover-color: $adf-ref-header-icon-color,
|
||||
--adf-header-icon-button-pressed-color: $adf-ref-header-icon-color,
|
||||
--adf-header-icon-button-disabled-color: $adf-ref-header-icon-color,
|
||||
--adf-danger-button-background: $adf-danger-button-background,
|
||||
--adf-secondary-button-background: $adf-secondary-button-background
|
||||
);
|
||||
|
||||
// propagates SCSS variables into the CSS variables scope
|
||||
|
@@ -25,3 +25,5 @@ $adf-ref-metadata-property-panel-label-color: rgba(33, 33, 33, 0.24);
|
||||
$adf-ref-metadata-property-panel-title-color: rgb(33, 33, 33);
|
||||
$adf-ref-header-icon-color: inherit;
|
||||
$adf-ref-header-icon-border-radius: 50%;
|
||||
$adf-danger-button-background: #ba1b1b;
|
||||
$adf-secondary-button-background: #2121210d;
|
||||
|
@@ -37,6 +37,7 @@ export * from './lib/templates/index';
|
||||
export * from './lib/pipes/index';
|
||||
export * from './lib/services/index';
|
||||
export * from './lib/directives/index';
|
||||
export * from './lib/dynamic-chip-list/index';
|
||||
export * from './lib/clipboard/index';
|
||||
export * from './lib/dialogs/index';
|
||||
export * from './lib/icon/index';
|
||||
|
Reference in New Issue
Block a user