diff --git a/modules/ui/src/app/app.component.html b/modules/ui/src/app/app.component.html
index 914d69518..d2969a096 100644
--- a/modules/ui/src/app/app.component.html
+++ b/modules/ui/src/app/app.component.html
@@ -89,20 +89,31 @@
Testrun
-
- Selected port is missing! Please define a valid one using
- System settings
- panel.
-
+
+
+
+ No ports are detected. Please define a valid ones using
+
+
+ Selected port is missing! Please define a valid one using
+
+ System settings
+ panel.
+
+
diff --git a/modules/ui/src/app/app.component.spec.ts b/modules/ui/src/app/app.component.spec.ts
index 6cc2da48d..901c08795 100644
--- a/modules/ui/src/app/app.component.spec.ts
+++ b/modules/ui/src/app/app.component.spec.ts
@@ -568,12 +568,17 @@ describe('AppComponent', () => {
});
describe('error', () => {
- describe('with error', () => {
+ describe('with settingMissedError with one port is missed', () => {
beforeEach(() => {
- component.error$ = of(true);
+ component.settingMissedError$ = of({
+ isSettingMissed: true,
+ devicePortMissed: true,
+ internetPortMissed: false,
+ });
component.ngOnInit();
fixture.detectChanges();
});
+
it('should have callout component', () => {
const callout = compiled.querySelector('app-callout');
const calloutContent = callout?.innerHTML.trim();
@@ -583,9 +588,29 @@ describe('AppComponent', () => {
});
});
- describe('with no error', () => {
+ describe('with settingMissedError with two ports are missed', () => {
+ beforeEach(() => {
+ component.settingMissedError$ = of({
+ isSettingMissed: true,
+ devicePortMissed: true,
+ internetPortMissed: true,
+ });
+ component.ngOnInit();
+ fixture.detectChanges();
+ });
+
+ it('should have callout component', () => {
+ const callout = compiled.querySelector('app-callout');
+ const calloutContent = callout?.innerHTML.trim();
+
+ expect(callout).toBeTruthy();
+ expect(calloutContent).toContain('No ports are detected.');
+ });
+ });
+
+ describe('with no settingMissedError', () => {
beforeEach(() => {
- component.error$ = of(false);
+ component.settingMissedError$ = of(null);
store.overrideSelector(selectHasDevices, true);
fixture.detectChanges();
});
diff --git a/modules/ui/src/app/app.component.ts b/modules/ui/src/app/app.component.ts
index c8b6d8a0b..55d6ab9dc 100644
--- a/modules/ui/src/app/app.component.ts
+++ b/modules/ui/src/app/app.component.ts
@@ -39,7 +39,7 @@ import {
updateFocusNavigation,
} from './store/actions';
import { appFeatureKey } from './store/reducers';
-import { SystemInterfaces } from './model/setting';
+import { SettingMissedError, SystemInterfaces } from './model/setting';
import { GeneralSettingsComponent } from './pages/settings/general-settings.component';
import { AppStore } from './app.store';
@@ -65,12 +65,12 @@ export class AppComponent implements OnInit {
selectHasConnectionSettings
);
isStatusLoaded = false;
- isConnectionSettingsLoaded = false;
private openedSettingFromToggleBtn = true;
isMenuOpen: Observable = this.store.select(selectMenuOpened);
interfaces: Observable =
this.store.select(selectInterfaces);
- error$: Observable = this.store.select(selectError);
+ settingMissedError$: Observable =
+ this.store.select(selectError);
@ViewChild('settingsDrawer') public settingsDrawer!: MatDrawer;
@ViewChild('toggleSettingsBtn') public toggleSettingsBtn!: HTMLButtonElement;
diff --git a/modules/ui/src/app/model/setting.ts b/modules/ui/src/app/model/setting.ts
index e27f8ba8a..101ae6ded 100644
--- a/modules/ui/src/app/model/setting.ts
+++ b/modules/ui/src/app/model/setting.ts
@@ -22,6 +22,18 @@ export interface SystemConfig {
monitor_period?: number;
}
+export interface InterfacesValidation {
+ hasSetInterfaces: boolean;
+ deviceValid: boolean;
+ internetValid: boolean;
+}
+
+export interface SettingMissedError {
+ isSettingMissed: boolean;
+ devicePortMissed: boolean;
+ internetPortMissed: boolean;
+}
+
export interface SettingOption {
key: string;
value: string;
diff --git a/modules/ui/src/app/store/actions.ts b/modules/ui/src/app/store/actions.ts
index 9b31d84ff..f4582b7d0 100644
--- a/modules/ui/src/app/store/actions.ts
+++ b/modules/ui/src/app/store/actions.ts
@@ -15,7 +15,11 @@
*/
import { createAction, props } from '@ngrx/store';
-import { SystemConfig } from '../model/setting';
+import {
+ InterfacesValidation,
+ SettingMissedError,
+ SystemConfig,
+} from '../model/setting';
import { SystemInterfaces } from '../model/setting';
import { Device } from '../model/device';
@@ -36,12 +40,12 @@ export const updateFocusNavigation = createAction(
export const updateValidInterfaces = createAction(
'[App Component] Update Valid Interfaces',
- props<{ validInterfaces: boolean }>()
+ props<{ validInterfaces: InterfacesValidation }>()
);
export const updateError = createAction(
- '[App Component] Update Error',
- props<{ error: boolean }>()
+ '[App Component] Update Setting Missed Error',
+ props<{ settingMissedError: SettingMissedError }>()
);
// Settings
diff --git a/modules/ui/src/app/store/effects.spec.ts b/modules/ui/src/app/store/effects.spec.ts
index 74ce2cf82..819959c3f 100644
--- a/modules/ui/src/app/store/effects.spec.ts
+++ b/modules/ui/src/app/store/effects.spec.ts
@@ -77,27 +77,59 @@ describe('Effects', () => {
});
describe('onValidateInterfaces$', () => {
- it('should call updateError with false if interfaces are valid', done => {
- actions$ = of(actions.updateValidInterfaces({ validInterfaces: true }));
+ it('should call updateError and set false if interfaces are not missed', done => {
+ actions$ = of(
+ actions.updateValidInterfaces({
+ validInterfaces: {
+ hasSetInterfaces: false,
+ deviceValid: false,
+ internetValid: false,
+ },
+ })
+ );
effects.onValidateInterfaces$.subscribe(action => {
- expect(action).toEqual(actions.updateError({ error: false }));
+ expect(action).toEqual(
+ actions.updateError({
+ settingMissedError: {
+ isSettingMissed: false,
+ devicePortMissed: false,
+ internetPortMissed: false,
+ },
+ })
+ );
done();
});
});
- it('should call updateError with true if interfaces are not valid', done => {
- actions$ = of(actions.updateValidInterfaces({ validInterfaces: false }));
+ it('should call updateError and set true if interfaces are missed', done => {
+ actions$ = of(
+ actions.updateValidInterfaces({
+ validInterfaces: {
+ hasSetInterfaces: true,
+ deviceValid: false,
+ internetValid: false,
+ },
+ })
+ );
effects.onValidateInterfaces$.subscribe(action => {
- expect(action).toEqual(actions.updateError({ error: true }));
+ expect(action).toEqual(
+ actions.updateError({
+ settingMissedError: {
+ isSettingMissed: true,
+ devicePortMissed: true,
+ internetPortMissed: true,
+ },
+ })
+ );
done();
});
});
});
describe('checkInterfacesInConfig$', () => {
- it('should call updateValidInterfaces with false if interface is no longer available', done => {
+ it('should call updateValidInterfaces and set deviceValid as false if device interface is no longer available', done => {
actions$ = of(
actions.fetchInterfacesSuccess({
interfaces: {
@@ -117,13 +149,19 @@ describe('Effects', () => {
effects.checkInterfacesInConfig$.subscribe(action => {
expect(action).toEqual(
- actions.updateValidInterfaces({ validInterfaces: false })
+ actions.updateValidInterfaces({
+ validInterfaces: {
+ hasSetInterfaces: true,
+ deviceValid: false,
+ internetValid: true,
+ },
+ })
);
done();
});
});
- it('should call updateValidInterfaces with true if interface is available', done => {
+ it('should call updateValidInterfaces and set all true if interface is set and valid', done => {
actions$ = of(
actions.fetchInterfacesSuccess({
interfaces: {
@@ -143,7 +181,13 @@ describe('Effects', () => {
effects.checkInterfacesInConfig$.subscribe(action => {
expect(action).toEqual(
- actions.updateValidInterfaces({ validInterfaces: true })
+ actions.updateValidInterfaces({
+ validInterfaces: {
+ hasSetInterfaces: true,
+ deviceValid: true,
+ internetValid: true,
+ },
+ })
);
done();
});
diff --git a/modules/ui/src/app/store/effects.ts b/modules/ui/src/app/store/effects.ts
index 21994cded..f3b2c602a 100644
--- a/modules/ui/src/app/store/effects.ts
+++ b/modules/ui/src/app/store/effects.ts
@@ -40,13 +40,18 @@ export class AppEffects {
},
]) =>
AppActions.updateValidInterfaces({
- validInterfaces:
- network != null &&
- // @ts-expect-error network is not null
- interfaces[network.device_intf] != null &&
- (network.internet_intf == '' ||
- // @ts-expect-error network is not null
- interfaces[network.internet_intf] != null),
+ validInterfaces: {
+ hasSetInterfaces: network != null,
+ deviceValid:
+ !!network &&
+ !!network.device_intf &&
+ !!interfaces[network.device_intf],
+ internetValid:
+ !!network &&
+ (network?.internet_intf == '' ||
+ (!!network.internet_intf &&
+ !!interfaces[network.internet_intf])),
+ },
})
)
)
@@ -56,7 +61,18 @@ export class AppEffects {
return this.actions$.pipe(
ofType(AppActions.updateValidInterfaces),
map(({ validInterfaces }) =>
- AppActions.updateError({ error: !validInterfaces })
+ AppActions.updateError({
+ settingMissedError: {
+ isSettingMissed:
+ validInterfaces.hasSetInterfaces &&
+ (!validInterfaces.deviceValid || !validInterfaces.internetValid),
+ devicePortMissed:
+ validInterfaces.hasSetInterfaces && !validInterfaces.deviceValid,
+ internetPortMissed:
+ validInterfaces.hasSetInterfaces &&
+ !validInterfaces.internetValid,
+ },
+ })
)
);
});
diff --git a/modules/ui/src/app/store/reducers.spec.ts b/modules/ui/src/app/store/reducers.spec.ts
index 2c9436b56..3fccf462f 100644
--- a/modules/ui/src/app/store/reducers.spec.ts
+++ b/modules/ui/src/app/store/reducers.spec.ts
@@ -94,10 +94,20 @@ describe('Reducer', () => {
describe('updateError action', () => {
it('should update state', () => {
+ const mockSettingMissedError = {
+ isSettingMissed: true,
+ devicePortMissed: true,
+ internetPortMissed: true,
+ };
const initialState = initialAppComponentState;
- const action = updateError({ error: true });
+ const action = updateError({
+ settingMissedError: mockSettingMissedError,
+ });
const state = fromReducer.appComponentReducer(initialState, action);
- const newState = { ...initialState, ...{ error: true } };
+ const newState = {
+ ...initialState,
+ ...{ settingMissedError: mockSettingMissedError },
+ };
expect(state).toEqual(newState);
expect(state).not.toBe(initialState);
diff --git a/modules/ui/src/app/store/reducers.ts b/modules/ui/src/app/store/reducers.ts
index e5fc95a31..fff777847 100644
--- a/modules/ui/src/app/store/reducers.ts
+++ b/modules/ui/src/app/store/reducers.ts
@@ -33,9 +33,9 @@ export const appComponentReducer = createReducer(
...state,
focusNavigation,
})),
- on(Actions.updateError, (state, { error }) => ({
+ on(Actions.updateError, (state, { settingMissedError }) => ({
...state,
- error,
+ settingMissedError,
}))
);
diff --git a/modules/ui/src/app/store/selectors.spec.ts b/modules/ui/src/app/store/selectors.spec.ts
index 8aa55f69f..9443829b8 100644
--- a/modules/ui/src/app/store/selectors.spec.ts
+++ b/modules/ui/src/app/store/selectors.spec.ts
@@ -33,7 +33,7 @@ describe('Selectors', () => {
isStatusLoaded: false,
devicesLength: 0,
focusNavigation: false,
- error: false,
+ settingMissedError: null,
},
shared: {
hasConnectionSettings: false,
@@ -58,9 +58,9 @@ describe('Selectors', () => {
expect(result).toEqual(false);
});
- it('should select error', () => {
+ it('should select settingMissedError', () => {
const result = selectError.projector(initialState);
- expect(result).toEqual(false);
+ expect(result).toEqual(null);
});
it('should select devices', () => {
diff --git a/modules/ui/src/app/store/selectors.ts b/modules/ui/src/app/store/selectors.ts
index 0367229e3..29173bcc8 100644
--- a/modules/ui/src/app/store/selectors.ts
+++ b/modules/ui/src/app/store/selectors.ts
@@ -54,5 +54,5 @@ export const selectDevices = createSelector(
export const selectError = createSelector(
selectAppState,
- (state: AppState) => state.appComponent.error
+ (state: AppState) => state.appComponent.settingMissedError
);
diff --git a/modules/ui/src/app/store/state.ts b/modules/ui/src/app/store/state.ts
index e8b98ad6a..0693cdfd4 100644
--- a/modules/ui/src/app/store/state.ts
+++ b/modules/ui/src/app/store/state.ts
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { TestrunStatus } from '../model/testrun-status';
-import { SystemInterfaces } from '../model/setting';
+import { SettingMissedError, SystemInterfaces } from '../model/setting';
import { Device } from '../model/device';
export interface AppState {
@@ -29,7 +29,7 @@ export interface AppComponentState {
* Indicates, if side menu should be focused on keyboard navigation after menu is opened
*/
focusNavigation: boolean;
- error: boolean;
+ settingMissedError: SettingMissedError | null;
isStatusLoaded: boolean; // TODO should be updated in effect when fetch status
devicesLength: number; // TODO should be renamed to focusToggleSettingsBtn (true when devices.length > 0) and updated in effect when fetch device
}
@@ -54,7 +54,7 @@ export const initialAppComponentState: AppComponentState = {
focusNavigation: false,
isStatusLoaded: false,
devicesLength: 0,
- error: false,
+ settingMissedError: null,
};
export const initialSharedState: SharedState = {