build: Add build process for newgui (#7351)

This commit is contained in:
Jakob Borg
2021-02-15 14:52:28 +01:00
parent d117b4b570
commit b2c9e7b07b
123 changed files with 38050 additions and 17178 deletions
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { CookieService } from './cookie.service';
describe('CookieService', () => {
let service: CookieService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(CookieService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,35 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class CookieService {
constructor() { }
getCookie(name: string): string {
let ca: Array<string> = document.cookie.split(';');
let caLen: number = ca.length;
let cookieName = `${name}=`;
let c: string;
for (let i: number = 0; i < caLen; i += 1) {
c = ca[i].replace(/^\s+/g, '');
if (c.indexOf(cookieName) == 0) {
return c.substring(cookieName.length, c.length);
}
}
return '';
}
deleteCookie(name): void {
this.setCookie(name, "", -1);
}
setCookie(name: string, value: string, expireDays: number, path: string = ""): void {
let d: Date = new Date();
d.setTime(d.getTime() + expireDays * 24 * 60 * 60 * 1000);
let expires: string = "expires=" + d.toUTCString();
document.cookie = name + "=" + value + "; " + expires + (path.length > 0 ? "; path=" + path : "");
}
}
@@ -0,0 +1,20 @@
import { TestBed } from '@angular/core/testing';
import { DbCompletionService } from './db-completion.service';
import { HttpClientModule } from '@angular/common/http';
describe('DbCompletionService', () => {
let service: DbCompletionService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
providers: [DbCompletionService]
});
service = TestBed.inject(DbCompletionService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,51 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { environment } from 'src/environments/environment';
import { apiURL } from '../api-utils';
import { Completion } from '../completion';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { StType } from '../type';
@Injectable({
providedIn: 'root'
})
export class DbCompletionService {
private dbStatusUrl = environment.production ? apiURL + 'rest/db/completion' : 'api/dbCompletion';
constructor(private http: HttpClient) { }
getCompletion(type: StType, id: string): Observable<Completion> {
let httpOptions: { params: HttpParams };
if (id) {
switch (type) {
case StType.Device:
httpOptions = {
params: new HttpParams().set('device', id)
};
break;
case StType.Folder:
httpOptions = {
params: new HttpParams().set('folder', id)
};
break;
}
} else { }
return this.http
.get<Completion>(this.dbStatusUrl, httpOptions)
.pipe(
map(res => {
// Remove from array in developement
// in-memory-web-api returns arrays
if (!environment.production) {
const a: any = res as any;
if (a.length > 0) {
res = res[0];
}
}
return res;
})
);
}
}
@@ -0,0 +1,21 @@
import { TestBed } from '@angular/core/testing';
import { DbStatusService } from './db-status.service';
import { HttpClientModule } from '@angular/common/http';
describe('DbStatusService', () => {
let service: DbStatusService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
providers: [DbStatusService]
});
TestBed.configureTestingModule({});
service = TestBed.inject(DbStatusService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,43 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { environment } from '../../environments/environment'
import { apiURL } from '../api-utils'
import Folder from '../folder'
@Injectable({
providedIn: 'root'
})
export class DbStatusService {
private dbStatusUrl = environment.production ? apiURL + 'rest/db/status' : 'api/dbStatus';
constructor(private http: HttpClient) { }
getFolderStatus(id: string): Observable<Folder.Status> {
let httpOptions: { params: HttpParams };
if (id) {
httpOptions = {
params: new HttpParams().set('folder', id)
};
} else { }
return this.http
.get<Folder.Status>(this.dbStatusUrl, httpOptions)
.pipe(
map(res => {
// Remove from array in developement
// in-memory-web-api returns arrays
if (!environment.production) {
const a: any = res as any;
if (a.length > 0) {
res = res[0];
}
}
return res;
})
);
}
}
@@ -0,0 +1,20 @@
import { TestBed } from '@angular/core/testing';
import { DeviceService } from './device.service';
import { HttpClientModule } from '@angular/common/http';
describe('DeviceService', () => {
let service: DeviceService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
providers: [DeviceService]
});
service = TestBed.inject(DeviceService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,128 @@
import { Injectable } from '@angular/core';
import Device from '../device';
import { Observable, Subscriber, ReplaySubject, Subject } from 'rxjs';
import { SystemConfigService } from './system-config.service';
import { SystemConnectionsService } from './system-connections.service';
import { DbCompletionService } from './db-completion.service';
import { SystemConnections } from '../connections';
import { SystemStatusService } from './system-status.service';
import { ProgressService } from './progress.service';
import { StType } from '../type';
@Injectable({
providedIn: 'root'
})
export class DeviceService {
private devices: Device[];
private sysConns: SystemConnections;
private devicesSubject: ReplaySubject<Device[]> = new ReplaySubject(1);
devicesUpdated$ = this.devicesSubject.asObservable();
private thisDevice: Device;
private deviceAddedSource = new Subject<Device>();
deviceAdded$ = this.deviceAddedSource.asObservable();
constructor(
private systemConfigService: SystemConfigService,
private systemConnectionsService: SystemConnectionsService,
private dbCompletionService: DbCompletionService,
private systemStatusService: SystemStatusService,
private progressService: ProgressService,
) { }
getDeviceStatusInOrder(startIndex: number) {
// Return if there aren't any device at the index
if (startIndex >= (this.devices.length)) {
this.devicesSubject.next(this.devices);
// this.devicesSubject.complete();
// this.deviceAddedSource.complete();
return;
}
const device: Device = this.devices[startIndex];
startIndex = startIndex + 1;
// Check if device in the connections
if (this.sysConns.connections[device.deviceID] === undefined) {
device.stateType = Device.StateType.Unknown;
} else {
// Set connected
device.connected = this.sysConns.connections[device.deviceID].connected;
// TODO ? temporarily set to connected
if (device.deviceID === this.thisDevice.deviceID) {
device.connected = true;
}
}
this.dbCompletionService.getCompletion(StType.Device, device.deviceID).subscribe(
c => {
device.completion = c;
Device.recalcCompletion(device);
device.stateType = Device.getStateType(device);
device.state = Device.stateTypeToString(device.stateType);
this.deviceAddedSource.next(device);
this.progressService.addToProgress(1);
// recursively get the status of the next device
this.getDeviceStatusInOrder(startIndex);
});
}
/**
* getEach() returns each device
*/
requestDevices() {
this.systemConfigService.getDevices().subscribe(
devices => {
this.devices = devices;
// First check to see which device is local 'thisDevice'
this.systemStatusService.getSystemStatus().subscribe(
status => {
this.devices.forEach(device => {
if (device.deviceID === status.myID) {
// TODO Determine if it should ignore thisDevice
this.thisDevice = device;
}
});
// Check folder devices to see if the device is used
this.systemConfigService.getFolders().subscribe(
folders => {
// Loop through all folder devices to see if the device is used
this.devices.forEach(device => {
// Alloc array if needed
if (!device.folders) {
device.folders = [];
}
folders.forEach(folder => {
folder.devices.forEach(fdevice => {
if (device.deviceID === fdevice.deviceID) {
// The device is used by a folder
device.used = true;
// Add a reference to the folder to the device
device.folders.push(folder);
}
});
});
});
// See if the connection is connected or undefined
this.systemConnectionsService.getSystemConnections().subscribe(
c => {
this.sysConns = c;
// Synchronously get the status of each device
this.getDeviceStatusInOrder(0);
}
);
});
}
)
}
);
}
}
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { FilterService } from './filter.service';
describe('FilterService', () => {
let service: FilterService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(FilterService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,30 @@
import { Injectable } from '@angular/core';
import { StType } from '../type';
import { Subject } from 'rxjs';
export interface FilterInput {
type: StType;
text: string
}
@Injectable({
providedIn: 'root'
})
export class FilterService {
previousInputs = new Map<StType, string>(
[
[StType.Folder, ""],
[StType.Device, ""],
]
)
constructor() { }
private filterChangeSource = new Subject<FilterInput>();
filterChanged$ = this.filterChangeSource.asObservable();
changeFilter(input: FilterInput) {
this.previousInputs.set(input.type, input.text)
this.filterChangeSource.next(input);
}
}
@@ -0,0 +1,20 @@
import { TestBed } from '@angular/core/testing';
import { FolderService } from './folder.service';
import { HttpClientModule } from '@angular/common/http';
describe('FolderService', () => {
let service: FolderService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
providers: [FolderService]
});
service = TestBed.inject(FolderService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,98 @@
import { Injectable } from '@angular/core';
import { SystemConfigService } from './system-config.service';
import { Observable, Subscriber, Subject, ReplaySubject } from 'rxjs';
import Folder from '../folder';
import { DbStatusService } from './db-status.service';
import { ProgressService } from './progress.service';
import { DbCompletionService } from './db-completion.service';
import { StType } from '../type';
import { DeviceService } from './device.service';
@Injectable({
providedIn: 'root'
})
export class FolderService {
private folders: Folder[];
private foldersSubject: ReplaySubject<Folder[]> = new ReplaySubject(1);
foldersUpdated$ = this.foldersSubject.asObservable();
private folderAddedSource = new Subject<Folder>();
folderAdded$ = this.folderAddedSource.asObservable();
constructor(
private systemConfigService: SystemConfigService,
private deviceService: DeviceService,
private dbStatusService: DbStatusService,
private dbCompletionService: DbCompletionService,
private progressService: ProgressService,
) { }
getFolderStatusInOrder(startIndex: number) {
// Return if there aren't any folders at the index
if (startIndex >= (this.folders.length)) {
this.foldersSubject.next(this.folders);
// this.folderAddedSource.complete();
return;
}
const folder: Folder = this.folders[startIndex];
startIndex = startIndex + 1;
// Folder devices array only has deviceID
// and we want all the device info
this.systemConfigService.getDevices().subscribe(
devices => {
devices.forEach(device => {
// Update any device this folder
// has reference to
folder.devices.forEach((folderDevice, index) => {
if (folderDevice.deviceID === device.deviceID) {
console.log("find device match?", device.name)
folder.devices[index] = device;
console.log("update?", folder.devices);
}
});
});
// Gather the folder information from the status and
// completion services
this.dbStatusService.getFolderStatus(folder.id).subscribe(
status => {
folder.status = status;
this.dbCompletionService.getCompletion(StType.Folder, folder.id).subscribe(
c => {
folder.completion = c;
folder.stateType = Folder.getStateType(folder);
folder.state = Folder.stateTypeToString(folder.stateType);
this.folderAddedSource.next(folder);
this.progressService.addToProgress(1);
// Now that we have all the folder information
// recursively get the status of the next folder
this.getFolderStatusInOrder(startIndex);
});
}
);
}
)
}
/**
* requestFolders() requests each folder and uses db status service to
* set all their statuses and db completion service to find
* completion in order. Updating folderAdded$ and foldersUpdate$
* observers
*/
requestFolders() {
this.systemConfigService.getFolders().subscribe(
folders => {
this.folders = folders;
// Synchronously get the status of each folder
this.getFolderStatusInOrder(0);
}
);
}
}
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { InMemoryConfigDataService } from './in-memory-config-data.service';
describe('InMemoryDataService', () => {
let service: InMemoryConfigDataService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(InMemoryConfigDataService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,17 @@
import { Injectable } from '@angular/core';
import { config } from '../mocks/mock-system-config';
import { dbStatus } from '../mocks/mock-db-status';
import { connections } from '../mocks/mock-system-connections';
import { dbCompletion } from '../mocks/mock-db-completion';
import { systemStatus } from '../mocks/mock-system-status';
@Injectable({
providedIn: 'root'
})
export class InMemoryConfigDataService {
createDb() {
return { config, dbStatus, connections, dbCompletion, systemStatus };
}
constructor() { }
}
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { MessageService } from './message.service';
describe('MessageService', () => {
let service: MessageService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(MessageService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,20 @@
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class MessageService {
messages: string[] = [];
private messageAddedSource = new Subject<string>();
messageAdded$ = this.messageAddedSource.asObservable();
add(message: string) {
this.messages.push(message);
this.messageAddedSource.next(message);
}
clear() {
this.messages = [];
}
}
@@ -0,0 +1,40 @@
import { TestBed } from '@angular/core/testing';
import { ProgressService } from './progress.service';
import { stringToKeyValue } from '@angular/flex-layout/extended/typings/style/style-transforms';
describe('ProgressService', () => {
let service: ProgressService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ProgressService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('#percentValue should return 0 - 100', () => {
interface iTest {
total: number,
progress: number,
expected: number,
}
const tests: Map<string, iTest> = new Map([
["default", { total: 0, progress: 0, expected: 0 }],
["NaN return 0", { total: 0, progress: 100, expected: 0 }],
["greater than 100 return 100", { total: 10, progress: 100, expected: 100 }],
["valid", { total: 100, progress: 100, expected: 100 }],
["valid", { total: 100, progress: 50, expected: 50 }],
["test floor", { total: 133, progress: 41, expected: 30 }],
]);
service = new ProgressService();
for (let test of tests.values()) {
service.total = test.total;
service.updateProgress(test.progress);
expect(service.percentValue).toBe(test.expected);
}
});
});
@@ -0,0 +1,50 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ProgressService {
private progress: number = 0;
private _total: number = 0;
set total(t: number) {
this._total = t;
}
get percentValue(): number {
let p: number = Math.floor((this.progress / this._total) * 100);
if (p < 0 || isNaN(p) || p === Infinity) {
p = 0;
} else if (p > 100) {
p = 100;
}
return p;
}
constructor() { }
addToProgress(n: number) {
if (n < 0 || isNaN(n) || n === Infinity) {
n = 0;
}
this.progress += n;
}
updateProgress(n: number) {
if (n < 0 || isNaN(n) || n === Infinity) {
n = 0
} else if (n > 100) {
n = 100
}
this.progress = n;
}
isComplete(): boolean {
if (this.progress >= this._total && this.progress > 0 && this._total > 0) {
return true;
}
return false;
}
}
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { RequestCacheService } from './request-cache.service';
describe('RequestCacheService', () => {
let service: RequestCacheService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(RequestCacheService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,50 @@
import { Injectable } from '@angular/core';
import { HttpResponse, HttpRequest } from '@angular/common/http';
export interface RequestCacheEntry {
url: string;
response: HttpResponse<any>;
lastRead: number;
}
const maxAge = 30000; // milliseconds
@Injectable({
providedIn: 'root'
})
export class RequestCacheService {
private cache: Map<string, RequestCacheEntry> = new Map();
constructor() { }
get(req: HttpRequest<any>): HttpResponse<any> | undefined {
const url = req.urlWithParams;
const cached = this.cache.get(url);
if (!cached) {
return undefined;
}
const isExpired = cached.lastRead < (Date.now() - maxAge);
return isExpired ? undefined : cached.response;
}
put(req: HttpRequest<any>, response: HttpResponse<any>): void {
const url = req.urlWithParams;
const entry = { url, response, lastRead: Date.now() };
this.cache.set(url, entry);
// Remove expired cache entries
const expired = Date.now() - maxAge;
this.cache.forEach(entry => {
if (entry.lastRead < expired) {
this.cache.delete(entry.url);
}
});
}
clearAll(): void {
this.cache = new Map();
}
}
@@ -0,0 +1,20 @@
import { TestBed } from '@angular/core/testing';
import { SystemConfigService } from './system-config.service';
import { HttpClientModule } from '@angular/common/http';
describe('SystemConfigService', () => {
let service: SystemConfigService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
providers: [SystemConfigService]
});
service = TestBed.inject(SystemConfigService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,55 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, ReplaySubject } from 'rxjs';
import { map } from 'rxjs/operators';
import Folder from '../folder';
import Device from '../device';
import { environment } from '../../environments/environment'
import { apiURL } from '../api-utils'
import { ProgressService } from './progress.service';
@Injectable({
providedIn: 'root'
})
export class SystemConfigService {
private folders: Folder[];
private devices: Device[];
private foldersSubject: ReplaySubject<Folder[]> = new ReplaySubject(1);
private devicesSubject: ReplaySubject<Device[]> = new ReplaySubject(1);
private systemConfigUrl = environment.production ? apiURL + 'rest/system/config' : 'api/config';
constructor(
private http: HttpClient,
private progressService: ProgressService,
) { }
getSystemConfig(): Observable<any> {
return this.http
.get(this.systemConfigUrl)
.pipe(
map(res => {
this.folders = res['folders'];
this.devices = res['devices'];
// Set the total for the progress service
this.progressService.total = this.folders.length + this.devices.length;
this.foldersSubject.next(this.folders);
this.devicesSubject.next(this.devices);
return res;
})
);
}
getFolders(): Observable<Folder[]> {
return this.foldersSubject.asObservable();
}
getDevices(): Observable<Device[]> {
return this.devicesSubject.asObservable();
}
}
@@ -0,0 +1,20 @@
import { TestBed } from '@angular/core/testing';
import { SystemConnectionsService } from './system-connections.service';
import { HttpClientModule } from '@angular/common/http';
describe('SystemConnectionsService', () => {
let service: SystemConnectionsService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
providers: [SystemConnectionsService]
});
service = TestBed.inject(SystemConnectionsService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,26 @@
import { Injectable } from '@angular/core';
import { environment } from 'src/environments/environment';
import { apiURL } from '../api-utils';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { SystemConnections } from '../connections';
@Injectable({
providedIn: 'root'
})
export class SystemConnectionsService {
private systemConfigUrl = environment.production ? apiURL + 'rest/system/connections' : 'api/connections';
constructor(private http: HttpClient) { }
getSystemConnections(): Observable<SystemConnections> {
return this.http
.get<SystemConnections>(this.systemConfigUrl)
.pipe(
map(res => {
return res;
})
);
}
}
@@ -0,0 +1,20 @@
import { TestBed } from '@angular/core/testing';
import { SystemStatusService } from './system-status.service';
import { HttpClientModule } from '@angular/common/http';
describe('SystemStatusService', () => {
let service: SystemStatusService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
providers: [SystemStatusService]
});
service = TestBed.inject(SystemStatusService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,27 @@
import { Injectable } from '@angular/core';
import { environment } from 'src/environments/environment';
import { apiURL } from '../api-utils';
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { SystemStatus } from '../system-status';
@Injectable({
providedIn: 'root'
})
export class SystemStatusService {
private systemStatusUrl = environment.production ? apiURL + 'rest/system/status' : 'api/systemStatus';
constructor(private http: HttpClient) { }
getSystemStatus(): Observable<SystemStatus> {
return this.http
.get<SystemStatus>(this.systemStatusUrl)
.pipe(
map(res => {
return res;
})
);
}
}