Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion modules/ui/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@
</ng-container>
<app-version
[consentShown]="vm.consentShown"
(consentShownEvent)="consentShown()"></app-version>
[hasRiskProfiles]="vm.hasRiskProfiles"
(consentShownEvent)="consentShown()"
(navigateToRiskAssessmentEvent)="
navigateToRiskAssessment()
"></app-version>
</div>
</mat-drawer>

Expand Down
2 changes: 2 additions & 0 deletions modules/ui/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -786,5 +786,7 @@ class FakeShutdownAppComponent {
})
class FakeVersionComponent {
@Input() consentShown!: boolean;
@Input() hasRiskProfiles!: boolean;
@Output() consentShownEvent = new EventEmitter<void>();
@Output() navigateToRiskAssessmentEvent = new EventEmitter<void>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,23 @@ <h2>Welcome to Testrun!</h2>
</ul>
</section>

<section class="consent-update" *ngIf="data.update_available === true">
<section
class="section-container"
*ngIf="data.version.update_available === true">
<app-callout [type]="CalloutType.Warning">
<span class="consent-update-title">Software is outdated!</span>
<p class="consent-update-content">
<span class="section-title">Software is outdated!</span>
<p class="section-content consent">
You are currently using an outdated software (<b>{{
data.installed_version
data.version.installed_version
}}</b
>).
<br />
The latest version number is <b>{{ data.latest_version }}</b
The latest version number is <b>{{ data.version.latest_version }}</b
>. Please consider to update or continue at your own risk.
</p>
<p class="download-link-container">
<p class="section-action-container">
<a
href="{{ data.latest_version_url }}"
href="{{ data.version.latest_version_url }}"
target="_blank"
class="download-link"
color="primary"
Expand All @@ -79,6 +81,27 @@ <h2>Welcome to Testrun!</h2>
</p>
</app-callout>
</section>
<section class="section-container" *ngIf="data.hasRiskProfiles === false">
<app-callout [type]="CalloutType.Check">
<span class="section-title">Risk Assessment feature added!</span>
<p class="section-content risk-assessment">
Now you can answer a short questionnaire, create a security profile and
attach it to the Testrun result to complete a device verification. Also,
it will speed up the process a lot!
</p>
<p class="section-action-container">
<button
(click)="confirm(optOut, true)"
class="risk-assessment-button"
color="primary"
mat-button
aria-label="Go to Risk Assessment page"
type="button">
Go to Risk Assessment
</button>
</p>
</app-callout>
</section>
<section>
<app-callout [type]="CalloutType.Info">
Testrun uses Google Analytics to learn about how our users use the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@
}
}

.consent-update {
.consent-update-title {
.section-container {
.section-title {
font-size: 18px;
}
.download-link-container {
.section-action-container {
text-align: end;
margin-bottom: 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ describe('ConsentDialogComponent', () => {
});
fixture = TestBed.createComponent(ConsentDialogComponent);
component = fixture.componentInstance;
component.data = NEW_VERSION;
component.data = { version: NEW_VERSION, hasRiskProfiles: false };
component.optOut = false;
fixture.detectChanges();
compiled = fixture.nativeElement as HTMLElement;
Expand All @@ -56,30 +56,32 @@ describe('ConsentDialogComponent', () => {
expect(component).toBeTruthy();
});

it('should close dialog with true when checkbox unchecked on "confirm" click', () => {
it('should close dialog with grant as true when checkbox unchecked on "confirm" click', () => {
const closeSpy = spyOn(component.dialogRef, 'close');
const confirmButton = compiled.querySelector(
'.confirm-button'
) as HTMLButtonElement;
const dialogRes = { grant: true, isNavigateToRiskAssessment: undefined };

confirmButton?.click();

expect(closeSpy).toHaveBeenCalledWith(true);
expect(closeSpy).toHaveBeenCalledWith(dialogRes);

closeSpy.calls.reset();
});

it('should close dialog with false when checkbox unchecked on "confirm" click', () => {
it('should close dialog with grant as false when checkbox unchecked on "confirm" click', () => {
component.optOut = true;
fixture.detectChanges();
const closeSpy = spyOn(component.dialogRef, 'close');
const confirmButton = compiled.querySelector(
'.confirm-button'
) as HTMLButtonElement;
const dialogRes = { grant: false, isNavigateToRiskAssessment: undefined };

confirmButton?.click();

expect(closeSpy).toHaveBeenCalledWith(false);
expect(closeSpy).toHaveBeenCalledWith(dialogRes);

closeSpy.calls.reset();
});
Expand All @@ -97,13 +99,13 @@ describe('ConsentDialogComponent', () => {

describe('with new version available', () => {
beforeEach(() => {
component.data = NEW_VERSION;
component.data = { version: NEW_VERSION, hasRiskProfiles: false };
fixture.detectChanges();
});

it('should has content', () => {
it('should has consent content', () => {
const content = compiled.querySelector(
'.consent-update-content'
'.section-content.consent'
) as HTMLElement;

const innerContent = content.innerHTML.trim();
Expand All @@ -120,13 +122,60 @@ describe('ConsentDialogComponent', () => {

describe('with no new version available', () => {
beforeEach(() => {
component.data = VERSION;
component.data = { version: VERSION, hasRiskProfiles: false };
fixture.detectChanges();
});

it('should has content', () => {
it('should not has consent content', () => {
const content = compiled.querySelector(
'.consent-update-content'
'.section-content.consent'
) as HTMLElement;

expect(content).toBeNull();
});
});

describe('with no risk assessment profiles', () => {
beforeEach(() => {
component.data = { version: VERSION, hasRiskProfiles: false };
fixture.detectChanges();
});

it('should has risk-assessment content', () => {
const content = compiled.querySelector(
'.section-content.risk-assessment'
) as HTMLElement;

const innerContent = content.innerHTML.trim();
expect(innerContent).toContain(
'Now you can answer a short questionnaire'
);
});

it('should close dialog with isNavigateToRiskAssessment as true when click "confirm"', () => {
const closeSpy = spyOn(component.dialogRef, 'close');
const riskAssessmentBtn = compiled.querySelector(
'.risk-assessment-button'
) as HTMLButtonElement;
const dialogRes = { grant: true, isNavigateToRiskAssessment: true };

riskAssessmentBtn?.click();

expect(closeSpy).toHaveBeenCalledWith(dialogRes);

closeSpy.calls.reset();
});
});

describe('with risk assessment profiles', () => {
beforeEach(() => {
component.data = { version: VERSION, hasRiskProfiles: true };
fixture.detectChanges();
});

it('should not has risk-assessment content', () => {
const content = compiled.querySelector(
'.section-content.risk-assessment'
) as HTMLElement;

expect(content).toBeNull();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@ import {
MatDialogModule,
MatDialogRef,
} from '@angular/material/dialog';
import { Version } from '../../../model/version';
import { ConsentDialogResult, Version } from '../../../model/version';
import { MatButtonModule } from '@angular/material/button';
import { CalloutComponent } from '../../callout/callout.component';
import { CalloutType } from '../../../model/callout-type';
import { NgIf } from '@angular/common';
import { MatCheckbox } from '@angular/material/checkbox';
import { FormsModule } from '@angular/forms';

type DialogData = Version;
type DialogData = {
version: Version;
hasRiskProfiles: boolean;
};

@Component({
selector: 'app-consent-dialog',
Expand All @@ -51,8 +54,12 @@ export class ConsentDialogComponent {
@Inject(MAT_DIALOG_DATA) public data: DialogData
) {}

confirm(optOut: boolean) {
confirm(optOut: boolean, isNavigateToRiskAssessment?: boolean) {
// dialog should be closed with opposite value to grant or deny access to GA
this.dialogRef.close(!optOut);
const dialogResult: ConsentDialogResult = {
grant: !optOut,
isNavigateToRiskAssessment,
};
this.dialogRef.close(dialogResult);
}
}
17 changes: 12 additions & 5 deletions modules/ui/src/app/components/version/version.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
TestRunService,
UNAVAILABLE_VERSION,
} from '../../services/test-run.service';
import { Version } from '../../model/version';
import { ConsentDialogResult, Version } from '../../model/version';
import { MatButtonModule } from '@angular/material/button';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { tap } from 'rxjs/internal/operators/tap';
Expand All @@ -48,7 +48,9 @@ declare const gtag: Function;
})
export class VersionComponent implements OnInit, OnDestroy {
@Input() consentShown!: boolean;
@Input() hasRiskProfiles!: boolean;
@Output() consentShownEvent = new EventEmitter<void>();
@Output() navigateToRiskAssessmentEvent = new EventEmitter<void>();
version$!: Observable<Version | null>;
private destroy$: Subject<boolean> = new Subject<boolean>();

Expand Down Expand Up @@ -84,9 +86,10 @@ export class VersionComponent implements OnInit, OnDestroy {
}

openConsentDialog(version: Version) {
const dialogData = { version, hasRiskProfiles: this.hasRiskProfiles };
const dialogRef = this.dialog.open(ConsentDialogComponent, {
ariaLabel: 'Welcome to Testrun modal window',
data: version,
data: dialogData,
autoFocus: true,
hasBackdrop: true,
disableClose: true,
Expand All @@ -96,13 +99,17 @@ export class VersionComponent implements OnInit, OnDestroy {
dialogRef
?.afterClosed()
.pipe(takeUntil(this.destroy$))
.subscribe((grant: boolean) => {
if (grant === null) {
.subscribe((dialogResult: ConsentDialogResult) => {
if (dialogResult.grant === null) {
return;
}
gtag('consent', 'update', {
analytics_storage: grant ? 'granted' : 'denied',
analytics_storage: dialogResult.grant ? 'granted' : 'denied',
});

if (dialogResult.isNavigateToRiskAssessment) {
this.navigateToRiskAssessmentEvent.emit();
}
});
}

Expand Down
5 changes: 5 additions & 0 deletions modules/ui/src/app/model/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,8 @@ export interface Version {
latest_version: string;
latest_version_url: string;
}

export interface ConsentDialogResult {
grant: boolean;
isNavigateToRiskAssessment?: boolean;
}