Skip to content

Commit

Permalink
Merge pull request #53 from Buildings-IOT/DisplayPoints
Browse files Browse the repository at this point in the history
Display points
  • Loading branch information
mspratt-biot committed Mar 16, 2022
2 parents b273d9d + 33f2aa6 commit c6dc142
Show file tree
Hide file tree
Showing 12 changed files with 225 additions and 20 deletions.
4 changes: 3 additions & 1 deletion udmd/web/src/app/device/device.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
</mat-card>

<nav mat-tab-nav-bar [tabPanel]="tabPanel">
<a mat-tab-link routerLink="points" routerLinkActive="active">Points</a>
<a mat-tab-link routerLink="points" routerLinkActive="active" #rla="routerLinkActive" [active]="rla.isActive"
>Points</a
>
</nav>
<mat-tab-nav-panel #tabPanel>
<div class="container">
Expand Down
6 changes: 3 additions & 3 deletions udmd/web/src/app/device/device.component.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Device } from './device';
import { Device, DeviceModel } from './device';
import { DeviceService } from './device.service';

@Component({
templateUrl: './device.component.html',
styleUrls: ['./device.component.scss'],
})
export class DeviceComponent implements OnInit {
fields: (keyof Device)[] = [
fields: (keyof DeviceModel)[] = [
'name',
'make',
'model',
Expand All @@ -20,7 +20,7 @@ export class DeviceComponent implements OnInit {
'lastPayload',
'tags',
];
device!: Device;
device: Device = null;
loading: boolean = true;

constructor(private route: ActivatedRoute, private deviceService: DeviceService) {}
Expand Down
21 changes: 12 additions & 9 deletions udmd/web/src/app/device/device.d.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
export interface Device {
interface DeviceModel {
id: string;
name: string;
make?: string;
model?: string;
site?: string;
section?: string;
lastPayload?: string;
operational?: boolean;
firmware?: string;
serialNumber?: string;
make: string;
model: string;
site: string;
section: string;
lastPayload: string;
operational: boolean;
firmware: string;
serialNumber: string;
tags: string[];
points: string[];
}

export type Device = Partial<DeviceModel> | null;

export type DeviceResponse = {
device: Device;
};
Expand Down
15 changes: 12 additions & 3 deletions udmd/web/src/app/devices/devices.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core';
import { PageEvent } from '@angular/material/paginator';
import { Sort } from '@angular/material/sort';
import { SearchFilterItem } from '../search-filter/search-filter';
import { Device } from '../device/device';
import { Device, DeviceModel } from '../device/device';
import { SortOptions } from './devices';
import { DevicesService } from './devices.service';

Expand All @@ -11,7 +11,16 @@ import { DevicesService } from './devices.service';
styleUrls: ['./devices.component.scss'],
})
export class DevicesComponent implements OnInit {
displayedColumns: string[] = ['name', 'make', 'model', 'site', 'section', 'lastPayload', 'operational', 'tags'];
displayedColumns: (keyof DeviceModel)[] = [
'name',
'make',
'model',
'site',
'section',
'lastPayload',
'operational',
'tags',
];
loading: boolean = true;
devices: Device[] = [];
totalCount: number = 0;
Expand Down Expand Up @@ -42,7 +51,7 @@ export class DevicesComponent implements OnInit {
ngOnInit(): void {
this.devicesService.getDevices(0, this.pageSize).subscribe(({ data, loading }) => {
this.loading = loading;
this.devices = data.devices?.devices;
this.devices = data.devices?.devices ?? [];
this.totalCount = data.devices?.totalCount;
this.totalFilteredCount = data.devices?.totalFilteredCount;
}); // start off on first page, i.e. offset 0
Expand Down
2 changes: 1 addition & 1 deletion udmd/web/src/app/devices/devices.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface SortOptions {
}

export type DevicesResponse = {
devices: Device[];
devices: Device[] | null;
totalCount: number;
totalFilteredCount: number;
};
Expand Down
2 changes: 1 addition & 1 deletion udmd/web/src/app/points/points.component.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<p>points works!</p>
<p>{{ points }}</p>
47 changes: 47 additions & 0 deletions udmd/web/src/app/points/points.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,55 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ActivatedRoute } from '@angular/router';
import { ApolloQueryResult } from '@apollo/client/core';
import { of } from 'rxjs';
import { Point, PointsQueryResponse } from './points';
import { PointsComponent } from './points.component';
import { PointsModule } from './points.module';
import { PointsService } from './points.service';

describe('PointsComponent', () => {
let component: PointsComponent;
let fixture: ComponentFixture<PointsComponent>;
let mockPointsService: jasmine.SpyObj<PointsService>;
let points: Point[] = [
{
id: 'point-id-123',
},
];

beforeEach(async () => {
mockPointsService = jasmine.createSpyObj(PointsService, ['getPoints']);
mockPointsService.getPoints.and.returnValue(
of(<ApolloQueryResult<PointsQueryResponse>>{
data: {
device: {
id: 'device-id-123',
points,
},
},
loading: false,
})
);

await TestBed.configureTestingModule({
imports: [PointsModule],
providers: [
{ provide: PointsService, useValue: mockPointsService },
{
provide: ActivatedRoute,
useValue: {
parent: {
snapshot: {
parent: {
params: {
id: 'device-id-123',
},
},
},
},
},
},
],
}).compileComponents();
});

Expand All @@ -21,4 +62,10 @@ describe('PointsComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});

it('should store the points in memory', () => {
expect(mockPointsService.getPoints).toHaveBeenCalledWith('device-id-123');
expect(component.points).toEqual(points);
expect(component.loading).toBeFalse();
});
});
17 changes: 15 additions & 2 deletions udmd/web/src/app/points/points.component.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Point } from './points';
import { PointsService } from './points.service';

@Component({
templateUrl: './points.component.html',
styleUrls: ['./points.component.scss'],
})
export class PointsComponent implements OnInit {
constructor() {}
points: Point[] = [];
loading: boolean = true;

ngOnInit(): void {}
constructor(private route: ActivatedRoute, private pointsService: PointsService) {}

ngOnInit(): void {
const deviceId: string = this.route.parent?.snapshot.parent?.params['id'];

this.pointsService.getPoints(deviceId).subscribe(({ data, loading }) => {
this.loading = loading;
this.points = data.device?.points ?? [];
});
}
}
22 changes: 22 additions & 0 deletions udmd/web/src/app/points/points.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export interface PointModel {
id: string;
name: string;
value: string;
units: string;
state: string;
}

export type Point = Partial<PointModel> | null;

export type PointsResponse = {
device: {
id: string;
points: Point[];
} | null;
};

export type PointsQueryResponse = PointsResponse;

export type PointsQueryVariables = {
id: string;
};
25 changes: 25 additions & 0 deletions udmd/web/src/app/points/points.gql.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { gql } from 'apollo-angular';

export const fragments = {
point: gql`
fragment Point on Point {
id
name
value
units
state
}
`,
};

export const GET_POINTS = gql`
query GetDevicePoints($id: ID!) {
device(id: $id) {
id
points {
...Point
}
}
}
${fragments.point}
`;
57 changes: 57 additions & 0 deletions udmd/web/src/app/points/points.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { TestBed } from '@angular/core/testing';
import { ApolloTestingController, ApolloTestingModule } from 'apollo-angular/testing';
import { GraphQLModule } from '../graphql/graphql.module';
import { GET_POINTS } from './points.gql';
import { PointsQueryResponse } from './points';
import { PointsService } from './points.service';

describe('PointsService', () => {
let service: PointsService;
let controller: ApolloTestingController;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [ApolloTestingModule, GraphQLModule],
});
service = TestBed.inject(PointsService);
controller = TestBed.inject(ApolloTestingController);
});

afterEach(() => {
controller.verify();
});

it('should be created', () => {
expect(service).toBeTruthy();
});

xit('should return the points', (done) => {
const mockDeviceResponse: PointsQueryResponse = {
device: {
id: '123',
points: [],
},
};

// Make some assertion about the result for once it's fulfilled.
service.getPoints('123').subscribe(({ data }) => {
expect(data).toEqual(mockDeviceResponse);
done();
});

// The following `expectOne()` will match the operation's document.
// If no requests or multiple requests matched that document
// `expectOne()` would throw.
const op = controller.expectOne(GET_POINTS);

// Assert the correct search options were sent.
expect(op.operation.variables).toEqual({
id: '123',
});

// Respond with mock data, causing Observable to resolve.
op.flush({
data: mockDeviceResponse,
});
});
});
27 changes: 27 additions & 0 deletions udmd/web/src/app/points/points.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Injectable } from '@angular/core';
import { Apollo } from 'apollo-angular';
import { GET_POINTS } from './points.gql';
import { QueryRef } from 'apollo-angular';
import { Observable } from 'rxjs';
import { ApolloQueryResult } from '@apollo/client/core';
import { PointsQueryResponse, PointsQueryVariables } from './points';

@Injectable({
providedIn: 'root',
})
export class PointsService {
devicesQuery!: QueryRef<PointsQueryResponse, PointsQueryVariables>;

constructor(private apollo: Apollo) {}

getPoints(deviceId: string): Observable<ApolloQueryResult<PointsQueryResponse>> {
this.devicesQuery = this.apollo.watchQuery<PointsQueryResponse, PointsQueryVariables>({
query: GET_POINTS,
variables: {
id: deviceId,
},
});

return this.devicesQuery.valueChanges;
}
}

0 comments on commit c6dc142

Please sign in to comment.