Skip to content

Commit

Permalink
Disable device item if device in progress (#370)
Browse files Browse the repository at this point in the history
  • Loading branch information
sofyakurilova committed May 6, 2024
1 parent 4e3513d commit fcd83d4
Show file tree
Hide file tree
Showing 19 changed files with 159 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
*ngIf="deviceView === DeviceView.WithActions"
class="device-item-with-actions">
<button
[disabled]="disabled"
[tabIndex]="tabIndex"
(click)="itemClick()"
attr.aria-label="Edit device {{ label }}"
Expand All @@ -57,6 +58,7 @@
</div>
</button>
<button
[disabled]="disabled"
(click)="startTestrunClick()"
attr.aria-label="Start new testrun for device {{ label }}"
class="button-start"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ $border-radius: 12px;
width: 24px;
}
}

&:disabled {
pointer-events: none;
opacity: 0.5;
}
}

.item-manufacturer {
Expand Down Expand Up @@ -170,6 +175,10 @@ $border-radius: 12px;
color: $white;
}
}
&:disabled {
pointer-events: none;
opacity: 0.5;
}
}

.button-start-icon {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,5 +109,27 @@ describe('DeviceItemComponent', () => {

expect(clickSpy).toHaveBeenCalledWith(component.device);
});

it('should disable buttons if disable set to true', () => {
component.disabled = true;
fixture.detectChanges();

const startBtn = compiled.querySelector('.button-start') as HTMLElement;
const editBtn = compiled.querySelector('.button-edit') as HTMLElement;

expect(editBtn.getAttribute('disabled')).not.toBeNull();
expect(startBtn.getAttribute('disabled')).toBeTruthy();
});

it('should not disable buttons if disable set to false', () => {
component.disabled = false;
fixture.detectChanges();

const startBtn = compiled.querySelector('.button-start') as HTMLElement;
const editBtn = compiled.querySelector('.button-edit') as HTMLElement;

expect(editBtn.getAttribute('disabled')).toBeNull();
expect(startBtn.getAttribute('disabled')).toBeFalsy();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export class DeviceItemComponent {
@Input() device!: Device;
@Input() tabIndex = 0;
@Input() deviceView!: string;
@Input() disabled = false;
@Output() itemClicked = new EventEmitter<Device>();
@Output() startTestrunClicked = new EventEmitter<Device>();
readonly DeviceView = DeviceView;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ <h2 class="title">Devices</h2>
(startTestrunClicked)="openStartTestrun($event, vm.devices)"
[deviceView]="DeviceView.WithActions"
[class.device-item-selected]="device === vm.selectedDevice"
[device]="device"></app-device-item>
[device]="device"
[disabled]="
device?.mac_addr === vm.deviceInProgress?.mac_addr
"></app-device-item>
</ng-container>
</div>
</ng-container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ describe('DeviceRepositoryComponent', () => {
component.viewModel$ = of({
devices: [] as Device[],
selectedDevice: null,
deviceInProgress: null,
});
mockDevicesStore.devices$ = of([]);
mockDevicesStore.isOpenAddDevice$ = of(true);
Expand Down Expand Up @@ -107,6 +108,7 @@ describe('DeviceRepositoryComponent', () => {
component.viewModel$ = of({
devices: [device, device, device],
selectedDevice: device,
deviceInProgress: device,
});
fixture.detectChanges();
});
Expand Down Expand Up @@ -204,6 +206,12 @@ describe('DeviceRepositoryComponent', () => {
openSpy.calls.reset();
});
});

it('should disable device if deviceInProgress is exist', () => {
const item = compiled.querySelector('app-device-item');

expect(item?.getAttribute('ng-reflect-disabled')).toBeTruthy();
});
});

it('should call setIsOpenAddDevice if dialog closes with null', () => {
Expand Down Expand Up @@ -235,6 +243,7 @@ describe('DeviceRepositoryComponent', () => {
component.viewModel$ = of({
devices: [device, device, device],
selectedDevice: device,
deviceInProgress: null,
});
fixture.detectChanges();
});
Expand Down
7 changes: 6 additions & 1 deletion modules/ui/src/app/pages/devices/devices.store.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import { TestBed } from '@angular/core/testing';
import { of, skip, take } from 'rxjs';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { AppState } from '../../store/state';
import { selectHasDevices } from '../../store/selectors';
import {
selectDeviceInProgress,
selectHasDevices,
} from '../../store/selectors';
import { TestRunService } from '../../services/test-run.service';
import SpyObj = jasmine.SpyObj;
import { device, updated_device } from '../../mocks/device.mock';
Expand Down Expand Up @@ -45,6 +48,7 @@ describe('DevicesStore', () => {
selectors: [
{ selector: selectDevices, value: [device] },
{ selector: selectIsOpenAddDevice, value: true },
{ selector: selectDeviceInProgress, value: device },
],
}),
{ provide: TestRunService, useValue: mockService },
Expand Down Expand Up @@ -79,6 +83,7 @@ describe('DevicesStore', () => {
expect(store).toEqual({
devices: [device],
selectedDevice: null,
deviceInProgress: device,
});
done();
});
Expand Down
8 changes: 7 additions & 1 deletion modules/ui/src/app/pages/devices/devices.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ import { tap, withLatestFrom } from 'rxjs/operators';
import { Device } from '../../model/device';
import { AppState } from '../../store/state';
import { Store } from '@ngrx/store';
import { selectDevices, selectIsOpenAddDevice } from '../../store/selectors';
import {
selectDeviceInProgress,
selectDevices,
selectIsOpenAddDevice,
} from '../../store/selectors';
import { setDevices, setIsOpenAddDevice } from '../../store/actions';

export interface DevicesComponentState {
Expand All @@ -34,12 +38,14 @@ export interface DevicesComponentState {
export class DevicesStore extends ComponentStore<DevicesComponentState> {
devices$ = this.store.select(selectDevices);
isOpenAddDevice$ = this.store.select(selectIsOpenAddDevice);
private deviceInProgress$ = this.store.select(selectDeviceInProgress);
private selectedDevice$ = this.select(state => state.selectedDevice);

testModules = this.testRunService.getTestModules();
viewModel$ = this.select({
devices: this.devices$,
selectedDevice: this.selectedDevice$,
deviceInProgress: this.deviceInProgress$,
});

selectDevice = this.updater((state, device: Device | null) => ({
Expand Down
2 changes: 0 additions & 2 deletions modules/ui/src/app/pages/testrun/progress.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import { Component, Input } from '@angular/core';
import { IResult, TestrunStatus } from '../../model/testrun-status';
import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { ProgressInitiateFormComponent } from './components/progress-initiate-form/progress-initiate-form.component';
import { DownloadReportComponent } from '../../components/download-report/download-report.component';
import { DeleteFormComponent } from '../../components/delete-form/delete-form.component';
import { SpinnerComponent } from '../../components/spinner/spinner.component';
import { LoaderService } from '../../services/loader.service';
Expand Down Expand Up @@ -119,7 +118,6 @@ describe('ProgressComponent', () => {
MatToolbarModule,
MatDialogModule,
SpinnerComponent,
DownloadReportPdfComponent,
BrowserAnimationsModule,
],
})
Expand Down
7 changes: 6 additions & 1 deletion modules/ui/src/app/services/test-run.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import {
} from '../model/testrun-status';
import { device } from '../mocks/device.mock';
import { NEW_VERSION, VERSION } from '../mocks/version.mock';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { AppState } from '../store/state';

const MOCK_SYSTEM_CONFIG: SystemConfig = {
network: {
Expand All @@ -42,15 +44,18 @@ describe('TestRunService', () => {
let injector: TestBed;
let httpTestingController: HttpTestingController;
let service: TestRunService;
let store: MockStore<AppState>;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [TestRunService],
providers: [TestRunService, provideMockStore({})],
});
injector = getTestBed();
httpTestingController = injector.get(HttpTestingController);
service = injector.get(TestRunService);
store = TestBed.inject(MockStore);
spyOn(store, 'dispatch').and.callFake(() => {});
});

afterEach(() => {
Expand Down
7 changes: 6 additions & 1 deletion modules/ui/src/app/services/test-run.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import {
TestrunStatus,
} from '../model/testrun-status';
import { Version } from '../model/version';
import { Store } from '@ngrx/store';
import { AppState } from '../store/state';

const API_URL = `http://${window.location.hostname}:8000`;
export const SYSTEM_STOP = '/system/stop';
Expand Down Expand Up @@ -77,7 +79,10 @@ export class TestRunService {

private version = new BehaviorSubject<Version | null>(null);

constructor(private http: HttpClient) {}
constructor(
private http: HttpClient,
private store: Store<AppState>
) {}

fetchDevices(): Observable<Device[]> {
return this.http.get<Device[]>(`${API_URL}/devices`);
Expand Down
5 changes: 5 additions & 0 deletions modules/ui/src/app/store/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,8 @@ export const setIsTestrunStarted = createAction(
'[Shared] Set Testrun Started',
props<{ isTestrunStarted: boolean }>()
);

export const setDeviceInProgress = createAction(
'[Shared] Set Device In Progress',
props<{ device: Device | null }>()
);
13 changes: 13 additions & 0 deletions modules/ui/src/app/store/effects.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { AppState } from './state';
import { selectMenuOpened } from './selectors';
import { device } from '../mocks/device.mock';
import { MOCK_PROGRESS_DATA_IN_PROGRESS } from '../mocks/progress.mock';
describe('Effects', () => {
let actions$ = new Observable<Action>();
let effects: AppEffects;
Expand Down Expand Up @@ -55,6 +56,18 @@ describe('Effects', () => {
store.refreshState();
});

it('onSetDevices$ should call setDeviceInProgress when testrun in progress', done => {
const status = MOCK_PROGRESS_DATA_IN_PROGRESS;
actions$ = of(actions.setTestrunStatus({ systemStatus: status }));

effects.onSetTestrunStatus$.subscribe(action => {
expect(action).toEqual(
actions.setDeviceInProgress({ device: status.device })
);
done();
});
});

it('onSetDevices$ should call setHasDevices', done => {
actions$ = of(actions.setDevices({ devices: [device] }));

Expand Down
17 changes: 17 additions & 0 deletions modules/ui/src/app/store/effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { AppState } from './state';
import { TestRunService } from '../services/test-run.service';
import { filter, combineLatest } from 'rxjs';
import { selectMenuOpened } from './selectors';
import { StatusOfTestrun } from '../model/testrun-status';

@Injectable()
export class AppEffects {
Expand Down Expand Up @@ -95,6 +96,22 @@ export class AppEffects {
);
});

onSetTestrunStatus$ = createEffect(() => {
return this.actions$.pipe(
ofType(AppActions.setTestrunStatus),
map(({ systemStatus }) =>
AppActions.setDeviceInProgress({
device:
systemStatus.status === StatusOfTestrun.Monitoring ||
systemStatus.status === StatusOfTestrun.InProgress ||
systemStatus.status === StatusOfTestrun.WaitingForDevice
? systemStatus.device
: null,
})
)
);
});

constructor(
private actions$: Actions,
private testrunService: TestRunService,
Expand Down
32 changes: 32 additions & 0 deletions modules/ui/src/app/store/reducers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import * as fromReducer from './reducers';
import { initialAppComponentState, initialSharedState } from './state';
import {
fetchInterfacesSuccess,
setDeviceInProgress,
setDevices,
setHasConnectionSettings,
setHasDevices,
setIsOpenAddDevice,
Expand All @@ -27,6 +29,7 @@ import {
updateError,
updateFocusNavigation,
} from './actions';
import { device } from '../mocks/device.mock';
import { MOCK_PROGRESS_DATA_CANCELLING } from '../mocks/progress.mock';

describe('Reducer', () => {
Expand Down Expand Up @@ -140,6 +143,35 @@ describe('Reducer', () => {
});
});

describe('setDevices action', () => {
it('should update state', () => {
const initialState = initialSharedState;
const devices = [device, device];
const action = setDevices({ devices });
const state = fromReducer.sharedReducer(initialState, action);
const newState = { ...initialState, ...{ devices } };

expect(state).toEqual(newState);
expect(state).not.toBe(initialState);
});
});

describe('setDeviceInProgress action', () => {
it('should update state', () => {
const initialState = initialSharedState;
const deviceInProgress = device;
const action = setDeviceInProgress({ device: deviceInProgress });
const state = fromReducer.sharedReducer(initialState, action);
const newState = {
...initialState,
...{ deviceInProgress: deviceInProgress },
};

expect(state).toEqual(newState);
expect(state).not.toBe(initialState);
});
});

describe('setTestrunStatus action', () => {
it('should update state', () => {
const initialState = initialSharedState;
Expand Down
6 changes: 6 additions & 0 deletions modules/ui/src/app/store/reducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ export const sharedReducer = createReducer(
...state,
isTestrunStarted,
};
}),
on(Actions.setDeviceInProgress, (state, { device }) => {
return {
...state,
deviceInProgress: device,
};
})
);

Expand Down
Loading

0 comments on commit fcd83d4

Please sign in to comment.