From b04046853bd0ff201fbf79cdac89265bed95e5f1 Mon Sep 17 00:00:00 2001 From: Volha Mardvilka Date: Mon, 3 Jun 2024 07:00:08 +0000 Subject: [PATCH 1/2] 342365574: (feat) display info about Risk Assessment during testing --- modules/ui/src/app/app.component.html | 22 ++++++ modules/ui/src/app/app.component.spec.ts | 37 ++++++++++ modules/ui/src/app/app.component.ts | 5 ++ modules/ui/src/app/app.store.spec.ts | 31 +++++++- modules/ui/src/app/app.store.ts | 17 +++++ .../components/callout/callout.component.scss | 12 +++- modules/ui/src/app/model/callout-type.ts | 1 + .../risk-assessment.component.spec.ts | 16 +++++ .../risk-assessment.component.ts | 4 +- .../risk-assessment.store.spec.ts | 71 +++++++------------ .../risk-assessment/risk-assessment.store.ts | 28 +++----- modules/ui/src/app/store/actions.ts | 11 +++ modules/ui/src/app/store/effects.spec.ts | 13 ++++ modules/ui/src/app/store/effects.ts | 11 +++ modules/ui/src/app/store/reducers.spec.ts | 28 ++++++++ modules/ui/src/app/store/reducers.ts | 12 ++++ modules/ui/src/app/store/selectors.spec.ts | 14 ++++ modules/ui/src/app/store/selectors.ts | 10 +++ modules/ui/src/app/store/state.ts | 6 ++ modules/ui/src/styles.scss | 29 ++++++++ 20 files changed, 309 insertions(+), 69 deletions(-) diff --git a/modules/ui/src/app/app.component.html b/modules/ui/src/app/app.component.html index 6a853db98..425aeb683 100644 --- a/modules/ui/src/app/app.component.html +++ b/modules/ui/src/app/app.component.html @@ -189,6 +189,28 @@

Testrun

>start testing. + + Congratulations, the device is under test now! Do not forget to fill + Risk Assessment questionnaire. It is required to complete verification process. + diff --git a/modules/ui/src/app/app.component.spec.ts b/modules/ui/src/app/app.component.spec.ts index df773ccff..dc156549b 100644 --- a/modules/ui/src/app/app.component.spec.ts +++ b/modules/ui/src/app/app.component.spec.ts @@ -54,6 +54,7 @@ import { selectError, selectHasConnectionSettings, selectHasDevices, + selectHasRiskProfiles, selectInterfaces, selectIsOpenStartTestrun, selectIsOpenWaitSnackBar, @@ -104,6 +105,7 @@ describe('AppComponent', () => { 'fetchDevices', 'getTestModules', 'testrunInProgress', + 'fetchProfiles', 'fetchCertificates', ]); @@ -148,6 +150,7 @@ describe('AppComponent', () => { { selector: selectError, value: null }, { selector: selectMenuOpened, value: false }, { selector: selectHasDevices, value: false }, + { selector: selectHasRiskProfiles, value: false }, { selector: selectStatus, value: null }, { selector: selectSystemStatus, value: null }, { selector: selectIsOpenStartTestrun, value: false }, @@ -466,6 +469,40 @@ describe('AppComponent', () => { }); }); + describe('with systemStatus data IN Progress and without riskProfiles', () => { + beforeEach(() => { + mockService.testrunInProgress.and.returnValue(true); + store.overrideSelector(selectHasConnectionSettings, true); + store.overrideSelector(selectHasDevices, true); + store.overrideSelector(selectHasRiskProfiles, false); + store.overrideSelector( + selectSystemStatus, + MOCK_PROGRESS_DATA_IN_PROGRESS + ); + + fixture.detectChanges(); + }); + + it('should have callout component with "Congratulations" text', () => { + const callout = compiled.querySelector('app-callout'); + const calloutContent = callout?.innerHTML.trim(); + + expect(callout).toBeTruthy(); + expect(calloutContent).toContain('Congratulations'); + }); + + it('should have callout component with "Risk Assessment" link', () => { + const callout = compiled.querySelector('app-callout'); + const calloutLinkEl = compiled.querySelector( + '.message-link' + ) as HTMLAnchorElement; + const calloutLinkContent = calloutLinkEl.innerHTML.trim(); + + expect(callout).toBeTruthy(); + expect(calloutLinkContent).toContain('Risk Assessment'); + }); + }); + describe('with no devices setted', () => { beforeEach(() => { store.overrideSelector(selectHasDevices, false); diff --git a/modules/ui/src/app/app.component.ts b/modules/ui/src/app/app.component.ts index 97e017daf..877050393 100644 --- a/modules/ui/src/app/app.component.ts +++ b/modules/ui/src/app/app.component.ts @@ -74,6 +74,7 @@ export class AppComponent { public appStore: AppStore ) { this.appStore.getDevices(); + this.appStore.getRiskProfiles(); this.appStore.getSystemStatus(); this.matIconRegistry.addSvgIcon( 'devices', @@ -115,6 +116,10 @@ export class AppComponent { this.appStore.setIsOpenStartTestrun(); } + navigateToRiskAssessment(): void { + this.route.navigate([Routes.RiskAssessment]); + } + async closeCertificates(): Promise { await this.certDrawer.close(); } diff --git a/modules/ui/src/app/app.store.spec.ts b/modules/ui/src/app/app.store.spec.ts index 6f1a2dba3..2807bcc51 100644 --- a/modules/ui/src/app/app.store.spec.ts +++ b/modules/ui/src/app/app.store.spec.ts @@ -22,6 +22,7 @@ import { selectError, selectHasConnectionSettings, selectHasDevices, + selectHasRiskProfiles, selectInterfaces, selectIsOpenWaitSnackBar, selectMenuOpened, @@ -30,8 +31,13 @@ import { import { TestRunService } from './services/test-run.service'; import SpyObj = jasmine.SpyObj; import { device } from './mocks/device.mock'; -import { fetchSystemStatus, setDevices } from './store/actions'; +import { + fetchSystemStatus, + setDevices, + setRiskProfiles, +} from './store/actions'; import { MOCK_PROGRESS_DATA_IN_PROGRESS } from './mocks/testrun.mock'; +import { PROFILE_MOCK } from './mocks/profile.mock'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { NotificationService } from './services/notification.service'; @@ -60,7 +66,10 @@ describe('AppStore', () => { let mockNotificationService: SpyObj; beforeEach(() => { - mockService = jasmine.createSpyObj('mockService', ['fetchDevices']); + mockService = jasmine.createSpyObj('mockService', [ + 'fetchDevices', + 'fetchProfiles', + ]); mockNotificationService = jasmine.createSpyObj('mockNotificationService', [ 'notify', ]); @@ -84,6 +93,7 @@ describe('AppStore', () => { appStore = TestBed.inject(AppStore); store.overrideSelector(selectHasDevices, true); + store.overrideSelector(selectHasRiskProfiles, false); store.overrideSelector(selectHasConnectionSettings, true); store.overrideSelector(selectMenuOpened, true); store.overrideSelector(selectInterfaces, {}); @@ -127,6 +137,7 @@ describe('AppStore', () => { expect(store).toEqual({ consentShown: false, hasDevices: true, + hasRiskProfiles: false, isStatusLoaded: false, systemStatus: null, hasConnectionSettings: true, @@ -171,6 +182,22 @@ describe('AppStore', () => { }); }); + describe('fetchProfiles', () => { + const riskProfiles = [PROFILE_MOCK]; + + beforeEach(() => { + mockService.fetchProfiles.and.returnValue(of(riskProfiles)); + }); + + it('should dispatch action setRiskProfiles', () => { + appStore.getRiskProfiles(); + + expect(store.dispatch).toHaveBeenCalledWith( + setRiskProfiles({ riskProfiles }) + ); + }); + }); + describe('getSystemStatus', () => { it('should dispatch fetchSystemStatus', () => { appStore.getSystemStatus(); diff --git a/modules/ui/src/app/app.store.ts b/modules/ui/src/app/app.store.ts index 66d4086b3..cf67ffcf1 100644 --- a/modules/ui/src/app/app.store.ts +++ b/modules/ui/src/app/app.store.ts @@ -21,6 +21,7 @@ import { selectError, selectHasConnectionSettings, selectHasDevices, + selectHasRiskProfiles, selectInterfaces, selectMenuOpened, selectStatus, @@ -34,8 +35,10 @@ import { setDevices, setIsOpenStartTestrun, fetchSystemStatus, + setRiskProfiles, } from './store/actions'; import { TestrunStatus } from './model/testrun-status'; +import { Profile } from './model/profile'; import { SettingMissedError, SystemInterfaces } from './model/setting'; export const CONSENT_SHOWN_KEY = 'CONSENT_SHOWN'; @@ -49,6 +52,7 @@ export class AppStore extends ComponentStore { private consentShown$ = this.select(state => state.consentShown); private isStatusLoaded$ = this.select(state => state.isStatusLoaded); private hasDevices$ = this.store.select(selectHasDevices); + private hasRiskProfiles$ = this.store.select(selectHasRiskProfiles); private hasConnectionSetting$ = this.store.select( selectHasConnectionSettings ); @@ -62,6 +66,7 @@ export class AppStore extends ComponentStore { viewModel$ = this.select({ consentShown: this.consentShown$, hasDevices: this.hasDevices$, + hasRiskProfiles: this.hasRiskProfiles$, isStatusLoaded: this.isStatusLoaded$, systemStatus: this.systemStatus$, hasConnectionSettings: this.hasConnectionSetting$, @@ -101,6 +106,18 @@ export class AppStore extends ComponentStore { ); }); + getRiskProfiles = this.effect(trigger$ => { + return trigger$.pipe( + exhaustMap(() => { + return this.testRunService.fetchProfiles().pipe( + tap((riskProfiles: Profile[]) => { + this.store.dispatch(setRiskProfiles({ riskProfiles })); + }) + ); + }) + ); + }); + statusLoaded = this.effect(() => { return this.systemStatus$.pipe( skip(1), diff --git a/modules/ui/src/app/components/callout/callout.component.scss b/modules/ui/src/app/components/callout/callout.component.scss index 262552c91..20f30e28f 100644 --- a/modules/ui/src/app/components/callout/callout.component.scss +++ b/modules/ui/src/app/components/callout/callout.component.scss @@ -22,7 +22,8 @@ } :host:has(.callout-container.info), -:host:has(.callout-container.error) { +:host:has(.callout-container.error), +:host:has(.callout-container.check_circle) { position: absolute; } @@ -72,6 +73,15 @@ } } +.callout-container.check_circle { + margin: 24px 32px; + background-color: $green-50; + + .callout-icon { + color: $green-800; + } +} + .callout-container.error_outline { display: flex; align-items: flex-start; diff --git a/modules/ui/src/app/model/callout-type.ts b/modules/ui/src/app/model/callout-type.ts index b8fabd0bc..c784b46f6 100644 --- a/modules/ui/src/app/model/callout-type.ts +++ b/modules/ui/src/app/model/callout-type.ts @@ -15,6 +15,7 @@ */ export enum CalloutType { Info = 'info', + Check = 'check_circle', Warning = 'warning_amber', Error = 'error', ErrorOutline = 'error_outline', diff --git a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts index 2667388bc..db45e728f 100644 --- a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts +++ b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts @@ -33,12 +33,14 @@ import { Profile } from '../../model/profile'; import { MatDialogRef } from '@angular/material/dialog'; import { DeleteFormComponent } from '../../components/delete-form/delete-form.component'; import { FocusManagerService } from '../../services/focus-manager.service'; +import { RiskAssessmentStore } from './risk-assessment.store'; describe('RiskAssessmentComponent', () => { let component: RiskAssessmentComponent; let fixture: ComponentFixture; let mockService: SpyObj; let mockFocusManagerService: SpyObj; + let mockRiskAssessmentStore: SpyObj; let compiled: HTMLElement; beforeEach(async () => { @@ -49,15 +51,25 @@ describe('RiskAssessmentComponent', () => { 'focusFirstElementInContainer', ]); + mockRiskAssessmentStore = jasmine.createSpyObj('RiskAssessmentStore', [ + 'deleteProfile', + 'setFocus', + ]); + await TestBed.configureTestingModule({ declarations: [RiskAssessmentComponent, FakeProfileItemComponent], imports: [MatToolbarModule, MatSidenavModule, BrowserAnimationsModule], providers: [ { provide: TestRunService, useValue: mockService }, { provide: FocusManagerService, useValue: mockFocusManagerService }, + { provide: RiskAssessmentStore, useValue: mockRiskAssessmentStore }, ], }).compileComponents(); + TestBed.overrideProvider(RiskAssessmentStore, { + useValue: mockRiskAssessmentStore, + }); + fixture = TestBed.createComponent(RiskAssessmentComponent); component = fixture.componentInstance; compiled = fixture.nativeElement as HTMLElement; @@ -69,6 +81,10 @@ describe('RiskAssessmentComponent', () => { describe('with no data', () => { beforeEach(() => { + component.viewModel$ = of({ + profiles: [] as Profile[], + }); + mockRiskAssessmentStore.profiles$ = of([]); fixture.detectChanges(); }); diff --git a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts index 6e9bfa54c..ddd9d8b3e 100644 --- a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts +++ b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts @@ -32,9 +32,7 @@ export class RiskAssessmentComponent implements OnDestroy { constructor( private store: RiskAssessmentStore, public dialog: MatDialog - ) { - this.store.getProfiles(); - } + ) {} ngOnDestroy() { this.destroy$.next(true); diff --git a/modules/ui/src/app/pages/risk-assessment/risk-assessment.store.spec.ts b/modules/ui/src/app/pages/risk-assessment/risk-assessment.store.spec.ts index 7b45ca9a1..a9add3bc4 100644 --- a/modules/ui/src/app/pages/risk-assessment/risk-assessment.store.spec.ts +++ b/modules/ui/src/app/pages/risk-assessment/risk-assessment.store.spec.ts @@ -14,17 +14,21 @@ * limitations under the License. */ import { TestBed } from '@angular/core/testing'; -import { of, skip, take } from 'rxjs'; -import { provideMockStore } from '@ngrx/store/testing'; +import { of, take } from 'rxjs'; +import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { TestRunService } from '../../services/test-run.service'; import SpyObj = jasmine.SpyObj; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { RiskAssessmentStore } from './risk-assessment.store'; import { PROFILE_MOCK, PROFILE_MOCK_2 } from '../../mocks/profile.mock'; import { FocusManagerService } from '../../services/focus-manager.service'; +import { AppState } from '../../store/state'; +import { selectRiskProfiles } from '../../store/selectors'; +import { setRiskProfiles } from '../../store/actions'; describe('RiskAssessmentStore', () => { let riskAssessmentStore: RiskAssessmentStore; + let store: MockStore; let mockService: SpyObj; let mockFocusManagerService: SpyObj; @@ -38,35 +42,34 @@ describe('RiskAssessmentStore', () => { imports: [NoopAnimationsModule], providers: [ RiskAssessmentStore, - provideMockStore({}), + provideMockStore({ + selectors: [ + { + selector: selectRiskProfiles, + value: [PROFILE_MOCK, PROFILE_MOCK_2], + }, + ], + }), { provide: TestRunService, useValue: mockService }, { provide: FocusManagerService, useValue: mockFocusManagerService }, ], }); + store = TestBed.inject(MockStore); riskAssessmentStore = TestBed.inject(RiskAssessmentStore); + + spyOn(store, 'dispatch').and.callFake(() => {}); }); it('should be created', () => { expect(riskAssessmentStore).toBeTruthy(); }); - describe('updaters', () => { - it('should update profiles', (done: DoneFn) => { - riskAssessmentStore.viewModel$.pipe(skip(1), take(1)).subscribe(store => { - expect(store.profiles).toEqual([PROFILE_MOCK]); - done(); - }); - - riskAssessmentStore.updateProfiles([PROFILE_MOCK]); - }); - }); - describe('selectors', () => { it('should select state', done => { riskAssessmentStore.viewModel$.pipe(take(1)).subscribe(store => { expect(store).toEqual({ - profiles: [], + profiles: [PROFILE_MOCK, PROFILE_MOCK_2], }); done(); }); @@ -74,37 +77,15 @@ describe('RiskAssessmentStore', () => { }); describe('effects', () => { - describe('getProfiles', () => { - beforeEach(() => { - mockService.fetchProfiles.and.returnValue(of([PROFILE_MOCK])); - }); - - it('should update profiles', done => { - riskAssessmentStore.viewModel$ - .pipe(skip(1), take(1)) - .subscribe(store => { - expect(store.profiles).toEqual([PROFILE_MOCK]); - done(); - }); - - riskAssessmentStore.getProfiles(); - }); - }); - describe('deleteProfile', () => { - it('should update store profiles', done => { + it('should dispatch setRiskProfiles', () => { mockService.deleteProfile.and.returnValue(of(true)); - riskAssessmentStore.updateProfiles([PROFILE_MOCK, PROFILE_MOCK_2]); - - riskAssessmentStore.viewModel$ - .pipe(skip(1), take(1)) - .subscribe(store => { - expect(store.profiles).toEqual([PROFILE_MOCK_2]); - done(); - }); - riskAssessmentStore.deleteProfile(PROFILE_MOCK.name); + + expect(store.dispatch).toHaveBeenCalledWith( + setRiskProfiles({ riskProfiles: [PROFILE_MOCK_2] }) + ); }); }); @@ -118,7 +99,6 @@ describe('RiskAssessmentStore', () => { nextItem: mockNextItem, firstItem: mockFirstItem, }; - riskAssessmentStore.updateProfiles([PROFILE_MOCK, PROFILE_MOCK_2]); riskAssessmentStore.setFocus(mockData); @@ -132,7 +112,6 @@ describe('RiskAssessmentStore', () => { nextItem: mockNullEL, firstItem: mockFirstItem, }; - riskAssessmentStore.updateProfiles([PROFILE_MOCK, PROFILE_MOCK_2]); riskAssessmentStore.setFocus(mockData); @@ -146,7 +125,9 @@ describe('RiskAssessmentStore', () => { nextItem: mockNullEL, firstItem: mockFirstItem, }; - riskAssessmentStore.updateProfiles([PROFILE_MOCK]); + + store.overrideSelector(selectRiskProfiles, [PROFILE_MOCK]); + store.refreshState(); riskAssessmentStore.setFocus(mockData); diff --git a/modules/ui/src/app/pages/risk-assessment/risk-assessment.store.ts b/modules/ui/src/app/pages/risk-assessment/risk-assessment.store.ts index 6b0a348c8..737d8f024 100644 --- a/modules/ui/src/app/pages/risk-assessment/risk-assessment.store.ts +++ b/modules/ui/src/app/pages/risk-assessment/risk-assessment.store.ts @@ -21,35 +21,22 @@ import { exhaustMap } from 'rxjs'; import { TestRunService } from '../../services/test-run.service'; import { Profile } from '../../model/profile'; import { FocusManagerService } from '../../services/focus-manager.service'; +import { Store } from '@ngrx/store'; +import { AppState } from '../../store/state'; +import { selectRiskProfiles } from '../../store/selectors'; +import { setRiskProfiles } from '../../store/actions'; export interface AppComponentState { profiles: Profile[]; } @Injectable() export class RiskAssessmentStore extends ComponentStore { - private profiles$ = this.select(state => state.profiles); + profiles$ = this.store.select(selectRiskProfiles); viewModel$ = this.select({ profiles: this.profiles$, }); - updateProfiles = this.updater((state, profiles: Profile[]) => ({ - ...state, - profiles, - })); - - getProfiles = this.effect(trigger$ => { - return trigger$.pipe( - exhaustMap(() => { - return this.testRunService.fetchProfiles().pipe( - tap((profiles: Profile[]) => { - this.updateProfiles(profiles); - }) - ); - }) - ); - }); - deleteProfile = this.effect(trigger$ => { return trigger$.pipe( exhaustMap((name: string) => { @@ -87,8 +74,13 @@ export class RiskAssessmentStore extends ComponentStore { this.updateProfiles(profiles); } + private updateProfiles(riskProfiles: Profile[]): void { + this.store.dispatch(setRiskProfiles({ riskProfiles })); + } + constructor( private testRunService: TestRunService, + private store: Store, private focusManagerService: FocusManagerService ) { super({ diff --git a/modules/ui/src/app/store/actions.ts b/modules/ui/src/app/store/actions.ts index 0024ccd9e..f5c0c937e 100644 --- a/modules/ui/src/app/store/actions.ts +++ b/modules/ui/src/app/store/actions.ts @@ -23,6 +23,7 @@ import { import { SystemInterfaces } from '../model/setting'; import { Device } from '../model/device'; import { TestrunStatus } from '../model/testrun-status'; +import { Profile } from '../model/profile'; // App component export const toggleMenu = createAction('[App Component] Toggle Menu'); @@ -83,6 +84,16 @@ export const setDevices = createAction( props<{ devices: Device[] }>() ); +export const setHasRiskProfiles = createAction( + '[Shared] Set Has Risk Profiles', + props<{ hasRiskProfiles: boolean }>() +); + +export const setRiskProfiles = createAction( + '[Shared] Set Risk Profiles', + props<{ riskProfiles: Profile[] }>() +); + export const setTestrunStatus = createAction( '[Shared] Set Testrun Status', props<{ systemStatus: TestrunStatus }>() diff --git a/modules/ui/src/app/store/effects.spec.ts b/modules/ui/src/app/store/effects.spec.ts index dc8ab8620..92cddf9fb 100644 --- a/modules/ui/src/app/store/effects.spec.ts +++ b/modules/ui/src/app/store/effects.spec.ts @@ -40,6 +40,8 @@ import { } from '../mocks/testrun.mock'; import { fetchSystemStatus, setStatus, setTestrunStatus } from './actions'; import { NotificationService } from '../services/notification.service'; +import { PROFILE_MOCK } from '../mocks/profile.mock'; + describe('Effects', () => { let actions$ = new Observable(); let effects: AppEffects; @@ -110,6 +112,17 @@ describe('Effects', () => { }); }); + it('onSetRiskProfiles$ should call setHasRiskProfiles', done => { + actions$ = of(actions.setRiskProfiles({ riskProfiles: [PROFILE_MOCK] })); + + effects.onSetRiskProfiles$.subscribe(action => { + expect(action).toEqual( + actions.setHasRiskProfiles({ hasRiskProfiles: true }) + ); + done(); + }); + }); + it('onMenuOpened$ should call updateFocusNavigation', done => { actions$ = of(actions.toggleMenu()); store.overrideSelector(selectMenuOpened, true); diff --git a/modules/ui/src/app/store/effects.ts b/modules/ui/src/app/store/effects.ts index e98f96686..ee082a178 100644 --- a/modules/ui/src/app/store/effects.ts +++ b/modules/ui/src/app/store/effects.ts @@ -114,6 +114,17 @@ export class AppEffects { ); }); + onSetRiskProfiles$ = createEffect(() => { + return this.actions$.pipe( + ofType(AppActions.setRiskProfiles), + map(({ riskProfiles }) => + AppActions.setHasRiskProfiles({ + hasRiskProfiles: riskProfiles.length > 0, + }) + ) + ); + }); + onSetTestrunStatus$ = createEffect(() => { return this.actions$.pipe( ofType(AppActions.setTestrunStatus), diff --git a/modules/ui/src/app/store/reducers.spec.ts b/modules/ui/src/app/store/reducers.spec.ts index 7adb63c61..ad611e9f9 100644 --- a/modules/ui/src/app/store/reducers.spec.ts +++ b/modules/ui/src/app/store/reducers.spec.ts @@ -21,9 +21,11 @@ import { setDevices, setHasConnectionSettings, setHasDevices, + setHasRiskProfiles, setIsOpenAddDevice, setIsOpenStartTestrun, setIsOpenWaitSnackBar, + setRiskProfiles, setStatus, setTestrunStatus, toggleMenu, @@ -32,6 +34,7 @@ import { } from './actions'; import { device } from '../mocks/device.mock'; import { MOCK_PROGRESS_DATA_CANCELLING } from '../mocks/testrun.mock'; +import { PROFILE_MOCK } from '../mocks/profile.mock'; describe('Reducer', () => { describe('unknown action', () => { @@ -169,6 +172,31 @@ describe('Reducer', () => { }); }); + describe('setHasRiskProfiles action', () => { + it('should update state', () => { + const initialState = initialSharedState; + const action = setHasRiskProfiles({ hasRiskProfiles: true }); + const state = fromReducer.sharedReducer(initialState, action); + const newState = { ...initialState, ...{ hasRiskProfiles: true } }; + + expect(state).toEqual(newState); + expect(state).not.toBe(initialState); + }); + }); + + describe('setRiskProfiles action', () => { + it('should update state', () => { + const initialState = initialSharedState; + const riskProfiles = [PROFILE_MOCK]; + const action = setRiskProfiles({ riskProfiles }); + const state = fromReducer.sharedReducer(initialState, action); + const newState = { ...initialState, ...{ riskProfiles } }; + + expect(state).toEqual(newState); + expect(state).not.toBe(initialState); + }); + }); + describe('setDeviceInProgress action', () => { it('should update state', () => { const initialState = initialSharedState; diff --git a/modules/ui/src/app/store/reducers.ts b/modules/ui/src/app/store/reducers.ts index cf8b3a48b..501c231a5 100644 --- a/modules/ui/src/app/store/reducers.ts +++ b/modules/ui/src/app/store/reducers.ts @@ -71,6 +71,18 @@ export const sharedReducer = createReducer( devices, }; }), + on(Actions.setHasRiskProfiles, (state, { hasRiskProfiles }) => { + return { + ...state, + hasRiskProfiles, + }; + }), + on(Actions.setRiskProfiles, (state, { riskProfiles }) => { + return { + ...state, + riskProfiles, + }; + }), on(Actions.setTestrunStatus, (state, { systemStatus }) => { return { ...state, diff --git a/modules/ui/src/app/store/selectors.spec.ts b/modules/ui/src/app/store/selectors.spec.ts index 43843b9dd..e8d31efc8 100644 --- a/modules/ui/src/app/store/selectors.spec.ts +++ b/modules/ui/src/app/store/selectors.spec.ts @@ -21,11 +21,13 @@ import { selectError, selectHasConnectionSettings, selectHasDevices, + selectHasRiskProfiles, selectInterfaces, selectIsOpenAddDevice, selectIsOpenStartTestrun, selectIsOpenWaitSnackBar, selectMenuOpened, + selectRiskProfiles, selectStatus, selectSystemStatus, } from './selectors'; @@ -45,6 +47,8 @@ describe('Selectors', () => { devices: [], hasDevices: false, isOpenAddDevice: false, + riskProfiles: [], + hasRiskProfiles: false, isStopTestrun: false, isOpenWaitSnackBar: false, isOpenStartTestrun: false, @@ -84,6 +88,16 @@ describe('Selectors', () => { expect(result).toEqual(false); }); + it('should select riskProfiles', () => { + const result = selectRiskProfiles.projector(initialState); + expect(result).toEqual([]); + }); + + it('should select hasRiskProfiles', () => { + const result = selectHasRiskProfiles.projector(initialState); + expect(result).toEqual(false); + }); + it('should select isOpenAddDevice', () => { const result = selectIsOpenAddDevice.projector(initialState); expect(result).toEqual(false); diff --git a/modules/ui/src/app/store/selectors.ts b/modules/ui/src/app/store/selectors.ts index 7075d4b0d..2f42db3d6 100644 --- a/modules/ui/src/app/store/selectors.ts +++ b/modules/ui/src/app/store/selectors.ts @@ -57,6 +57,16 @@ export const selectDeviceInProgress = createSelector( (state: AppState) => state.shared.deviceInProgress ); +export const selectHasRiskProfiles = createSelector( + selectAppState, + (state: AppState) => state.shared.hasRiskProfiles +); + +export const selectRiskProfiles = createSelector( + selectAppState, + (state: AppState) => state.shared.riskProfiles +); + export const selectError = createSelector( selectAppState, (state: AppState) => state.appComponent.settingMissedError diff --git a/modules/ui/src/app/store/state.ts b/modules/ui/src/app/store/state.ts index 11f52af2b..e2528c5a0 100644 --- a/modules/ui/src/app/store/state.ts +++ b/modules/ui/src/app/store/state.ts @@ -16,6 +16,7 @@ import { TestrunStatus } from '../model/testrun-status'; import { SettingMissedError, SystemInterfaces } from '../model/setting'; import { Device } from '../model/device'; +import { Profile } from '../model/profile'; export interface AppState { appComponent: AppComponentState; @@ -38,6 +39,9 @@ export interface SharedState { devices: Device[]; //used in app, devices, testrun hasDevices: boolean; + //app, risk-assessment, testrun, reports + riskProfiles: Profile[]; + hasRiskProfiles: boolean; //app, testrun status: string | null; systemStatus: TestrunStatus | null; @@ -69,6 +73,8 @@ export const initialSharedState: SharedState = { hasDevices: false, devices: [], deviceInProgress: null, + riskProfiles: [], + hasRiskProfiles: false, isOpenStartTestrun: false, systemStatus: null, status: null, diff --git a/modules/ui/src/styles.scss b/modules/ui/src/styles.scss index a35b71254..74cb3765a 100644 --- a/modules/ui/src/styles.scss +++ b/modules/ui/src/styles.scss @@ -239,6 +239,19 @@ body #main:has(app-callout .info):not(:has(app-callout .error)) app-risk-assessment .risk-assessment-container, +body + #main:has(app-callout .check_circle):not(:has(app-callout .error)) + app-device-repository:not(:has(.device-repository-content-empty)), +body + #main:has(app-callout .check_circle):not(:has(app-callout .error)) + app-history:not(:has(.results-content-empty)), +body + #main:has(app-callout .check_circle):not(:has(app-callout .error)) + app-progress:not(:has(.progress-content-empty)), +body + #main:has(app-callout .check_circle):not(:has(app-callout .error)) + app-risk-assessment + .risk-assessment-container, body #main:has(app-callout .error):not(:has(app-callout .info)) app-device-repository:not(:has(.device-repository-content-empty)), @@ -271,6 +284,22 @@ body margin-top: 156px; } +body + #main:has(app-callout .check_circle):has(app-callout .error) + app-device-repository:not(:has(.device-repository-content-empty)), +body + #main:has(app-callout .check_circle):has(app-callout .error) + app-history:not(:has(.results-content-empty)), +body + #main:has(app-callout .check_circle):has(app-callout .error) + app-progress:not(:has(.progress-content-empty)), +body + #main:has(app-callout .check_circle):has(app-callout .error) + app-risk-assessment + .risk-assessment-container { + margin-top: 156px; +} + body:has(app-risk-assessment .profiles-drawer) #main app-callout { width: calc(100% - $profiles-drawer-width); } From 1a18bfe46dc88e0a3af74c05cb17f746b3d3a372 Mon Sep 17 00:00:00 2001 From: Volha Mardvilka Date: Mon, 3 Jun 2024 15:32:24 +0000 Subject: [PATCH 2/2] 342365574: (fix) change to show Risk Assessment callout only on InProgress --- modules/ui/src/app/app.component.html | 2 +- modules/ui/src/app/app.component.spec.ts | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/ui/src/app/app.component.html b/modules/ui/src/app/app.component.html index 425aeb683..10ec58c4e 100644 --- a/modules/ui/src/app/app.component.html +++ b/modules/ui/src/app/app.component.html @@ -197,7 +197,7 @@

Testrun

vm.hasConnectionSettings === true && vm.hasDevices === true && vm.hasRiskProfiles === false && - isTestrunInProgress(vm.systemStatus) + vm.systemStatus === StatusOfTestrun.InProgress "> Congratulations, the device is under test now! Do not forget to fill { describe('with systemStatus data IN Progress and without riskProfiles', () => { beforeEach(() => { - mockService.testrunInProgress.and.returnValue(true); store.overrideSelector(selectHasConnectionSettings, true); store.overrideSelector(selectHasDevices, true); store.overrideSelector(selectHasRiskProfiles, false); store.overrideSelector( - selectSystemStatus, - MOCK_PROGRESS_DATA_IN_PROGRESS + selectStatus, + MOCK_PROGRESS_DATA_IN_PROGRESS.status ); - fixture.detectChanges(); });