Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Alert, Alert Group, Alert Service]: New components and service #427

Merged
merged 28 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
ba7252f
DS-269: Expose Alert and AlertGroup components to public API
RiinaKuu Sep 5, 2024
381693f
DS-269: Expose AlertGroup inside Dialog template
RiinaKuu Sep 5, 2024
baea710
DS-269: Change Body Text variant logic when used inside Dialog to avo…
RiinaKuu Sep 5, 2024
1c301b5
DS-269: Refactor Alert message to Observable, add Output for clicking…
RiinaKuu Sep 6, 2024
053e02d
DS-269: Refactor all Alert Service Signals to Observables
RiinaKuu Sep 6, 2024
2cd9823
DS-269: Add exception stylings for Link and Body Text inside Alert
RiinaKuu Sep 6, 2024
9dc641e
DS-269: Update Alert Group docs and Story
RiinaKuu Sep 6, 2024
64db67f
DS-269: Update Alert Service unit tests
RiinaKuu Sep 9, 2024
42a2575
DS-269: Create Playwright tests and base images for Alert Group
RiinaKuu Sep 9, 2024
30a13e3
DS-269: Update Alert Component unit tests, remove tests that are cove…
RiinaKuu Sep 9, 2024
f37d4ca
DS-269: Update Alert Group unit tests, force change detection in Afte…
RiinaKuu Sep 9, 2024
b98fc03
DS-269: Add comment to Alert Group docs that the component is not com…
RiinaKuu Sep 9, 2024
14e115b
Merge branch 'main' into DS-269-alert
RiinaKuu Sep 9, 2024
2eb68e8
DS-269: Fix Playwright test and add missing base images
RiinaKuu Sep 9, 2024
f81f6fb
DS-269: Add focus and blur event unit test back to Alert Component
RiinaKuu Sep 10, 2024
2ce8ccb
DS-269: Fix Alert Group story control
RiinaKuu Sep 10, 2024
ea2aaed
DS-269: Change Dialog Service Signals to Observables
RiinaKuu Sep 11, 2024
49e95f8
DS-269: Remove link feature from Alert, remove string option from Ale…
RiinaKuu Sep 11, 2024
70e962a
DS-269: Change AlertGroup life cycle, add OnPush change detection, re…
RiinaKuu Sep 11, 2024
62f9e50
DS-269: Add Alert Group example to sandbox
RiinaKuu Sep 11, 2024
62a3032
DS-269: Remove unnecessary link-theme file since links are not suppor…
RiinaKuu Sep 11, 2024
eca71d3
DS-269: Remove Link Component styleUrl since its stylesheet is import…
RiinaKuu Sep 11, 2024
27adec2
DS-269: Update Playwright tests and base images after link feature wa…
RiinaKuu Sep 11, 2024
dafa1c6
DS-269: Fix failing test, remove unused property, small addition to docs
RiinaKuu Sep 12, 2024
3958fef
Merge branch 'main' into DS-269-alert
RiinaKuu Sep 13, 2024
1e5588f
DS-269: unit test adjust
videoeero Sep 19, 2024
365944d
DS-289: doc and comment tweaks
videoeero Sep 19, 2024
64931cf
Merge branch 'main' into DS-269-alert
videoeero Sep 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ngx-fudis/projects/dev/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<ng-container *transloco="let t">
<div class="root-style">
<!-- <fudis-alert-group /> -->
<fudis-alert-group />

<fudis-grid [columns]="4" [marginTop]="'lg'">
<fudis-grid-item [columns]="'3 / 4'" [alignSelfX]="'end'" [alignSelfY]="'end'">
Expand All @@ -24,7 +24,7 @@
<fudis-heading [level]="3" fudisGridItem [columns]="'auto'">
<fudis-link [href]="'#'" [title]="'Link inside a heading'"></fudis-link>
</fudis-heading>
<!-- <fudis-button [label]="'Trigger alert'" (handleClick)="triggerAlert()" /> -->
<fudis-button [label]="'Trigger alert'" (handleClick)="triggerAlert()" />
<fudis-button [label]="'Open dialog with form'" (handleClick)="openDialog()" />
<fudis-body-text *ngIf="_message"
>This value comes from the closed dialog input:
Expand Down
24 changes: 11 additions & 13 deletions ngx-fudis/projects/dev/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component, Inject, OnInit } from '@angular/core';
import { TranslocoService } from '@ngneat/transloco';
import {
// FudisAlertService,
FudisAlertService,
FudisDialogService,
FudisGridService,
FudisTranslationService,
Expand All @@ -10,7 +10,7 @@ import {
} from 'ngx-fudis';
import { DOCUMENT } from '@angular/common';
import { FudisSelectOption, FudisCheckboxOption } from 'dist/ngx-fudis/lib/types/forms';
// import { FudisAlert } from 'dist/ngx-fudis/lib/types/miscellaneous';
import { FudisAlert } from 'dist/ngx-fudis/lib/types/miscellaneous';
import { DialogTestContentComponent } from './dialog-test/dialog-test-content/dialog-test-content.component';
import { FudisGridAlign } from 'projects/ngx-fudis/src/lib/types/grid';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
Expand All @@ -28,7 +28,7 @@ export class AppComponent implements OnInit {
private _translocoService: TranslocoService,
private _gridService: FudisGridService,
private _fudisLanguage: FudisTranslationService,
// private _alertService: FudisAlertService,
private _alertService: FudisAlertService,
private _errorSummaryService: FudisErrorSummaryService,
private _breakpointService: FudisBreakpointService,
) {
Expand Down Expand Up @@ -93,16 +93,14 @@ export class AppComponent implements OnInit {
this.getApplicationFontSize();
}

// triggerAlert(): void {
// const newAlert: FudisAlert = {
// message: 'Something dangerous MIGHT happen.',
// type: 'warning',
// id: 'my-own-id-3',
// routerLinkUrl: '/',
// linkTitle: 'More info about this warning.',
// };
// this._alertService.addAlert(newAlert);
// }
triggerAlert(): void {
const newAlert: FudisAlert = {
message: this._translocoService.selectTranslate('alertText'),
type: 'warning',
id: 'my-own-id-3',
};
this._alertService.addAlert(newAlert);
}

getApplicationFontSize(): void {
this.fontSize = getComputedStyle(
Expand Down
1 change: 1 addition & 0 deletions ngx-fudis/projects/dev/src/assets/i18n/en.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"alertText": "Something dangerous MIGHT happen",
"label": "This is text input",
"change_language": "Change language",
"helpText": "This is English.",
Expand Down
1 change: 1 addition & 0 deletions ngx-fudis/projects/dev/src/assets/i18n/fi.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"alertText": "Jotain kamalaa voipi tapahtua",
"label": "Tämä on tekstikenttä",
"change_language": "Vaihda kieli",
"helpText": "Kivaa jos näet minut suomeksi!",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
<section
*ngIf="_visible"
*ngIf="(_visible | async) && (_alertService.alerts | async) as alerts"
class="fudis-alert-group fudis-alert-group__{{ position }}"
[attr.aria-label]="_alertList().length > 0 ? _alertGroupLabel + ': ' + _alertList().length : null"
[attr.aria-label]="alerts.length > 0 ? (_alertGroupLabel | async) + ': ' + alerts.length : null"
>
<ng-container *ngFor="let alert of _alertList()">
<ng-container *ngFor="let alert of alerts">
<fudis-alert
[initialFocus]="alert.initialFocus"
[variant]="alert.type"
[message]="alert.message"
[id]="alert.id"
[htmlId]="alert.htmlId"
[buttonId]="alert.buttonId"
[linkTitle]="alert.linkTitle"
[link]="alert.routerLinkUrl"
/>
</ng-container>
</section>
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { MockComponent } from 'ng-mocks';
import { AlertGroupComponent } from './alert-group.component';
import { FudisDialogService } from '../../../services/dialog/dialog.service';
import { BodyTextComponent } from '../../typography/body-text/body-text.component';
import { FudisAlertService } from '../../../services/alert/alert.service';
import { FudisAlert } from '../../../types/miscellaneous';
import { FudisAlert, fudisAlertPositionArray } from '../../../types/miscellaneous';
import { AlertComponent } from '../alert/alert.component';
import { IconComponent } from '../../icon/icon.component';
import { getElement, sortClasses } from '../../../utilities/tests/utilities';
import { BehaviorSubject } from 'rxjs';
import { SimpleChange } from '@angular/core';

// TODO: fix & refactor when these are again published

describe.skip('AlertGroupComponent', () => {
describe('AlertGroupComponent', () => {
let component: AlertGroupComponent;
let fixture: ComponentFixture<AlertGroupComponent>;
let alertService: FudisAlertService;
let dialogService: FudisDialogService;

beforeEach(() => {
TestBed.configureTestingModule({
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [MatDialogModule],
declarations: [
AlertGroupComponent,
BodyTextComponent,
AlertComponent,
BodyTextComponent,
MockComponent(IconComponent),
],
providers: [
Expand All @@ -39,7 +38,10 @@ describe.skip('AlertGroupComponent', () => {
useValue: [],
},
],
});
}).compileComponents();

alertService = TestBed.inject(FudisAlertService);
dialogService = TestBed.inject(FudisDialogService);
fixture = TestBed.createComponent(AlertGroupComponent);
component = fixture.componentInstance;
fixture.detectChanges();
Expand All @@ -50,55 +52,33 @@ describe.skip('AlertGroupComponent', () => {
});

describe('Basic inputs', () => {
it('should have default CSS classes', () => {
const element = getElement(fixture, 'section');

expect(sortClasses(element.className)).toEqual(
sortClasses('fudis-alert-group fudis-alert-group__fixed'),
);
});

it('should have absolute position', () => {
component.position = 'absolute';
fixture.detectChanges();

const element = getElement(fixture, 'section');

expect(sortClasses(element.className)).toEqual(
sortClasses('fudis-alert-group fudis-alert-group__absolute'),
);
});

it('should have static position', () => {
component.position = 'static';
fixture.detectChanges();

const element = getElement(fixture, 'section');

expect(sortClasses(element.className)).toEqual(
sortClasses('fudis-alert-group fudis-alert-group__static'),
);
it('should update CSS class according to position input', () => {
fudisAlertPositionArray.forEach((position) => {
const element = getElement(fixture, '.fudis-alert-group');
fixture.componentRef.setInput('position', `${position}`);
fixture.detectChanges();

expect(sortClasses(element.className)).toEqual(
sortClasses(`fudis-alert-group fudis-alert-group__${position}`),
);
});
});
});

describe('Functionality with services', () => {
beforeEach(() => {
alertService = TestBed.inject(FudisAlertService);
dialogService = TestBed.inject(FudisDialogService);

jest.spyOn(alertService, 'getAlertsSignal').mockImplementation();

const firstAlert: FudisAlert = {
message: 'Test message',
message: new BehaviorSubject<string>('Test message'),
id: 'my-test-id-1',
type: 'info',
};

const secondAlert: FudisAlert = {
message: 'Second test message',
message: new BehaviorSubject<string>('Second test message'),
id: 'my-test-id-2',
type: 'warning',
};

alertService.addAlert(firstAlert);
alertService.addAlert(secondAlert);
});
Expand All @@ -111,7 +91,7 @@ describe.skip('AlertGroupComponent', () => {
expect(childAlerts.length).toEqual(2);
});

it('should have one alert as children after one is dismissed', () => {
it('should have one alert as child after one is dismissed', () => {
alertService.dismissAlert('my-test-id-1');
fixture.detectChanges();

Expand All @@ -123,7 +103,7 @@ describe.skip('AlertGroupComponent', () => {
});

it('should not be visible, if Dialog is open', () => {
dialogService.setDialogOpenSignal(true);
dialogService.setDialogOpenStatus(true);

fixture.detectChanges();

Expand All @@ -132,7 +112,7 @@ describe.skip('AlertGroupComponent', () => {
});

it('should be visible, if Dialog is closed', () => {
dialogService.setDialogOpenSignal(false);
dialogService.setDialogOpenStatus(false);

fixture.detectChanges();

Expand All @@ -141,11 +121,14 @@ describe.skip('AlertGroupComponent', () => {
});

it('should not be visible, if Dialog is not open and Alert Group is inside dialog', () => {
component.insideDialog = true;
dialogService.setDialogOpenStatus(false);

component.ngAfterViewInit();
component.insideDialog = true;
component.ngOnChanges({
insideDialog: new SimpleChange('false', component.insideDialog, true),
});

fixture.detectChanges();
fixture.autoDetectChanges();

expect(fixture.nativeElement.querySelector('section')).toBeNull();
expect(component.getVisibleStatus()).toEqual(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,82 +1,85 @@
import { ChangeDetectorRef, Component, Input, AfterViewInit, Signal, effect } from '@angular/core';

import { FudisAlertElement } from '../../../types/miscellaneous';
import { Component, Input, effect, OnChanges, ChangeDetectionStrategy } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import {
FudisAlertElement,
FudisAlertPosition,
FudisComponentChanges,
} from '../../../types/miscellaneous';
import { FudisTranslationService } from '../../../services/translation/translation.service';
import { FudisAlertService } from '../../../services/alert/alert.service';
import { FudisDialogService } from '../../../services/dialog/dialog.service';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

@Component({
selector: 'fudis-alert-group',
templateUrl: './alert-group.component.html',
styleUrls: ['./alert-group.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AlertGroupComponent implements AfterViewInit {
export class AlertGroupComponent implements OnChanges {
constructor(
private _alertService: FudisAlertService,
protected _alertService: FudisAlertService,
private _translationService: FudisTranslationService,
private readonly _changeDetectorRef: ChangeDetectorRef,
private _dialogService: FudisDialogService,
) {
effect(() => {
this._alertList = this._alertService.getAlertsSignal();
// TODO: To Observable
this._alertGroupLabel = this._translationService.getTranslations()().ALERT.HEADING_LABEL;
this._dialogService
.getDialogOpenStatus()
.pipe(takeUntilDestroyed())
.subscribe((value) => {
this._setVisibility(value);
});

this._dialogStatus = this._dialogService.getDialogOpenSignal()();

this._setVisibility();
effect(() => {
this._alertGroupLabel.next(this._translationService.getTranslations()().ALERT.HEADING_LABEL);
});
}

/**
* CSS position of alerts. Defaults to fixed.
* CSS position of alerts
*/
@Input() position: 'fixed' | 'absolute' | 'static' = 'fixed';
@Input() position: FudisAlertPosition = 'fixed';

/**
* Boolean to determine if Alert Group is used as child in Fudis Dialog.
* Boolean to determine if Alert Group is used inside Fudis Dialog Component
*/
@Input() insideDialog: boolean = false;
@Input() insideDialog: boolean;

/**
* List of Alerts fetched from service
* List of Alerts fetched from Alert Service
*/
protected _alertList: Signal<FudisAlertElement[]>;
protected _alertList = new BehaviorSubject<FudisAlertElement[]>([]);

/**
* Label for section element containing alerts
*/
protected _alertGroupLabel: string;
protected _alertGroupLabel = new BehaviorSubject<string>('');

/**
* Boolean to determine if Alert group is visible. Used with _dialogStatus boolean.
* Boolean to determine if Alert group is visible
*/
protected _visible: boolean = false;
protected _visible = new BehaviorSubject<boolean>(false);

/**
* Boolean from service to determine if Fudis Dialog is open.
*/
private _dialogStatus: boolean;

ngAfterViewInit(): void {
this._setVisibility();
ngOnChanges(changes: FudisComponentChanges<AlertGroupComponent>): void {
if (changes.insideDialog?.currentValue !== changes.insideDialog?.previousValue) {
this._setVisibility(this._dialogService.getDialogOpenStatus().value);
}
}

/**
* Getter for visible status
* Get Alert Group's visible status
*/
public getVisibleStatus(): boolean {
return this._visible;
return this._visible.value;
}

/**
* Set visibility when Fudis Dialog is opened and closed.
* Set visibility when Fudis Dialog is opened and closed
*/
private _setVisibility(): void {
if ((this._dialogStatus && this.insideDialog) || (!this._dialogStatus && !this.insideDialog)) {
this._visible = true;
private _setVisibility(dialogStatus: boolean): void {
if ((dialogStatus && this.insideDialog) || (!dialogStatus && !this.insideDialog)) {
this._visible.next(true);
} else {
this._visible = false;
this._visible.next(false);
}
}
}
Loading
Loading