[HXCS-1166] extend SnackBar to customize content appearance (#8379)

* [HXCS-1166] add templateRef to SnackBarData interface

* [HXCS-1166] update SnackBarContentComponent

to be able to manage data.templateRef

* [HXCS-1166] add tests to NotificationService

* [HXCS-1166] fix lint

* [HXCS-1166] add documentation

* [HXCS-1166] follow PR advices

* [HXCS-1166] typos

* [HXCS-1166] update testrail id

---------

Co-authored-by: Adriano Costa <Adriano.Costa@hyland.comgit>
This commit is contained in:
Adriano Costa 2023-03-21 16:54:29 +01:00 committed by GitHub
parent 0c4cc37dd2
commit cfe158839b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 124 additions and 8 deletions

View File

@ -4,17 +4,32 @@
<ul>
<li>Try setting custom message with unicode characters, for example: <strong>I ♥️ ADF</strong></li>
<li>Try setting custom i18n resource key, for example: <strong>APP_LAYOUT.NOTIFICATIONS</strong></li>
<li>Try setting a decorative icon, for example <strong>info</strong> or <strong>folder</strong></li>
<li>Try toggling the action button. Clicking the action within SnackBar should update the label under the toggle button.</li>
<li>All elements support <em>data-automation-id</em> attributes and can be automated.</li>
</ul>
<mat-form-field>
<input
matInput
placeholder="Message"
[(ngModel)]="message"
data-automation-id="notification-message">
</mat-form-field>
<div>
<mat-label class="adf-label">Message:</mat-label>
<mat-form-field>
<input
matInput
placeholder="Message"
[(ngModel)]="message"
data-automation-id="notification-message">
</mat-form-field>
</div>
<div>
<mat-label class="adf-label">Decorative icon:</mat-label>
<mat-form-field>
<input
matInput
placeholder="Decorative Icon"
[(ngModel)]="decorativeIcon"
data-automation-id="notification-icon">
</mat-form-field>
</div>
<div>
<mat-slide-toggle

View File

@ -1,3 +1,7 @@
.app-main-content {
padding: 10px;
.adf-label {
margin-right: 12px;
}
}

View File

@ -29,6 +29,7 @@ import { takeUntil } from 'rxjs/operators';
export class NotificationsComponent implements OnInit, OnDestroy {
message = 'I ♥️ ADF';
decorativeIcon = 'folder';
withAction = false;
actionOutput = '';
snackBarConfigObject = '';
@ -111,6 +112,9 @@ export class NotificationsComponent implements OnInit, OnDestroy {
"duration": "${this.snackBarConfig.duration}",
"horizontalPosition": "${ this.snackBarConfig.horizontalPosition}",
"verticalPosition": "${ this.snackBarConfig.verticalPosition}"}`;
this.snackBarConfig.data = { decorativeIcon: this.decorativeIcon };
if (this.message) {
if (this.withAction) {
this.notificationService

View File

@ -120,6 +120,32 @@ export class MyComponent implements OnInit {
}
```
By providing a `decorativeIcon` property in the `SnackBarData`, it is possible to render a decorative
[`MaterialIcon`](https://material.angular.io/components/icon/overview#interactive-icons) to the left of the message.
```ts
import { NotificationService } from '@alfresco/adf-core';
import { MatSnackBarConfig } from '@angular/material/snackbar';
export class MyComponent implements OnInit {
snackBarConfig: MatSnackBarConfig = new MatSnackBarConfig();
constructor(private notificationService: NotificationService) {
}
ngOnInit() {
this.snackBarConfig.data = { decorativeIcon: 'folder' };
this.notificationService
.openSnackMessageAction('Do you want to report this issue?', 'send', snackBarConfig)
.afterDismissed()
.subscribe(() => {
console.log('The snack-bar was dismissed');
});
}
}
```
The default message duration is 5000 ms that is used only if you don't pass a custom duration in the parameters of openSnackMessageAction/openSnackMessage methods.
You can also change the default 5000 ms adding the following configuration in the app.config.json:

View File

@ -67,6 +67,13 @@ describe('Notifications Component', () => {
await expect(await notificationPage.snackbarPage.getSnackBarMessage()).toEqual('test');
});
it('[C694098] Should show a decorative icon when the message and the icon fields are not empty and button is clicked', async () => {
await notificationPage.enterMessageField('test');
await notificationPage.enterDecorativeIconField('folder');
await notificationPage.clickNotificationButton();
await expect(await notificationPage.snackbarPage.getSnackBarDecorativeIcon()).toEqual('folder');
});
it('[C279978] Should show notification with action when the message is not empty and button is clicked', async () => {
await notificationPage.enterMessageField('test');
await notificationPage.clickActionToggle();

View File

@ -23,6 +23,7 @@ export class NotificationDemoPage {
snackbarPage = new SnackbarPage();
messageField = $('input[data-automation-id="notification-message"]');
decorativeIconField = $('input[data-automation-id="notification-icon"]');
durationField = $('input[data-automation-id="notification-duration"]');
actionToggle = $('mat-slide-toggle[data-automation-id="notification-action-toggle"]');
notificationSnackBar = $$('simple-snack-bar').first();
@ -50,6 +51,10 @@ export class NotificationDemoPage {
await BrowserActions.clearSendKeys(this.messageField, text);
}
async enterDecorativeIconField(icon: string): Promise<void> {
await BrowserActions.clearSendKeys(this.decorativeIconField, icon);
}
async enterDurationField(time: number): Promise<void> {
await BrowserActions.clearSendKeys(this.durationField, time.toString());
}

View File

@ -32,6 +32,7 @@ import { TranslateModule } from '@ngx-translate/core';
providers: [NotificationService]
})
class ProvidesNotificationServiceComponent {
constructor(public notificationService: NotificationService) {
}
@ -70,6 +71,22 @@ class ProvidesNotificationServiceComponent {
return this.notificationService.openSnackMessageAction('Test notification', 'TestWarn', matSnackBarConfig);
}
sendMessageWithDecorativeIcon() {
const notificationConfig = new MatSnackBarConfig();
notificationConfig.duration = 1000;
notificationConfig.data = {decorativeIcon: 'info'};
return this.notificationService.openSnackMessage('with decorative icon', notificationConfig);
}
sendMessageWithDecorativeIconAndAction() {
const notificationConfig = new MatSnackBarConfig();
notificationConfig.duration = 1000;
notificationConfig.data = { decorativeIcon: 'folder' };
return this.notificationService.openSnackMessageAction('with decorative icon', 'TestWarn', notificationConfig);
}
}
describe('NotificationService', () => {
@ -197,4 +214,27 @@ describe('NotificationService', () => {
expect(document.querySelector('snack-bar-container')).not.toBeNull();
});
it('should open a message notification bar with a decorative icon', (done) => {
const promise = fixture.componentInstance.sendMessageWithDecorativeIcon();
promise.afterDismissed().subscribe(() => {
done();
});
fixture.detectChanges();
expect(document.querySelector('[data-automation-id="adf-snackbar-message-content"] mat-icon')).not.toBeNull();
});
it('should open a message notification bar with action and a decorative icon', (done) => {
const promise = fixture.componentInstance.sendMessageWithDecorativeIconAndAction();
promise.afterDismissed().subscribe(() => {
done();
});
fixture.detectChanges();
expect(document.querySelector('[data-automation-id="adf-snackbar-message-content"] mat-icon')).not.toBeNull();
});
});

View File

@ -22,4 +22,5 @@ export interface SnackBarData {
message: string;
showAction?: boolean;
callActionOnIconClick?: boolean;
decorativeIcon?: string;
}

View File

@ -1,4 +1,6 @@
<p class="adf-snackbar-message-content" data-automation-id="adf-snackbar-message-content" aria-hidden="true">{{ data.message }}</p>
<p class="adf-snackbar-message-content" data-automation-id="adf-snackbar-message-content" aria-hidden="true">
<mat-icon *ngIf="data.decorativeIcon" data-automation-id="adf-snackbar-decorative-icon">{{ data.decorativeIcon }}</mat-icon>{{ data.message }}
</p>
<div *ngIf="data.showAction" class="adf-snackbar-message-content-action" aria-hidden="true">
<button mat-button (click)="snackBarRef.dismissWithAction()" *ngIf="data.actionLabel" class="adf-snackbar-message-content-action-button"
data-automation-id="adf-snackbar-message-content-action-button">

View File

@ -4,7 +4,13 @@
justify-content: space-between;
.adf-snackbar-message-content {
display: flex;
align-items: center;
margin: 0;
mat-icon {
margin-right: 8px;
}
}
.adf-snackbar-message-content-action {

View File

@ -24,6 +24,7 @@ export class SnackbarPage {
notificationSnackBar = $$(`[data-automation-id='adf-snackbar-message-content']`).first();
snackBarAction = $(`[data-automation-id='adf-snackbar-message-content-action-button']`);
snackBarContainerCss = $$('adf-snackbar-content');
decorativeIconSnackBar = $(`[data-automation-id='adf-snackbar-decorative-icon']`).first();
async waitForSnackBarToAppear(timeout = 5000) {
return BrowserVisibility.waitUntilElementIsVisible(this.snackBarContainerCss.first(), timeout,
@ -45,6 +46,11 @@ export class SnackbarPage {
return this.snackBarAction.getText();
}
async getSnackBarDecorativeIcon(): Promise<string> {
await this.waitForSnackBarToAppear();
return this.decorativeIconSnackBar.getText();
}
async clickSnackBarAction(): Promise<void> {
await this.waitForSnackBarToAppear();
await BrowserActions.click(this.snackBarAction);