From ae776ff8df5f381727701c07ae3d1b6e4779c71b Mon Sep 17 00:00:00 2001 From: Jesse Lucas Date: Fri, 10 Apr 2020 22:06:27 -0400 Subject: [PATCH] Rework device and folder service to have public obseravble to accomaccommodatemodate many subscribers without re-requesting data from the API --- src/app/charts/chart/chart.component.ts | 13 +- src/app/dashboard/dashboard.component.ts | 13 +- .../device-list/device-list.component.ts | 21 +++- .../folder-list/folder-list.component.ts | 18 ++- src/app/services/device.service.ts | 118 +++++++++--------- src/app/services/folder.service.ts | 43 ++++--- 6 files changed, 129 insertions(+), 97 deletions(-) diff --git a/src/app/charts/chart/chart.component.ts b/src/app/charts/chart/chart.component.ts index a4ce30012..d18189054 100644 --- a/src/app/charts/chart/chart.component.ts +++ b/src/app/charts/chart/chart.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ViewChild, Input } from '@angular/core'; +import { Component, OnInit, ViewChild, Input, Type } from '@angular/core'; import Folder from '../../folder' import { FolderService } from 'src/app/services/folder.service'; import { DonutChartComponent } from '../donut-chart/donut-chart.component'; @@ -6,6 +6,7 @@ import { DeviceService } from 'src/app/services/device.service'; import Device from 'src/app/device'; import { StType } from '../../type'; import { FilterService } from 'src/app/services/filter.service'; +import { Observable } from 'rxjs'; export interface ChartItemState { @@ -27,12 +28,12 @@ export class ChartComponent implements OnInit { chartID: string; states: ChartItemState[] = []; - private service: any; + private observer: Observable; private activeChartState: ChartItemState; constructor( private folderService: FolderService, - private deviceServce: DeviceService, + private deviceService: DeviceService, private filterService: FilterService, ) { } @@ -60,19 +61,19 @@ export class ChartComponent implements OnInit { case StType.Folder: this.title = "Folders"; this.chartID = 'foldersChart'; - this.service = this.folderService; + this.observer = this.folderService.folderAdded$; break; case StType.Device: this.title = "Devices"; this.chartID = 'devicesChart'; - this.service = this.deviceServce; + this.observer = this.deviceService.deviceAdded$; break; } } ngAfterViewInit() { let totalCount: number = 0; - this.service.getEach().subscribe( + this.observer.subscribe( t => { // Count the number of folders and set chart totalCount++; diff --git a/src/app/dashboard/dashboard.component.ts b/src/app/dashboard/dashboard.component.ts index 86f8b48f5..41d1fed61 100644 --- a/src/app/dashboard/dashboard.component.ts +++ b/src/app/dashboard/dashboard.component.ts @@ -14,6 +14,8 @@ import { MatProgressBar } from '@angular/material/progress-bar'; import { MessageService } from '../services/message.service'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { DialogComponent } from '../dialog/dialog.component'; +import { FolderService } from '../services/folder.service'; +import { DeviceService } from '../services/device.service'; @Component({ selector: 'app-dashboard', @@ -64,16 +66,21 @@ export class DashboardComponent implements OnInit, AfterViewInit { constructor( private systemConfigService: SystemConfigService, + private folderService: FolderService, + private deviceService: DeviceService, private progressService: ProgressService, private messageService: MessageService, public dialog: MatDialog ) { } ngOnInit() { + // Request data from Rest API this.systemConfigService.getSystemConfig().subscribe( - x => console.log('Observer got a next value: ' + x), - err => console.error('Observer got an error: ' + err), - () => console.log('Observer got a complete notification') + _ => { + // Request devices and folders for charts and lists + this.folderService.requestFolders(); + this.deviceService.requestDevices(); + } ); } diff --git a/src/app/lists/device-list/device-list.component.ts b/src/app/lists/device-list/device-list.component.ts index e5e7e4964..52361cc0e 100644 --- a/src/app/lists/device-list/device-list.component.ts +++ b/src/app/lists/device-list/device-list.component.ts @@ -8,6 +8,7 @@ import { SystemConfigService } from '../../services/system-config.service'; import { FilterService } from 'src/app/services/filter.service'; import { StType } from 'src/app/type'; import { MatInput } from '@angular/material/input'; +import { DeviceService } from 'src/app/services/device.service'; @Component({ selector: 'app-device-list', @@ -22,10 +23,10 @@ export class DeviceListComponent implements AfterViewInit, OnInit, OnDestroy { dataSource: MatTableDataSource; /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ - displayedColumns = ['id', 'name', 'state']; + displayedColumns = ['id', 'name', 'state', 'folders']; constructor( - private systemConfigService: SystemConfigService, + private deviceService: DeviceService, private filterService: FilterService, private cdr: ChangeDetectorRef, ) { }; @@ -41,9 +42,19 @@ export class DeviceListComponent implements AfterViewInit, OnInit, OnDestroy { this.dataSource = new MatTableDataSource(); this.dataSource.data = []; - this.systemConfigService.getDevices().subscribe( - data => { - this.dataSource.data = data; + // Replace all data when requests are finished + this.deviceService.devicesUpdated$.subscribe( + devices => { + this.dataSource.data = devices; + } + ); + + // Add device as they come in + let devices: Device[] = []; + this.deviceService.deviceAdded$.subscribe( + device => { + devices.push(device); + this.dataSource.data = devices; } ); } diff --git a/src/app/lists/folder-list/folder-list.component.ts b/src/app/lists/folder-list/folder-list.component.ts index df4f79eb5..bf24be2d5 100644 --- a/src/app/lists/folder-list/folder-list.component.ts +++ b/src/app/lists/folder-list/folder-list.component.ts @@ -25,7 +25,7 @@ export class FolderListComponent implements AfterViewInit, OnInit, OnDestroy { displayedColumns = ['id', 'label', 'path', 'state']; constructor( - private systemConfigService: SystemConfigService, + private folderService: FolderService, private filterService: FilterService, private cdr: ChangeDetectorRef, ) { @@ -41,11 +41,21 @@ export class FolderListComponent implements AfterViewInit, OnInit, OnDestroy { this.dataSource = new MatTableDataSource(); this.dataSource.data = []; - this.systemConfigService.getFolders().subscribe( - data => { - this.dataSource.data = data; + // Replace all data when requests are finished + this.folderService.foldersUpdated$.subscribe( + folders => { + this.dataSource.data = folders; } ); + + // Add device as they come in + let folders: Folder[] = []; + this.folderService.folderAdded$.subscribe( + folder => { + folders.push(folder); + this.dataSource.data = folders; + } + );; } ngAfterViewInit() { diff --git a/src/app/services/device.service.ts b/src/app/services/device.service.ts index 0570502b7..f7170b00d 100644 --- a/src/app/services/device.service.ts +++ b/src/app/services/device.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import Device from '../device'; -import { Observable, Subscriber } from 'rxjs'; +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'; @@ -15,7 +15,12 @@ import { StType } from '../type'; export class DeviceService { private devices: Device[]; private sysConns: SystemConnections; - thisDevice: Device; + private devicesSubject: ReplaySubject = new ReplaySubject(1); + devicesUpdated$ = this.devicesSubject.asObservable(); + private thisDevice: Device; + + private deviceAddedSource = new Subject(); + deviceAdded$ = this.deviceAddedSource.asObservable(); constructor( private systemConfigService: SystemConfigService, @@ -25,10 +30,12 @@ export class DeviceService { private progressService: ProgressService, ) { } - getDeviceStatusInOrder(observer: Subscriber, startIndex: number) { + getDeviceStatusInOrder(startIndex: number) { // Return if there aren't any device at the index if (startIndex >= (this.devices.length)) { - observer.complete(); + this.devicesSubject.next(this.devices); + // this.devicesSubject.complete(); + // this.deviceAddedSource.complete(); return; } const device: Device = this.devices[startIndex]; @@ -53,76 +60,73 @@ export class DeviceService { Device.recalcCompletion(device); device.stateType = Device.getStateType(device); device.state = Device.stateTypeToString(device.stateType); - observer.next(device); + this.deviceAddedSource.next(device); this.progressService.addToProgress(1); // recursively get the status of the next device - this.getDeviceStatusInOrder(observer, startIndex); + this.getDeviceStatusInOrder(startIndex); }); } /** * getEach() returns each device */ - getEach(): Observable { - const deviceObservable: Observable = new Observable((observer) => { - // TODO return devices if cached + requestDevices() { + this.systemConfigService.getDevices().subscribe( + devices => { + this.devices = devices; - 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; + } + }); - // 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 = []; + device.folderNames = []; + } - // 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; - 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); - // Add a reference to the folder to the device - device.folders.push(folder); - } - }); + // Add string folder name + device.folderNames.push(folder.label); + } }); }); - - // 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(observer, 0); - } - ); }); - } - ) - }, - err => { console.log("getEach error!", err) }, - () => { console.log("getEach complete!") } - ); - }); - return deviceObservable + + // 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); + } + ); + }); + } + ) + } + ); } } diff --git a/src/app/services/folder.service.ts b/src/app/services/folder.service.ts index a41b46436..1bb9cc73b 100644 --- a/src/app/services/folder.service.ts +++ b/src/app/services/folder.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { SystemConfigService } from './system-config.service'; -import { Observable, Subscriber } from 'rxjs'; +import { Observable, Subscriber, Subject, ReplaySubject } from 'rxjs'; import Folder from '../folder'; import { DbStatusService } from './db-status.service'; import { ProgressService } from './progress.service'; @@ -12,6 +12,10 @@ import { StType } from '../type'; }) export class FolderService { private folders: Folder[]; + private foldersSubject: ReplaySubject = new ReplaySubject(1); + foldersUpdated$ = this.foldersSubject.asObservable(); + private folderAddedSource = new Subject(); + folderAdded$ = this.folderAddedSource.asObservable(); constructor( private systemConfigService: SystemConfigService, @@ -20,10 +24,11 @@ export class FolderService { private progressService: ProgressService, ) { } - getFolderStatusInOrder(observer: Subscriber, startIndex: number) { + getFolderStatusInOrder(startIndex: number) { // Return if there aren't any folders at the index if (startIndex >= (this.folders.length)) { - observer.complete(); + this.foldersSubject.next(this.folders); + // this.folderAddedSource.complete(); return; } const folder: Folder = this.folders[startIndex]; @@ -37,37 +42,31 @@ export class FolderService { folder.completion = c; folder.stateType = Folder.getStateType(folder); folder.state = Folder.stateTypeToString(folder.stateType); - observer.next(folder); + this.folderAddedSource.next(folder); this.progressService.addToProgress(1); // recursively get the status of the next folder - this.getFolderStatusInOrder(observer, startIndex); + this.getFolderStatusInOrder(startIndex); }); } ); } /** - * getEach() returns each folder and uses db status service to + * requestFolders() requests each folder and uses db status service to * set all their statuses and db completion service to find - * completion + * completion in order. Updating folderAdded$ and foldersUpdate$ + * observers */ - getEach(): Observable { - // TODO return this.folders if cached + requestFolders() { + this.systemConfigService.getFolders().subscribe( + folders => { + this.folders = folders; - const folderObservable: Observable = new Observable((observer) => { - this.systemConfigService.getFolders().subscribe( - folders => { - this.folders = folders; - - // Synchronously get the status of each folder - this.getFolderStatusInOrder(observer, 0); - }, - err => { console.log("getEach error!", err) }, - () => { console.log("getEach complete!") } - ); - }); - return folderObservable; + // Synchronously get the status of each folder + this.getFolderStatusInOrder(0); + } + ); } } \ No newline at end of file