diff --git a/modules/ui/src/app/components/stepper/stepper.component.html b/modules/ui/src/app/components/stepper/stepper.component.html
index 487bce262..8571dfd2c 100644
--- a/modules/ui/src/app/components/stepper/stepper.component.html
+++ b/modules/ui/src/app/components/stepper/stepper.component.html
@@ -34,7 +34,7 @@
diff --git a/modules/ui/src/app/components/stepper/stepper.component.scss b/modules/ui/src/app/components/stepper/stepper.component.scss
index 87c7ffecd..e300fb8c6 100644
--- a/modules/ui/src/app/components/stepper/stepper.component.scss
+++ b/modules/ui/src/app/components/stepper/stepper.component.scss
@@ -29,7 +29,8 @@
display: grid;
padding: 24px;
gap: 10px;
- overflow: auto;
+ overflow: hidden;
+ height: 100%;
}
.form-footer {
@@ -78,6 +79,6 @@
}
&.hidden {
- display: none;
+ visibility: hidden;
}
}
diff --git a/modules/ui/src/app/components/stepper/stepper.component.ts b/modules/ui/src/app/components/stepper/stepper.component.ts
index fdd0c9ce7..6f688d377 100644
--- a/modules/ui/src/app/components/stepper/stepper.component.ts
+++ b/modules/ui/src/app/components/stepper/stepper.component.ts
@@ -40,10 +40,8 @@ export class StepperComponent extends CdkStepper {
@Input() header: TemplateRef | undefined;
@Input() activeClass = 'active';
- stepsCount = [1, 2, 3, 4]; //TODO will be removed when all steps are implemented
-
forwardButtonHidden() {
- return this.selectedIndex === this.stepsCount.length - 1;
+ return this.selectedIndex === this.steps.length - 1;
}
backButtonHidden() {
diff --git a/modules/ui/src/app/pages/devices/components/device-form/device-form.component.spec.ts b/modules/ui/src/app/pages/devices/components/device-form/device-form.component.spec.ts
index 6ea72aa52..1911402a0 100644
--- a/modules/ui/src/app/pages/devices/components/device-form/device-form.component.spec.ts
+++ b/modules/ui/src/app/pages/devices/components/device-form/device-form.component.spec.ts
@@ -20,7 +20,7 @@ import {
TestBed,
} from '@angular/core/testing';
-import { DeviceFormComponent, FormAction } from './device-form.component';
+import { DeviceFormComponent } from './device-form.component';
import { MatButtonModule } from '@angular/material/button';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { MatCheckboxModule } from '@angular/material/checkbox';
@@ -39,6 +39,7 @@ import { NgxMaskDirective, NgxMaskPipe, provideNgxMask } from 'ngx-mask';
import { DevicesStore } from '../../devices.store';
import { device, MOCK_TEST_MODULES } from '../../../../mocks/device.mock';
import SpyObj = jasmine.SpyObj;
+import { FormAction } from '../../devices.component';
describe('DeviceFormComponent', () => {
let component: DeviceFormComponent;
diff --git a/modules/ui/src/app/pages/devices/components/device-form/device-form.component.ts b/modules/ui/src/app/pages/devices/components/device-form/device-form.component.ts
index 38ab05ffa..f7aa4f180 100644
--- a/modules/ui/src/app/pages/devices/components/device-form/device-form.component.ts
+++ b/modules/ui/src/app/pages/devices/components/device-form/device-form.component.ts
@@ -29,6 +29,7 @@ import { Subject } from 'rxjs';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
import { EscapableDialogComponent } from '../../../../components/escapable-dialog/escapable-dialog.component';
import { DevicesStore } from '../../devices.store';
+import { FormAction, FormResponse } from '../../devices.component';
const MAC_ADDRESS_PATTERN =
'^[\\s]*[a-fA-F0-9]{2}(?:[:][a-fA-F0-9]{2}){5}[\\s]*$';
@@ -40,16 +41,6 @@ interface DialogData {
testModules: TestModule[];
}
-export enum FormAction {
- Delete = 'Delete',
- Save = 'Save',
-}
-
-export interface FormResponse {
- device?: Device;
- action: FormAction;
-}
-
@Component({
selector: 'app-device-form',
templateUrl: './device-form.component.html',
diff --git a/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.html b/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.html
index 60f7226b0..cf1d60fb6 100644
--- a/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.html
+++ b/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.html
@@ -32,10 +32,11 @@
+ [header]="header"
+ [selectedIndex]="selectedIndex">
Device Manufacturer
@@ -151,26 +152,43 @@
[editable]="true"
[formGroupName]="step.step"
[stepControl]="getStep(step.step)">
-
-
- {{ step.description }}
-
-
+
+
+
+ {{ step.description }}
+
+
+
-
- Final step
+
+
+
+
+ The device has been configured. Please check the setup.
+
+
+
+
+
+
+
diff --git a/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.scss b/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.scss
index f4c06d5e6..97b92dfbc 100644
--- a/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.scss
+++ b/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.scss
@@ -145,3 +145,27 @@ $form-height: 993px;
margin: 0;
padding-top: 8px;
}
+
+.device-qualification-form-step-content {
+ overflow: scroll;
+}
+
+.device-qualification-form-page {
+ display: grid;
+ gap: 10px;
+ height: 100%;
+ overflow: hidden;
+ &:last-of-type {
+ grid-template-rows: min-content min-content 1fr min-content;
+ }
+}
+
+.device-qualification-form-actions {
+ text-align: center;
+ .close-button {
+ padding: 0 16px;
+ }
+ .save-button {
+ margin: 0 16px;
+ }
+}
diff --git a/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.spec.ts b/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.spec.ts
index cc320e03f..2dd7263f2 100644
--- a/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.spec.ts
+++ b/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.spec.ts
@@ -39,6 +39,7 @@ import { MatIconTestingModule } from '@angular/material/icon/testing';
import { TestRunService } from '../../../../services/test-run.service';
import { DevicesStore } from '../../devices.store';
import { provideMockStore } from '@ngrx/store/testing';
+import { FormAction } from '../../devices.component';
describe('DeviceQualificationFromComponent', () => {
let component: DeviceQualificationFromComponent;
let fixture: ComponentFixture;
@@ -85,6 +86,7 @@ describe('DeviceQualificationFromComponent', () => {
component.data = {
testModules: MOCK_TEST_MODULES,
devices: [],
+ index: 0,
};
testrunServiceMock.fetchQuestionnaireFormat.and.returnValue(
of(DEVICES_FORM)
@@ -97,13 +99,13 @@ describe('DeviceQualificationFromComponent', () => {
expect(component).toBeTruthy();
});
- it('should fetch devices format', () => {
+ it('should contain device form', () => {
const form = compiled.querySelector('.device-qualification-form');
expect(form).toBeTruthy();
});
- it('should contain device form', () => {
+ it('should fetch devices format', () => {
const getQuestionnaireFormatSpy = spyOn(
component.devicesStore,
'getQuestionnaireFormat'
@@ -122,7 +124,23 @@ describe('DeviceQualificationFromComponent', () => {
closeButton?.click();
- expect(closeSpy).toHaveBeenCalledWith();
+ expect(closeSpy).toHaveBeenCalledWith({
+ action: FormAction.Close,
+ index: 0,
+ device: {
+ manufacturer: '',
+ model: '',
+ mac_addr: '',
+ test_modules: {
+ udmi: {
+ enabled: false,
+ },
+ connection: {
+ enabled: true,
+ },
+ },
+ },
+ });
closeSpy.calls.reset();
});
@@ -304,6 +322,7 @@ describe('DeviceQualificationFromComponent', () => {
component.data = {
testModules: MOCK_TEST_MODULES,
devices: [device],
+ index: 0,
};
component.ngOnInit();
fixture.detectChanges();
@@ -341,6 +360,7 @@ describe('DeviceQualificationFromComponent', () => {
},
},
},
+ index: 0,
};
component.ngOnInit();
@@ -360,7 +380,7 @@ describe('DeviceQualificationFromComponent', () => {
});
});
- describe('with questioner', () => {
+ describe('with questionnaire', () => {
it('should have steps', () => {
expect(
(component.deviceQualificationForm.get('steps') as FormArray).controls
diff --git a/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.ts b/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.ts
index bdb8dc92d..f4efb34db 100644
--- a/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.ts
+++ b/modules/ui/src/app/pages/devices/components/device-qualification-from/device-qualification-from.component.ts
@@ -18,7 +18,9 @@ import {
Component,
ElementRef,
Inject,
+ OnDestroy,
OnInit,
+ ViewChild,
} from '@angular/core';
import {
AbstractControl,
@@ -56,7 +58,8 @@ import { MatRadioButton, MatRadioGroup } from '@angular/material/radio';
import { ProfileValidators } from '../../../risk-assessment/profile-form/profile.validators';
import { DevicesStore } from '../../devices.store';
import { DynamicFormComponent } from '../../../../components/dynamic-form/dynamic-form.component';
-import { skip } from 'rxjs';
+import { skip, Subject, takeUntil, timer } from 'rxjs';
+import { FormAction, FormResponse } from '../../devices.component';
const MAC_ADDRESS_PATTERN =
'^[\\s]*[a-fA-F0-9]{2}(?:[:][a-fA-F0-9]{2}){5}[\\s]*$';
@@ -66,6 +69,7 @@ interface DialogData {
device?: Device;
devices: Device[];
testModules: TestModule[];
+ index: number;
}
@Component({
@@ -98,12 +102,16 @@ interface DialogData {
})
export class DeviceQualificationFromComponent
extends EscapableDialogComponent
- implements OnInit, AfterViewInit
+ implements OnInit, AfterViewInit, OnDestroy
{
+ @ViewChild('stepper') public stepper!: StepperComponent;
testModules: TestModule[] = [];
deviceQualificationForm: FormGroup = this.fb.group({});
device: Device | undefined;
format: DeviceQuestionnaireSection[] = [];
+ selectedIndex: number = 0;
+
+ private destroy$: Subject = new Subject();
get model() {
return this.getStep(0).get('model') as AbstractControl;
@@ -146,6 +154,13 @@ export class DeviceQualificationFromComponent
this.devicesStore.questionnaireFormat$.pipe(skip(1)).subscribe(format => {
this.createDeviceForm(format);
this.format = format;
+ if (this.data.index) {
+ timer(0)
+ .pipe(takeUntil(this.destroy$))
+ .subscribe(() => {
+ this.selectedIndex = this.data.index;
+ });
+ }
});
this.devicesStore.getQuestionnaireFormat();
@@ -157,12 +172,21 @@ export class DeviceQualificationFromComponent
this.element.nativeElement.offsetHeight + 'px';
}
+ ngOnDestroy() {
+ this.destroy$.next(true);
+ this.destroy$.unsubscribe();
+ }
+
submit(): void {
this.device = this.createDeviceFromForm(this.getStep(0));
}
closeForm(): void {
- this.dialogRef.close();
+ this.dialogRef.close({
+ action: FormAction.Close,
+ device: this.createDeviceFromForm(this.getStep(0)),
+ index: this.stepper.selectedIndex,
+ } as FormResponse);
}
getStep(step: number) {
@@ -229,7 +253,7 @@ export class DeviceQualificationFromComponent
);
});
- // TODO dummy step
+ // summary step
(this.deviceQualificationForm.get('steps') as FormArray).controls.push(
this.fb.group({})
);
diff --git a/modules/ui/src/app/pages/devices/devices.component.html b/modules/ui/src/app/pages/devices/devices.component.html
index aef3730c5..7ea597d42 100644
--- a/modules/ui/src/app/pages/devices/devices.component.html
+++ b/modules/ui/src/app/pages/devices/devices.component.html
@@ -22,7 +22,7 @@ Devices
{
mockDevicesStore = jasmine.createSpyObj('DevicesStore', [
'setIsOpenAddDevice',
'selectDevice',
- 'deleteDevice',
'setStatus',
'getTestModules',
]);
@@ -163,6 +161,7 @@ describe('DevicesComponent', () => {
title: 'Create Device',
testModules: [],
devices: [device, device, device],
+ index: 0,
},
autoFocus: true,
hasBackdrop: true,
@@ -180,7 +179,7 @@ describe('DevicesComponent', () => {
} as MatDialogRef);
fixture.detectChanges();
- component.openDialog([device], MOCK_TEST_MODULES, device);
+ component.openDialog([device], MOCK_TEST_MODULES, device, true);
expect(openSpy).toHaveBeenCalled();
expect(openSpy).toHaveBeenCalledWith(DeviceQualificationFromComponent, {
@@ -190,6 +189,7 @@ describe('DevicesComponent', () => {
title: 'Edit device',
devices: [device],
testModules: MOCK_TEST_MODULES,
+ index: 0,
},
autoFocus: true,
hasBackdrop: true,
@@ -199,31 +199,6 @@ describe('DevicesComponent', () => {
openSpy.calls.reset();
});
-
- it('should open device dialog with delete-button focus element', () => {
- const openSpy = spyOn(component.dialog, 'open').and.returnValue({
- afterClosed: () => of(true),
- } as MatDialogRef);
- fixture.detectChanges();
-
- component.openDialog([device], MOCK_TEST_MODULES, device, true);
-
- expect(openSpy).toHaveBeenCalledWith(DeviceQualificationFromComponent, {
- ariaLabel: 'Edit device',
- data: {
- device: device,
- title: 'Edit device',
- devices: [device],
- testModules: MOCK_TEST_MODULES,
- },
- autoFocus: '.delete-button',
- hasBackdrop: true,
- disableClose: true,
- panelClass: 'device-form-dialog',
- });
-
- openSpy.calls.reset();
- });
});
it('should disable device if deviceInProgress is exist', () => {
@@ -243,21 +218,7 @@ describe('DevicesComponent', () => {
expect(mockDevicesStore.setIsOpenAddDevice).toHaveBeenCalled();
});
- it('should delete device if dialog closes with object, action delete and selected device', () => {
- spyOn(component.dialog, 'open').and.returnValue({
- afterClosed: () =>
- of({
- device,
- action: FormAction.Delete,
- }),
- } as MatDialogRef);
-
- component.openDialog([device], MOCK_TEST_MODULES, device);
-
- expect(mockDevicesStore.deleteDevice).toHaveBeenCalled();
- });
-
- describe('delete device dialog', () => {
+ describe('close dialog', () => {
beforeEach(() => {
component.viewModel$ = of({
devices: [device, device, device],
@@ -274,32 +235,20 @@ describe('DevicesComponent', () => {
expect(item.length).toEqual(3);
}));
- it('should delete device when dialog return true', () => {
- spyOn(component.dialog, 'open').and.returnValue({
- afterClosed: () => of(true),
- } as MatDialogRef);
-
- component.openDeleteDialog([device], MOCK_TEST_MODULES, device);
-
- const args = mockDevicesStore.deleteDevice.calls.argsFor(0);
- // @ts-expect-error config is in object
- expect(args[0].device).toEqual(device);
- expect(mockDevicesStore.deleteDevice).toHaveBeenCalled();
- });
-
it('should open device dialog when dialog return null', () => {
const openDeviceDialogSpy = spyOn(component, 'openDialog');
spyOn(component.dialog, 'open').and.returnValue({
afterClosed: () => of(null),
} as MatDialogRef);
- component.openDeleteDialog([device], MOCK_TEST_MODULES, device);
+ component.openCloseDialog([device], MOCK_TEST_MODULES, device);
expect(openDeviceDialogSpy).toHaveBeenCalledWith(
[device],
MOCK_TEST_MODULES,
device,
- true
+ false,
+ 0
);
});
});
diff --git a/modules/ui/src/app/pages/devices/devices.component.ts b/modules/ui/src/app/pages/devices/devices.component.ts
index e320663bf..a7243e148 100644
--- a/modules/ui/src/app/pages/devices/devices.component.ts
+++ b/modules/ui/src/app/pages/devices/devices.component.ts
@@ -22,21 +22,28 @@ import {
} from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { Device, DeviceView, TestModule } from '../../model/device';
-import {
- FormAction,
- FormResponse,
-} from './components/device-form/device-form.component';
import { Subject, takeUntil } from 'rxjs';
import { SimpleDialogComponent } from '../../components/simple-dialog/simple-dialog.component';
import { combineLatest } from 'rxjs/internal/observable/combineLatest';
import { FocusManagerService } from '../../services/focus-manager.service';
import { Routes } from '../../model/routes';
import { Router } from '@angular/router';
-import { timer } from 'rxjs/internal/observable/timer';
import { TestrunInitiateFormComponent } from '../testrun/components/testrun-initiate-form/testrun-initiate-form.component';
import { DevicesStore } from './devices.store';
import { DeviceQualificationFromComponent } from './components/device-qualification-from/device-qualification-from.component';
+export enum FormAction {
+ Delete = 'Delete',
+ Close = 'Close',
+ Save = 'Save',
+}
+
+export interface FormResponse {
+ device?: Device;
+ action: FormAction;
+ index: number;
+}
+
@Component({
selector: 'app-device-repository',
templateUrl: './devices.component.html',
@@ -113,17 +120,19 @@ export class DevicesComponent implements OnInit, OnDestroy {
devices: Device[] = [],
testModules: TestModule[],
selectedDevice?: Device,
- focusDeleteButton = false
+ isEditDevice = false,
+ index = 0
): void {
const dialogRef = this.dialog.open(DeviceQualificationFromComponent, {
- ariaLabel: selectedDevice ? 'Edit device' : 'Create Device',
+ ariaLabel: isEditDevice ? 'Edit device' : 'Create Device',
data: {
device: selectedDevice || null,
- title: selectedDevice ? 'Edit device' : 'Create Device',
+ title: isEditDevice ? 'Edit device' : 'Create Device',
testModules: testModules,
devices,
+ index,
},
- autoFocus: focusDeleteButton ? '.delete-button' : true,
+ autoFocus: true,
hasBackdrop: true,
disableClose: true,
panelClass: 'device-form-dialog',
@@ -138,37 +147,30 @@ export class DevicesComponent implements OnInit, OnDestroy {
this.devicesStore.setIsOpenAddDevice(false);
return;
}
- if (
- response.action === FormAction.Save &&
- response.device &&
- !selectedDevice
- ) {
- timer(10)
- .pipe(takeUntil(this.destroy$))
- .subscribe(() => {
- this.focusManagerService.focusFirstElementInContainer();
- });
- }
- if (response.action === FormAction.Delete && selectedDevice) {
- this.devicesStore.selectDevice(selectedDevice);
- this.openDeleteDialog(devices, testModules, selectedDevice);
+ if (response.action === FormAction.Close) {
+ this.openCloseDialog(
+ devices,
+ testModules,
+ response.device,
+ isEditDevice,
+ response.index
+ );
}
});
}
- openDeleteDialog(
+ openCloseDialog(
devices: Device[],
testModules: TestModule[],
- device: Device
+ device?: Device,
+ isEditDevice = false,
+ index = 0
) {
const dialogRef = this.dialog.open(SimpleDialogComponent, {
- ariaLabel: 'Delete device',
+ ariaLabel: 'Close the Device menu',
data: {
- title: 'Delete device?',
- content: `You are about to delete ${
- device.manufacturer + ' ' + device.model
- }. Are you sure?`,
- device: device,
+ title: 'Close the Device menu?',
+ content: `Are you ok to close the Device menu?`,
},
autoFocus: true,
hasBackdrop: true,
@@ -179,24 +181,16 @@ export class DevicesComponent implements OnInit, OnDestroy {
dialogRef
?.afterClosed()
.pipe(takeUntil(this.destroy$))
- .subscribe(deleteDevice => {
- if (deleteDevice) {
- this.devicesStore.deleteDevice({
- device,
- onDelete: () => {
- this.focusNextButton();
- this.devicesStore.selectDevice(null);
- },
- });
- } else {
- this.openDialog(devices, testModules, device, true);
+ .subscribe(close => {
+ if (!close) {
+ this.openDialog(devices, testModules, device, isEditDevice, index);
this.devicesStore.selectDevice(null);
}
});
}
private focusNextButton() {
- // Try to focus next device item, if exitst
+ // Try to focus next device item, if exist
const next = this.element.nativeElement.querySelector(
'.device-item-selected + app-device-item button'
);