From 26d755061b4e8b39895cef3736ce41082b7c22c5 Mon Sep 17 00:00:00 2001 From: kurilova Date: Mon, 29 Jun 2026 09:10:40 +0000 Subject: [PATCH 1/5] [TR] The text and background color for updating devices and risk profiles are not by design --- modules/ui/src/app/app.component.html | 3 ++- modules/ui/src/app/app.component.ts | 4 +++ .../consent-dialog.component.html | 25 ++++++++++++++++++- .../consent-dialog.component.ts | 5 +++- .../components/version/version.component.ts | 7 +++++- modules/ui/src/app/model/version.ts | 3 +++ 6 files changed, 43 insertions(+), 4 deletions(-) diff --git a/modules/ui/src/app/app.component.html b/modules/ui/src/app/app.component.html index 362a1d50f..d962cc67c 100644 --- a/modules/ui/src/app/app.component.html +++ b/modules/ui/src/app/app.component.html @@ -72,7 +72,8 @@ + (consentShownEvent)="consentShown()" + (navigateToRouteEvent)="navigateToRoute($event)"> diff --git a/modules/ui/src/app/app.component.ts b/modules/ui/src/app/app.component.ts index 7116aaa51..71278c911 100644 --- a/modules/ui/src/app/app.component.ts +++ b/modules/ui/src/app/app.component.ts @@ -324,6 +324,10 @@ export class AppComponent implements AfterViewInit { } } + navigateToRoute(route: Routes): void { + this.route.navigate([route]); + } + private subscribeToNavigation() { this.route.events .pipe( diff --git a/modules/ui/src/app/components/version/consent-dialog/consent-dialog.component.html b/modules/ui/src/app/components/version/consent-dialog/consent-dialog.component.html index becde20cf..0125c1c0c 100644 --- a/modules/ui/src/app/components/version/consent-dialog/consent-dialog.component.html +++ b/modules/ui/src/app/components/version/consent-dialog/consent-dialog.component.html @@ -50,7 +50,6 @@

Welcome to Testrun!

> to share you thoughts -
  • Risk Profile was lastly updated in 2026 V2.4.0
  • @@ -82,6 +81,30 @@

    Welcome to Testrun!

    } +
    + + Risk assessment questionnaire was lastly updated in version 2.4.0. Visit + the + + Devices + + and + + Risk Profiles + + pages to update. + +
    Testrun uses Google Analytics to learn about how our users use the diff --git a/modules/ui/src/app/components/version/consent-dialog/consent-dialog.component.ts b/modules/ui/src/app/components/version/consent-dialog/consent-dialog.component.ts index ef6aff1d4..05a8a865b 100644 --- a/modules/ui/src/app/components/version/consent-dialog/consent-dialog.component.ts +++ b/modules/ui/src/app/components/version/consent-dialog/consent-dialog.component.ts @@ -27,6 +27,7 @@ import { CalloutType } from '../../../model/callout-type'; import { MatCheckbox } from '@angular/material/checkbox'; import { FormsModule } from '@angular/forms'; import { timer } from 'rxjs'; +import { Routes } from '../../../model/routes'; type DialogData = { version: Version; @@ -51,11 +52,13 @@ export class ConsentDialogComponent { public readonly CalloutType = CalloutType; optOut = this.data.optOut; + public readonly Routes = Routes; - confirm(optOut: boolean) { + confirm(optOut: boolean, route?: Routes) { // dialog should be closed with opposite value to grant or deny access to GA const dialogResult: ConsentDialogResult = { grant: !optOut, + route, }; this.dialogRef.close(dialogResult); timer(100).subscribe(() => { diff --git a/modules/ui/src/app/components/version/version.component.ts b/modules/ui/src/app/components/version/version.component.ts index 2d80a46c0..b99d1b8e4 100644 --- a/modules/ui/src/app/components/version/version.component.ts +++ b/modules/ui/src/app/components/version/version.component.ts @@ -38,6 +38,7 @@ import { takeUntil } from 'rxjs/internal/operators/takeUntil'; import { filter, timer } from 'rxjs'; import { ConsentDialogComponent } from './consent-dialog/consent-dialog.component'; import { LocalStorageService } from '../../services/local-storage.service'; +import { Routes } from '../../model/routes'; export const INSTALLED_VERSION = 'INSTALLED_VERSION'; @@ -56,6 +57,7 @@ export class VersionComponent implements OnInit, OnDestroy { @Input() consentShown!: boolean; @Output() consentShownEvent = new EventEmitter(); + @Output() navigateToRouteEvent = new EventEmitter(); version$!: Observable; private destroy$: Subject = new Subject(); @@ -122,7 +124,10 @@ export class VersionComponent implements OnInit, OnDestroy { gtag('consent', 'update', { analytics_storage: dialogResult.grant ? 'granted' : 'denied', }); - this.localStorageService.setGAConsent(dialogResult.grant); + + if (dialogResult.route) { + this.navigateToRouteEvent.emit(); + } }); } diff --git a/modules/ui/src/app/model/version.ts b/modules/ui/src/app/model/version.ts index 5eb946e42..31fd9ded8 100644 --- a/modules/ui/src/app/model/version.ts +++ b/modules/ui/src/app/model/version.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Routes } from './routes'; + export interface Version { installed_version: string; update_available: boolean; @@ -23,4 +25,5 @@ export interface Version { export interface ConsentDialogResult { grant: boolean; + route?: Routes; } From 8954b32017628b0ce034e50c8c1c6869ff8e3519 Mon Sep 17 00:00:00 2001 From: kurilova Date: Mon, 29 Jun 2026 09:14:49 +0000 Subject: [PATCH 2/5] Fix emit value --- modules/ui/src/app/components/version/version.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui/src/app/components/version/version.component.ts b/modules/ui/src/app/components/version/version.component.ts index b99d1b8e4..c999eb9fa 100644 --- a/modules/ui/src/app/components/version/version.component.ts +++ b/modules/ui/src/app/components/version/version.component.ts @@ -126,7 +126,7 @@ export class VersionComponent implements OnInit, OnDestroy { }); if (dialogResult.route) { - this.navigateToRouteEvent.emit(); + this.navigateToRouteEvent.emit(dialogResult.route); } }); } From 2487403017f2acd011ebfecf801edf663c4f355c Mon Sep 17 00:00:00 2001 From: kurilova Date: Mon, 29 Jun 2026 11:46:21 +0000 Subject: [PATCH 3/5] Fix tests --- .../consent-dialog.component.html | 2 + .../consent-dialog.component.spec.ts | 37 ++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/modules/ui/src/app/components/version/consent-dialog/consent-dialog.component.html b/modules/ui/src/app/components/version/consent-dialog/consent-dialog.component.html index 0125c1c0c..0a6c606a4 100644 --- a/modules/ui/src/app/components/version/consent-dialog/consent-dialog.component.html +++ b/modules/ui/src/app/components/version/consent-dialog/consent-dialog.component.html @@ -86,6 +86,7 @@

    Welcome to Testrun!

    Risk assessment questionnaire was lastly updated in version 2.4.0. Visit the Welcome to Testrun! and { let component: ConsentDialogComponent; @@ -72,7 +73,7 @@ describe('ConsentDialogComponent', () => { const confirmButton = compiled.querySelector( '.confirm-button' ) as HTMLButtonElement; - const dialogRes = { grant: true }; + const dialogRes = { grant: true, route: undefined }; confirmButton?.click(); @@ -88,7 +89,7 @@ describe('ConsentDialogComponent', () => { const confirmButton = compiled.querySelector( '.confirm-button' ) as HTMLButtonElement; - const dialogRes = { grant: false }; + const dialogRes = { grant: false, route: undefined }; confirmButton?.click(); @@ -97,6 +98,38 @@ describe('ConsentDialogComponent', () => { closeSpy.calls.reset(); }); + it('should close dialog with devices route on device link click', () => { + component.optOut = true; + fixture.detectChanges(); + const closeSpy = spyOn(component.dialogRef, 'close'); + const devicesLink = compiled.querySelector( + '#devices-link' + ) as HTMLButtonElement; + const dialogRes = { grant: false, route: Routes.Devices }; + + devicesLink?.click(); + + expect(closeSpy).toHaveBeenCalledWith(dialogRes); + + closeSpy.calls.reset(); + }); + + it('should close dialog with risk profiles route on risk profiles link click', () => { + component.optOut = true; + fixture.detectChanges(); + const closeSpy = spyOn(component.dialogRef, 'close'); + const devicesLink = compiled.querySelector( + '#risk-profiles-link' + ) as HTMLButtonElement; + const dialogRes = { grant: false, route: Routes.RiskAssessment }; + + devicesLink?.click(); + + expect(closeSpy).toHaveBeenCalledWith(dialogRes); + + closeSpy.calls.reset(); + }); + it('should not close dialog on download link click', () => { const closeSpy = spyOn(component.dialogRef, 'close'); const confirmButton = compiled.querySelector( From 7f5a3e54214241ce39194da29f969ff27b61d557 Mon Sep 17 00:00:00 2001 From: kurilova Date: Mon, 29 Jun 2026 12:07:15 +0000 Subject: [PATCH 4/5] Fix tests coverage --- .../version/version.component.spec.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/modules/ui/src/app/components/version/version.component.spec.ts b/modules/ui/src/app/components/version/version.component.spec.ts index 381b6dbba..9a3cdefb4 100644 --- a/modules/ui/src/app/components/version/version.component.spec.ts +++ b/modules/ui/src/app/components/version/version.component.spec.ts @@ -33,6 +33,7 @@ import { of } from 'rxjs'; import { MatDialogRef } from '@angular/material/dialog'; import { ConsentDialogComponent } from './consent-dialog/consent-dialog.component'; import { MatIconTestingModule } from '@angular/material/icon/testing'; +import { Routes } from '../../model/routes'; describe('VersionComponent', () => { let component: VersionComponent; @@ -43,6 +44,8 @@ describe('VersionComponent', () => { const versionBehaviorSubject$ = new BehaviorSubject(null); beforeEach(() => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (window).gtag = jasmine.createSpy('gtag'); // @ts-expect-error data layer should be defined window.dataLayer = window.dataLayer || []; mockService = jasmine.createSpyObj(['getVersion', 'fetchVersion']); @@ -103,6 +106,25 @@ describe('VersionComponent', () => { expect(openSpy).toHaveBeenCalled(); }); + it('should emit navigateToRouteEvent when dialogResult contains a route', () => { + const navigateToRouteEventSpy = spyOn( + component.navigateToRouteEvent, + 'emit' + ); + const mockDialogResult = { + grant: true, + route: Routes.Devices, + }; + spyOn(component.dialog, 'open').and.returnValue({ + afterClosed: () => of(mockDialogResult), + } as MatDialogRef); + + component.openConsentDialog(VERSION); + + expect(navigateToRouteEventSpy).toHaveBeenCalledTimes(1); + expect(navigateToRouteEventSpy).toHaveBeenCalledWith(Routes.Devices); + }); + describe('update is not available', () => { beforeEach(() => { versionBehaviorSubject$.next(VERSION); From 198aa2530f043fdf4a1903b50f7888e4b8ed58f1 Mon Sep 17 00:00:00 2001 From: kurilova Date: Mon, 29 Jun 2026 12:23:30 +0000 Subject: [PATCH 5/5] Update verson --- make/DEBIAN/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/DEBIAN/control b/make/DEBIAN/control index ddd07d4da..439f0c1bc 100644 --- a/make/DEBIAN/control +++ b/make/DEBIAN/control @@ -1,5 +1,5 @@ Package: Testrun -Version: 2.4.0-beta.3 +Version: 2.4.0-beta.5 Architecture: amd64 Maintainer: Google Homepage: https://github.com/google/testrun