Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display points #53

Merged
merged 2 commits into from
Mar 16, 2022
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
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>({

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be

this.pointsQuery = ...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes, missed that from the copy-paste...i will re-work it regardless with ur new api to get points

query: GET_POINTS,
variables: {
id: deviceId,
},
});

return this.devicesQuery.valueChanges;
}
}