Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions modules/ui/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,6 @@ <h1 class="main-heading">Testrun</h1>
autoFocus="#setting-panel-close-button"
class="settings-drawer">
<app-certificates
[certificates]="vm.certificates"
(deleteCertificateEvent)="deleteCertificate($event)"
(closeCertificatedEvent)="closeCertificates()"></app-certificates>
</mat-drawer>
</ng-container>
Expand Down
9 changes: 1 addition & 8 deletions modules/ui/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,9 @@ describe('AppComponent', () => {
'getTestModules',
'testrunInProgress',
'fetchCertificates',
'deleteCertificate',
]);

mockService.deleteCertificate.and.returnValue(of(true));
mockService.fetchCertificates.and.returnValue(of([]));
mockFocusManagerService = jasmine.createSpyObj('mockFocusManagerService', [
'focusFirstElementInContainer',
]);
Expand Down Expand Up @@ -676,12 +675,6 @@ describe('AppComponent', () => {

expect(component.certDrawer.open).toHaveBeenCalledTimes(1);
});

it('should call delete certificate', () => {
component.deleteCertificate('name');

expect(mockService.deleteCertificate).toHaveBeenCalledWith('name');
});
});

@Component({
Expand Down
5 changes: 0 additions & 5 deletions modules/ui/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ export class AppComponent {
) {
this.appStore.getDevices();
this.appStore.getSystemStatus();
this.appStore.getCertificates();
this.matIconRegistry.addSvgIcon(
'devices',
this.domSanitizer.bypassSecurityTrustResourceUrl(DEVICES_LOGO_URL)
Expand Down Expand Up @@ -165,8 +164,4 @@ export class AppComponent {
isTestrunInProgress(status?: string) {
return this.testRunService.testrunInProgress(status);
}

deleteCertificate(name: string) {
this.appStore.deleteCertificate(name);
}
}
50 changes: 1 addition & 49 deletions modules/ui/src/app/app.store.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import SpyObj = jasmine.SpyObj;
import { device } from './mocks/device.mock';
import { setDevices, setTestrunStatus } from './store/actions';
import { MOCK_PROGRESS_DATA_IN_PROGRESS } from './mocks/progress.mock';
import { certificate, certificate2 } from './mocks/certificate.mock';

const mock = (() => {
let store: { [key: string]: string } = {};
Expand All @@ -58,12 +57,7 @@ describe('AppStore', () => {
let mockService: SpyObj<TestRunService>;

beforeEach(() => {
mockService = jasmine.createSpyObj([
'fetchDevices',
'fetchSystemStatus',
'fetchCertificates',
'deleteCertificate',
]);
mockService = jasmine.createSpyObj(['fetchDevices', 'fetchSystemStatus']);

TestBed.configureTestingModule({
providers: [
Expand Down Expand Up @@ -113,15 +107,6 @@ describe('AppStore', () => {

appStore.updateIsStatusLoaded(true);
});

it('should update certificates', (done: DoneFn) => {
appStore.viewModel$.pipe(skip(1), take(1)).subscribe(store => {
expect(store.certificates).toEqual([certificate]);
done();
});

appStore.updateCertificates([certificate]);
});
});

describe('selectors', () => {
Expand All @@ -137,7 +122,6 @@ describe('AppStore', () => {
isMenuOpen: true,
interfaces: {},
settingMissedError: null,
certificates: [],
});
done();
});
Expand Down Expand Up @@ -200,37 +184,5 @@ describe('AppStore', () => {
appStore.getSystemStatus();
});
});

describe('fetchCertificates', () => {
const certificates = [certificate];

beforeEach(() => {
mockService.fetchCertificates.and.returnValue(of(certificates));
});

it('should update certificates', done => {
appStore.viewModel$.pipe(skip(1), take(1)).subscribe(store => {
expect(store.certificates).toEqual(certificates);
done();
});

appStore.getCertificates();
});
});

describe('deleteCertificate', () => {
it('should update store', done => {
mockService.deleteCertificate.and.returnValue(of(true));

appStore.updateCertificates([certificate, certificate2]);

appStore.viewModel$.pipe(skip(1), take(1)).subscribe(store => {
expect(store.certificates).toEqual([certificate2]);
done();
});

appStore.deleteCertificate('iot.bms.google.com');
});
});
});
});
43 changes: 1 addition & 42 deletions modules/ui/src/app/app.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import { Injectable } from '@angular/core';
import { ComponentStore } from '@ngrx/component-store';
import { tap, withLatestFrom } from 'rxjs/operators';
import { tap } from 'rxjs/operators';
import {
selectError,
selectHasConnectionSettings,
Expand All @@ -38,21 +38,18 @@ import {
} from './store/actions';
import { TestrunStatus } from './model/testrun-status';
import { SettingMissedError, SystemInterfaces } from './model/setting';
import { Certificate } from './model/certificate';

export const CONSENT_SHOWN_KEY = 'CONSENT_SHOWN';
export interface AppComponentState {
consentShown: boolean;
isStatusLoaded: boolean;
isTestrunStarted: boolean;
systemStatus: TestrunStatus | null;
certificates: Certificate[];
}
@Injectable()
export class AppStore extends ComponentStore<AppComponentState> {
private consentShown$ = this.select(state => state.consentShown);
private isStatusLoaded$ = this.select(state => state.isStatusLoaded);
private certificates$ = this.select(state => state.certificates);
private hasDevices$ = this.store.select(selectHasDevices);
private hasConnectionSetting$ = this.store.select(
selectHasConnectionSettings
Expand All @@ -75,7 +72,6 @@ export class AppStore extends ComponentStore<AppComponentState> {
isMenuOpen: this.isMenuOpen$,
interfaces: this.interfaces$,
settingMissedError: this.settingMissedError$,
certificates: this.certificates$,
});

updateConsent = this.updater((state, consentShown: boolean) => ({
Expand All @@ -88,11 +84,6 @@ export class AppStore extends ComponentStore<AppComponentState> {
isStatusLoaded,
}));

updateCertificates = this.updater((state, certificates: Certificate[]) => ({
...state,
certificates,
}));

setContent = this.effect<void>(trigger$ => {
return trigger$.pipe(
tap(() => {
Expand Down Expand Up @@ -137,37 +128,6 @@ export class AppStore extends ComponentStore<AppComponentState> {
);
});

getCertificates = this.effect(trigger$ => {
return trigger$.pipe(
exhaustMap(() => {
return this.testRunService.fetchCertificates().pipe(
tap((certificates: Certificate[]) => {
this.updateCertificates(certificates);
})
);
})
);
});

deleteCertificate = this.effect<string>(trigger$ => {
return trigger$.pipe(
exhaustMap((name: string) => {
return this.testRunService.deleteCertificate(name).pipe(
withLatestFrom(this.certificates$),
tap(([, current]) => {
this.removeCertificate(name, current);
})
);
})
);
});

private removeCertificate(name: string, current: Certificate[]) {
const certificates = current.filter(
certificate => certificate.name !== name
);
this.updateCertificates(certificates);
}
constructor(
private store: Store<AppState>,
private testRunService: TestRunService
Expand All @@ -177,7 +137,6 @@ export class AppStore extends ComponentStore<AppComponentState> {
isStatusLoaded: false,
isTestrunStarted: false,
systemStatus: null,
certificates: [],
});
}
}
5 changes: 5 additions & 0 deletions modules/ui/src/app/mocks/certificate.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export const certificate = {
expires: '2024-09-01T09:00:12Z',
} as Certificate;

export const certificate_uploading = {
name: 'test',
uploading: true,
} as Certificate;

export const certificate2 = {
name: 'sensor.bms.google.com',
organisation: 'Google, Inc.',
Expand Down
5 changes: 3 additions & 2 deletions modules/ui/src/app/model/certificate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
export interface Certificate {
name: string;
organisation: string;
expires: string;
organisation?: string;
expires?: string;
uploading?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@
>
<div class="certificate-item-information">
<p class="certificate-item-name">{{ certificate.name }}</p>
<p class="certificate-item-organisation">{{ certificate.organisation }}</p>
<p class="certificate-item-expires">
<p class="certificate-item-organisation" *ngIf="certificate.organisation">
{{ certificate.organisation }}
</p>
<p class="certificate-item-expires" *ngIf="certificate.expires">
{{ certificate.expires | date: 'dd MMM yyyy' }}
</p>
<mat-progress-bar
*ngIf="certificate.uploading"
mode="indeterminate"></mat-progress-bar>
</div>

<button
[disabled]="certificate.uploading"
class="certificate-item-delete"
mat-icon-button
aria-label="Delete certificate"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@use '@angular/material' as mat;
@import '../../../../theming/colors';
@import '../../../../theming/variables';
@import 'src/theming/colors';
@import 'src/theming/variables';

:host {
::ng-deep .mat-mdc-progress-bar {
--mdc-linear-progress-active-indicator-color: #1967d2;
}
}
:host:first-child .certificate-item-container {
border-top: 1px solid $lighter-grey;
}
Expand Down Expand Up @@ -45,6 +49,10 @@
& ::ng-deep .mat-mdc-button-persistent-ripple {
border-radius: 4px;
}
&:disabled {
pointer-events: none;
opacity: 0.6;
}
}

.certificate-item-information {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { CertificateItemComponent } from './certificate-item.component';
import { certificate } from '../../../mocks/certificate.mock';
import {
certificate,
certificate_uploading,
} from '../../../mocks/certificate.mock';

describe('CertificateItemComponent', () => {
let component: CertificateItemComponent;
Expand Down Expand Up @@ -31,37 +34,60 @@ describe('CertificateItemComponent', () => {
expect(name?.textContent?.trim()).toEqual('iot.bms.google.com');
});

it('should have certificate organization', () => {
const organization = compiled.querySelector(
'.certificate-item-organisation'
);
describe('uploaded certificate', () => {
it('should have certificate organization', () => {
const organization = compiled.querySelector(
'.certificate-item-organisation'
);

expect(organization?.textContent?.trim()).toEqual('Google, Inc.');
});
expect(organization?.textContent?.trim()).toEqual('Google, Inc.');
});

it('should have certificate expire date', () => {
const date = compiled.querySelector('.certificate-item-expires');

expect(date?.textContent?.trim()).toEqual('01 Sep 2024');
});

describe('delete button', () => {
let deleteButton: HTMLButtonElement;
beforeEach(() => {
deleteButton = fixture.nativeElement.querySelector(
'.certificate-item-delete'
) as HTMLButtonElement;
});

it('should be present', () => {
expect(deleteButton).toBeDefined();
});

it('should have certificate expire date', () => {
const date = compiled.querySelector('.certificate-item-expires');
it('should emit delete event on delete button clicked', () => {
const deleteSpy = spyOn(component.deleteButtonClicked, 'emit');
deleteButton.click();

expect(date?.textContent?.trim()).toEqual('01 Sep 2024');
expect(deleteSpy).toHaveBeenCalledWith('iot.bms.google.com');
});
});
});

describe('delete button', () => {
let deleteButton: HTMLButtonElement;
describe('uploading certificate', () => {
beforeEach(() => {
deleteButton = fixture.nativeElement.querySelector(
'.certificate-item-delete'
) as HTMLButtonElement;
component.certificate = certificate_uploading;
fixture.detectChanges();
});

it('should be present', () => {
expect(deleteButton).toBeDefined();
it('should have loader', () => {
const loader = compiled.querySelector('mat-progress-bar');

expect(loader).toBeDefined();
});

it('should emit delete event on delete button clicked', () => {
const deleteSpy = spyOn(component.deleteButtonClicked, 'emit');
deleteButton.click();
it('should have disabled delete button', () => {
const deleteButton = fixture.nativeElement.querySelector(
'.certificate-item-delete'
) as HTMLButtonElement;

expect(deleteSpy).toHaveBeenCalledWith('iot.bms.google.com');
expect(deleteButton.getAttribute('disabled')).toBeTruthy();
});
});
});
Expand Down
Loading