mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
[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:
parent
0c4cc37dd2
commit
cfe158839b
@ -4,17 +4,32 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li>Try setting custom message with unicode characters, for example: <strong>I ♥️ ADF</strong></li>
|
<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 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>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>
|
<li>All elements support <em>data-automation-id</em> attributes and can be automated.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<mat-form-field>
|
<div>
|
||||||
<input
|
<mat-label class="adf-label">Message:</mat-label>
|
||||||
matInput
|
<mat-form-field>
|
||||||
placeholder="Message"
|
<input
|
||||||
[(ngModel)]="message"
|
matInput
|
||||||
data-automation-id="notification-message">
|
placeholder="Message"
|
||||||
</mat-form-field>
|
[(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>
|
<div>
|
||||||
<mat-slide-toggle
|
<mat-slide-toggle
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
.app-main-content {
|
.app-main-content {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|
||||||
|
.adf-label {
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import { takeUntil } from 'rxjs/operators';
|
|||||||
export class NotificationsComponent implements OnInit, OnDestroy {
|
export class NotificationsComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
message = 'I ♥️ ADF';
|
message = 'I ♥️ ADF';
|
||||||
|
decorativeIcon = 'folder';
|
||||||
withAction = false;
|
withAction = false;
|
||||||
actionOutput = '';
|
actionOutput = '';
|
||||||
snackBarConfigObject = '';
|
snackBarConfigObject = '';
|
||||||
@ -111,6 +112,9 @@ export class NotificationsComponent implements OnInit, OnDestroy {
|
|||||||
"duration": "${this.snackBarConfig.duration}",
|
"duration": "${this.snackBarConfig.duration}",
|
||||||
"horizontalPosition": "${ this.snackBarConfig.horizontalPosition}",
|
"horizontalPosition": "${ this.snackBarConfig.horizontalPosition}",
|
||||||
"verticalPosition": "${ this.snackBarConfig.verticalPosition}"}`;
|
"verticalPosition": "${ this.snackBarConfig.verticalPosition}"}`;
|
||||||
|
|
||||||
|
this.snackBarConfig.data = { decorativeIcon: this.decorativeIcon };
|
||||||
|
|
||||||
if (this.message) {
|
if (this.message) {
|
||||||
if (this.withAction) {
|
if (this.withAction) {
|
||||||
this.notificationService
|
this.notificationService
|
||||||
|
@ -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.
|
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:
|
You can also change the default 5000 ms adding the following configuration in the app.config.json:
|
||||||
|
|
||||||
|
@ -67,6 +67,13 @@ describe('Notifications Component', () => {
|
|||||||
await expect(await notificationPage.snackbarPage.getSnackBarMessage()).toEqual('test');
|
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 () => {
|
it('[C279978] Should show notification with action when the message is not empty and button is clicked', async () => {
|
||||||
await notificationPage.enterMessageField('test');
|
await notificationPage.enterMessageField('test');
|
||||||
await notificationPage.clickActionToggle();
|
await notificationPage.clickActionToggle();
|
||||||
|
@ -23,6 +23,7 @@ export class NotificationDemoPage {
|
|||||||
snackbarPage = new SnackbarPage();
|
snackbarPage = new SnackbarPage();
|
||||||
|
|
||||||
messageField = $('input[data-automation-id="notification-message"]');
|
messageField = $('input[data-automation-id="notification-message"]');
|
||||||
|
decorativeIconField = $('input[data-automation-id="notification-icon"]');
|
||||||
durationField = $('input[data-automation-id="notification-duration"]');
|
durationField = $('input[data-automation-id="notification-duration"]');
|
||||||
actionToggle = $('mat-slide-toggle[data-automation-id="notification-action-toggle"]');
|
actionToggle = $('mat-slide-toggle[data-automation-id="notification-action-toggle"]');
|
||||||
notificationSnackBar = $$('simple-snack-bar').first();
|
notificationSnackBar = $$('simple-snack-bar').first();
|
||||||
@ -50,6 +51,10 @@ export class NotificationDemoPage {
|
|||||||
await BrowserActions.clearSendKeys(this.messageField, text);
|
await BrowserActions.clearSendKeys(this.messageField, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async enterDecorativeIconField(icon: string): Promise<void> {
|
||||||
|
await BrowserActions.clearSendKeys(this.decorativeIconField, icon);
|
||||||
|
}
|
||||||
|
|
||||||
async enterDurationField(time: number): Promise<void> {
|
async enterDurationField(time: number): Promise<void> {
|
||||||
await BrowserActions.clearSendKeys(this.durationField, time.toString());
|
await BrowserActions.clearSendKeys(this.durationField, time.toString());
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
|||||||
providers: [NotificationService]
|
providers: [NotificationService]
|
||||||
})
|
})
|
||||||
class ProvidesNotificationServiceComponent {
|
class ProvidesNotificationServiceComponent {
|
||||||
|
|
||||||
constructor(public notificationService: NotificationService) {
|
constructor(public notificationService: NotificationService) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -70,6 +71,22 @@ class ProvidesNotificationServiceComponent {
|
|||||||
return this.notificationService.openSnackMessageAction('Test notification', 'TestWarn', matSnackBarConfig);
|
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', () => {
|
describe('NotificationService', () => {
|
||||||
@ -197,4 +214,27 @@ describe('NotificationService', () => {
|
|||||||
|
|
||||||
expect(document.querySelector('snack-bar-container')).not.toBeNull();
|
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();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -22,4 +22,5 @@ export interface SnackBarData {
|
|||||||
message: string;
|
message: string;
|
||||||
showAction?: boolean;
|
showAction?: boolean;
|
||||||
callActionOnIconClick?: boolean;
|
callActionOnIconClick?: boolean;
|
||||||
|
decorativeIcon?: string;
|
||||||
}
|
}
|
||||||
|
@ -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">
|
<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"
|
<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">
|
data-automation-id="adf-snackbar-message-content-action-button">
|
||||||
|
@ -4,7 +4,13 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
.adf-snackbar-message-content {
|
.adf-snackbar-message-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.adf-snackbar-message-content-action {
|
.adf-snackbar-message-content-action {
|
||||||
|
@ -24,6 +24,7 @@ export class SnackbarPage {
|
|||||||
notificationSnackBar = $$(`[data-automation-id='adf-snackbar-message-content']`).first();
|
notificationSnackBar = $$(`[data-automation-id='adf-snackbar-message-content']`).first();
|
||||||
snackBarAction = $(`[data-automation-id='adf-snackbar-message-content-action-button']`);
|
snackBarAction = $(`[data-automation-id='adf-snackbar-message-content-action-button']`);
|
||||||
snackBarContainerCss = $$('adf-snackbar-content');
|
snackBarContainerCss = $$('adf-snackbar-content');
|
||||||
|
decorativeIconSnackBar = $(`[data-automation-id='adf-snackbar-decorative-icon']`).first();
|
||||||
|
|
||||||
async waitForSnackBarToAppear(timeout = 5000) {
|
async waitForSnackBarToAppear(timeout = 5000) {
|
||||||
return BrowserVisibility.waitUntilElementIsVisible(this.snackBarContainerCss.first(), timeout,
|
return BrowserVisibility.waitUntilElementIsVisible(this.snackBarContainerCss.first(), timeout,
|
||||||
@ -45,6 +46,11 @@ export class SnackbarPage {
|
|||||||
return this.snackBarAction.getText();
|
return this.snackBarAction.getText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getSnackBarDecorativeIcon(): Promise<string> {
|
||||||
|
await this.waitForSnackBarToAppear();
|
||||||
|
return this.decorativeIconSnackBar.getText();
|
||||||
|
}
|
||||||
|
|
||||||
async clickSnackBarAction(): Promise<void> {
|
async clickSnackBarAction(): Promise<void> {
|
||||||
await this.waitForSnackBarToAppear();
|
await this.waitForSnackBarToAppear();
|
||||||
await BrowserActions.click(this.snackBarAction);
|
await BrowserActions.click(this.snackBarAction);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user