import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; import { HttpErrorResponse } from '@angular/common/http'; import { Component, ElementRef, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { MatSnackBar } from '@angular/material/snack-bar'; import { ActivatedRoute } from '@angular/router'; import { BaseWidget, Dashboard, DashboardService, PlotSize, PlotWidget, PlotWidgetRenderData, TextWidget } from 'src/app/dashboard.service'; import { PlotConfig, PlotRequest, PlotResponse, PlotService, RenderOptions } from 'src/app/plot.service'; import { AddPlotDialogComponent } from './add-plot-dialog/add-plot-dialog.component'; import { AddTextDialogComponent } from './add-text-dialog/add-text-dialog.component'; @Component({ selector: 'app-dashboard', templateUrl: './dashboard.component.html' }) export class DashboardComponent implements OnInit { dashboard?: Dashboard = undefined; error = ""; plotWidgetRenderData: PlotWidgetRenderData[] = []; constructor( private route: ActivatedRoute, private service: DashboardService, private dialog: MatDialog, private snackBar: MatSnackBar, private plotService: PlotService, private element: ElementRef) {} ngOnInit(): void { this.service.getDashboard(this.route.snapshot.paramMap.get("id")).subscribe({ 'next':(dashboard: Dashboard) => { this.dashboard = dashboard; this.repairArrangement(); dashboard.plots.forEach(p => { this.plotWidgetRenderData.push(new PlotWidgetRenderData(p)); }); this.loadImages(0, this.plotWidgetRenderData); }, 'error': (error: HttpErrorResponse) =>{ if (error.status == 404) { this.error = "Not Found"; }else if (error.status == 504) { // gateway timeout this.error = "Server Unreachable"; }else{ this.error = "Failed to load dashboard"; } } }); } loadImages(index: number, plotWidgetQueue: PlotWidgetRenderData[]) { if (index < plotWidgetQueue.length){ const plot = plotWidgetQueue[index]; const request = this.createPlotRequest(plot.widget) this.plotService.sendPlotRequest(request).subscribe({ next: (response: PlotResponse)=> { plot.plotResponse= response; }, error: (error:any)=> {}, complete: () => { this.loadImages(index +1 , plotWidgetQueue); } }); } } createPlotRequest(plotWidget: PlotWidget): PlotRequest { const height = this.height(plotWidget.size); const width = this.width(plotWidget.size); const fullWidth = window.innerWidth-30; const fullHeight = window.innerHeight-30; const request = new PlotRequest( (window).submitterId+crypto.randomUUID(), plotWidget.config, { 'main': new RenderOptions(height,width, false, true), 'fullScreen': new RenderOptions(fullHeight,fullWidth, false, true) } ); return request; } height(size: PlotSize): number{ switch (size) { case 'SMALL': return 300; case 'MEDIUM': return 400; case 'LARGE': return 600; } } width(size: PlotSize): number{ switch (size) { case 'SMALL': return 400; case 'MEDIUM': return 600; case 'LARGE': return 900; } } private repairArrangement(){ const arrangement = this.dashboard!.arrangement || []; if (arrangement.length == 0){ arrangement[0] = []; } this.dashboard?.texts.forEach(t => { if (!this.arrangmentContainsId(arrangement, t.id)){ arrangement[0].push(t.id); } }); this.dashboard?.plots.forEach(t => { if (!this.arrangmentContainsId(arrangement, t.id)){ arrangement[0].push(t.id); } }); this.dashboard!.arrangement = arrangement; } private arrangmentContainsId(arrangement: string[][], id: string): boolean{ for ( let i = 0; i < arrangement.length; i++){ if (arrangement[i].includes(id)) { return true; } } return false; } addText() { this.dialog.open(AddTextDialogComponent,{ width: '600px' }).afterClosed().subscribe((text: string) => { this.dashboard!.texts.push(new TextWidget(crypto.randomUUID(),'MEDIUM', text)); }); } addPlot() { this.dialog.open(AddPlotDialogComponent,{ width: 'calc(100% - 1em)', height: 'calc(100% - 1em)' }).afterClosed().subscribe((config: PlotConfig) => { this.dashboard!.plots.push(new PlotWidget(crypto.randomUUID(), 'MEDIUM', config)); }); } save() { const arrangement = []; const dashboardColumns = (this.element.nativeElement).querySelectorAll('.dashboard-column'); for(let i =0; i < dashboardColumns.length; i++){ const ids = []; const column = dashboardColumns.item(i); for(let c = 0; c column.children.item(c) const id = element!.getAttribute("widget-id"); if (id !== null) { ids.push(id); } } arrangement.push(ids); } this.dashboard!.arrangement = arrangement; this.service.saveDashboard(this.dashboard!).subscribe({ 'complete': () => { this.snackBar.open("saved dashboard","", { duration: 5000, verticalPosition: 'top' }); } }); } isTextWidget(id: string): boolean { return this.getTextWidget(id) !== undefined; } isPlotWidget(id: string): boolean { return this.dashboard?.plots.find( x => x.id == id) !== undefined; } getTextWidget(id: string): TextWidget | undefined { return this.dashboard?.texts.find( x => x.id == id); } getPlotWidget(id: string): PlotWidgetRenderData | undefined { return this.plotWidgetRenderData.find( x => x.widget.id == id); } drop(event: CdkDragDrop) { if (event.previousContainer === event.container) { moveItemInArray(event.container.data, event.previousIndex, event.currentIndex); } else { transferArrayItem( event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex, ); } } s(a: any){ return JSON.stringify(a); } }