From b5028e03be5ba72f687cc6c6dc358bdf4f537a2c Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Sun, 12 Mar 2023 08:24:16 +0100 Subject: [PATCH] edit plots --- pdb-js/.vscode/settings.json | 2 + .../dashboard-page.component.html | 8 +- .../add-plot-dialog.component.html | 6 +- .../add-plot-dialog.component.scss | 0 .../add-plot-dialog.component.ts | 15 ++-- .../dashboard/dashboard.component.ts | 24 +++--- .../plot-widget/plot-widget.component.html | 17 ++++- .../plot-widget/plot-widget.component.ts | 34 ++++++++- .../new-dashboard.component.html | 5 ++ .../new-dashboard.component.scss | 4 - .../new-dashboard/new-dashboard.component.ts | 5 +- pdb-js/src/app/dashboard.service.ts | 43 ++++++++++- .../src/app/limit-by/limit-by.component.html | 1 + pdb-js/src/app/plot.service.ts | 21 ++---- .../query-autocomplete.component.ts | 49 ++++++------ .../visualization-page.component.html | 2 +- .../visualization-page.component.scss | 6 +- .../visualization-page.component.ts | 74 ++++++++++++++----- pdb-js/src/index.html | 3 - 19 files changed, 222 insertions(+), 97 deletions(-) create mode 100644 pdb-js/.vscode/settings.json delete mode 100644 pdb-js/src/app/dashboard-page/dashboard/add-plot-dialog/add-plot-dialog.component.scss delete mode 100644 pdb-js/src/app/dashboard-page/new-dashboard/new-dashboard.component.scss diff --git a/pdb-js/.vscode/settings.json b/pdb-js/.vscode/settings.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/pdb-js/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/pdb-js/src/app/dashboard-page/dashboard-page.component.html b/pdb-js/src/app/dashboard-page/dashboard-page.component.html index 5180498..f543151 100644 --- a/pdb-js/src/app/dashboard-page/dashboard-page.component.html +++ b/pdb-js/src/app/dashboard-page/dashboard-page.component.html @@ -1,14 +1,8 @@ -

Add Plot

+

{{data.title}}

- +
- +
diff --git a/pdb-js/src/app/dashboard-page/dashboard/add-plot-dialog/add-plot-dialog.component.scss b/pdb-js/src/app/dashboard-page/dashboard/add-plot-dialog/add-plot-dialog.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/pdb-js/src/app/dashboard-page/dashboard/add-plot-dialog/add-plot-dialog.component.ts b/pdb-js/src/app/dashboard-page/dashboard/add-plot-dialog/add-plot-dialog.component.ts index c3e4fb8..4ef930e 100644 --- a/pdb-js/src/app/dashboard-page/dashboard/add-plot-dialog/add-plot-dialog.component.ts +++ b/pdb-js/src/app/dashboard-page/dashboard/add-plot-dialog/add-plot-dialog.component.ts @@ -1,17 +1,22 @@ -import { Component, ElementRef, ViewChild } from '@angular/core'; -import { MatDialogRef } from '@angular/material/dialog'; +import { AfterViewInit, Component, ElementRef, Inject, ViewChild } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { PlotConfig } from 'src/app/plot.service'; import { VisualizationPageComponent } from 'src/app/visualization-page/visualization-page.component'; @Component({ selector: 'app-add-plot-dialog', - templateUrl: './add-plot-dialog.component.html', - styleUrls: ['./add-plot-dialog.component.scss'] + templateUrl: './add-plot-dialog.component.html' }) export class AddPlotDialogComponent { @ViewChild("plot") plotElement! :VisualizationPageComponent; - constructor(public dialogRef: MatDialogRef){ + + + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: {config: PlotConfig, title: string} + ){ } onSaveClick(): void { diff --git a/pdb-js/src/app/dashboard-page/dashboard/dashboard.component.ts b/pdb-js/src/app/dashboard-page/dashboard/dashboard.component.ts index 5c3752e..d179105 100644 --- a/pdb-js/src/app/dashboard-page/dashboard/dashboard.component.ts +++ b/pdb-js/src/app/dashboard-page/dashboard/dashboard.component.ts @@ -58,20 +58,20 @@ export class DashboardComponent implements OnInit { 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); - } - }); + const request = PlotWidget.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); @@ -111,6 +111,7 @@ export class DashboardComponent implements OnInit { return 900; } } + */ private repairArrangement(){ const arrangement = this.dashboard!.arrangement || []; @@ -153,6 +154,7 @@ export class DashboardComponent implements OnInit { addPlot() { this.dialog.open(AddPlotDialogComponent,{ + data: {title: "Add Plot"}, width: 'calc(100% - 1em)', height: 'calc(100% - 1em)' }).afterClosed().subscribe((config: PlotConfig | "") => { diff --git a/pdb-js/src/app/dashboard-page/dashboard/plot-widget/plot-widget.component.html b/pdb-js/src/app/dashboard-page/dashboard/plot-widget/plot-widget.component.html index cd5274c..edebe8a 100644 --- a/pdb-js/src/app/dashboard-page/dashboard/plot-widget/plot-widget.component.html +++ b/pdb-js/src/app/dashboard-page/dashboard/plot-widget/plot-widget.component.html @@ -3,7 +3,7 @@ float: left; } .dashboard-card { - border: solid 1px red; + position: relative; display: flex; justify-content: center; align-items: center; @@ -19,8 +19,23 @@ img { cursor: zoom-in; } + + + .editable-hovered { + position: absolute; + right: 0; + top: 0; + } + + .dashboard-card .editable-hovered { + visibility: hidden; + } + .dashboard-card:hover .editable-hovered { + visibility: visible; + }
+
diff --git a/pdb-js/src/app/dashboard-page/dashboard/plot-widget/plot-widget.component.ts b/pdb-js/src/app/dashboard-page/dashboard/plot-widget/plot-widget.component.ts index c6ca11f..56c1ca0 100644 --- a/pdb-js/src/app/dashboard-page/dashboard/plot-widget/plot-widget.component.ts +++ b/pdb-js/src/app/dashboard-page/dashboard/plot-widget/plot-widget.component.ts @@ -1,8 +1,9 @@ import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { PlotWidget, PlotWidgetRenderData } from 'src/app/dashboard.service'; +import { PlotSize, PlotWidget, PlotWidgetRenderData } from 'src/app/dashboard.service'; import { PlotViewComponent } from 'src/app/plot-view/plot-view.component'; -import { PlotRequest, PlotResponse, PlotService, RenderOptions } from 'src/app/plot.service'; +import { PlotConfig, PlotRequest, PlotResponse, PlotService, RenderOptions } from 'src/app/plot.service'; +import { AddPlotDialogComponent } from '../add-plot-dialog/add-plot-dialog.component'; import { FullScreenPlotDialogComponent } from '../full-screen-plot-dialog/full-screen-plot-dialog.component'; @Component({ @@ -19,7 +20,7 @@ export class PlotWidgetComponent implements AfterViewInit { @ViewChild("plotView") plotView!: PlotViewComponent; - constructor(private dialog: MatDialog, ){} + constructor(private dialog: MatDialog, private service: PlotService){} ngAfterViewInit(): void { @@ -44,4 +45,31 @@ export class PlotWidgetComponent implements AfterViewInit { }); } + + + + edit() { + this.dialog.open(AddPlotDialogComponent, { + data: {config: this.data.widget.config, title:"Edit Plot"}, + width: 'calc(100% - 15px)', + height: 'calc(100% - 15px)', + }).afterClosed().subscribe((config?: PlotConfig) => { + if (config !== undefined && config.query.length > 0) { + this.data.widget.config = config; + + this.isError = false; + this.data.plotResponse = undefined; + + const request = PlotWidget.createPlotRequest(this.data.widget); + this.service.sendPlotRequest(request).subscribe({ + next: (response: PlotResponse)=> { + this.data.plotResponse = response; + }, + error: (error:any)=> { + this.isError = true; + }, + }); + } + }); + } } diff --git a/pdb-js/src/app/dashboard-page/new-dashboard/new-dashboard.component.html b/pdb-js/src/app/dashboard-page/new-dashboard/new-dashboard.component.html index dacad21..f4d3b5b 100644 --- a/pdb-js/src/app/dashboard-page/new-dashboard/new-dashboard.component.html +++ b/pdb-js/src/app/dashboard-page/new-dashboard/new-dashboard.component.html @@ -1,3 +1,8 @@ +

Create a new dashboard

diff --git a/pdb-js/src/app/dashboard-page/new-dashboard/new-dashboard.component.scss b/pdb-js/src/app/dashboard-page/new-dashboard/new-dashboard.component.scss deleted file mode 100644 index 59b9cec..0000000 --- a/pdb-js/src/app/dashboard-page/new-dashboard/new-dashboard.component.scss +++ /dev/null @@ -1,4 +0,0 @@ - -div[mat-dialog-content] { - overflow: hidden; -} \ No newline at end of file diff --git a/pdb-js/src/app/dashboard-page/new-dashboard/new-dashboard.component.ts b/pdb-js/src/app/dashboard-page/new-dashboard/new-dashboard.component.ts index e660232..faeabf4 100644 --- a/pdb-js/src/app/dashboard-page/new-dashboard/new-dashboard.component.ts +++ b/pdb-js/src/app/dashboard-page/new-dashboard/new-dashboard.component.ts @@ -1,11 +1,10 @@ import { Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core'; -import {MatDialog, MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import { DashboardCreationData } from 'src/app/dashboard.service'; @Component({ selector: 'app-new-dashboard', - templateUrl: './new-dashboard.component.html', - styleUrls: ['./new-dashboard.component.scss'] + templateUrl: './new-dashboard.component.html' }) export class NewDashboardComponent implements OnInit { diff --git a/pdb-js/src/app/dashboard.service.ts b/pdb-js/src/app/dashboard.service.ts index 14ab4de..8a55b05 100644 --- a/pdb-js/src/app/dashboard.service.ts +++ b/pdb-js/src/app/dashboard.service.ts @@ -1,7 +1,7 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { PlotConfig, PlotResponse } from './plot.service'; +import { PlotConfig, PlotRequest, PlotResponse, RenderOptions } from './plot.service'; @Injectable({ providedIn: 'root' @@ -67,6 +67,47 @@ export class PlotWidget extends BaseWidget { constructor(override id: string, override size: 'SMALL'|'MEDIUM'|'LARGE', public config: PlotConfig) { super(id, 'PLOT', size); } + + public static createPlotRequest(widget: PlotWidget): PlotRequest { + + const height = this.height(widget.size); + const width = this.width(widget.size); + + const fullWidth = window.innerWidth-30; + const fullHeight = window.innerHeight-30; + + const request = new PlotRequest( + (window).submitterId+crypto.randomUUID(), + widget.config, + { + 'main': new RenderOptions(height,width, false, true), + 'fullScreen': new RenderOptions(fullHeight,fullWidth, false, true) + } + ); + return request; + } + + + static height(size: PlotSize): number{ + switch (size) { + case 'SMALL': + return 300; + case 'MEDIUM': + return 400; + case 'LARGE': + return 600; + } + } + static width(size: PlotSize): number{ + switch (size) { + case 'SMALL': + return 400; + case 'MEDIUM': + return 600; + case 'LARGE': + return 900; + } + } } export type PlotSize = 'SMALL'|'MEDIUM'|'LARGE'; diff --git a/pdb-js/src/app/limit-by/limit-by.component.html b/pdb-js/src/app/limit-by/limit-by.component.html index 5ba3622..2390897 100644 --- a/pdb-js/src/app/limit-by/limit-by.component.html +++ b/pdb-js/src/app/limit-by/limit-by.component.html @@ -17,6 +17,7 @@ + ) : boolean { diff --git a/pdb-js/src/app/query-autocomplete/query-autocomplete.component.ts b/pdb-js/src/app/query-autocomplete/query-autocomplete.component.ts index 69a8e4a..371161c 100644 --- a/pdb-js/src/app/query-autocomplete/query-autocomplete.component.ts +++ b/pdb-js/src/app/query-autocomplete/query-autocomplete.component.ts @@ -1,5 +1,5 @@ -import { Component, OnInit, Input, ViewChild } from '@angular/core'; -import {UntypedFormControl} from '@angular/forms'; +import { Component, OnInit, Input, ViewChild, AfterViewInit } from '@angular/core'; +import {FormControl, UntypedFormControl} from '@angular/forms'; import {Observable} from 'rxjs'; import {startWith, map} from 'rxjs/operators'; import {MatAutocompleteTrigger } from '@angular/material/autocomplete'; @@ -12,41 +12,48 @@ import { PlotService, PlotType, AutocompleteResult, Suggestion, ResultMode } fro }) export class QueryAutocompleteComponent implements OnInit { - queryField = new UntypedFormControl(''); + queryField = new FormControl(new Suggestion("","",0)); suggestions = new UntypedFormControl(); filteredSuggestions!: Observable; query : string = ""; + + suggestionFetcherEnabled = true; @ViewChild(MatAutocompleteTrigger) autocomplete!: MatAutocompleteTrigger; - constructor(private plotService: PlotService) {} + constructor(private plotService: PlotService) { + } ngOnInit() { - const that = this; this.query = ""; - this.queryField.valueChanges.subscribe(function(value){ - if (typeof value == "string") { - that.query = value; - }else{ - that.query = value.newQuery; + this.queryField.valueChanges.subscribe((value) =>{ + if (value != null) { + if (typeof value == "string") { + this.query = value; + }else{ + this.query = value.newQuery; + + const el : HTMLInputElement = document.getElementById('query-autocomplete-input'); + el.selectionStart=value.newCaretPosition; + el.selectionEnd=value.newCaretPosition; + } - var el : HTMLInputElement = document.getElementById('query-autocomplete-input'); - el.selectionStart=value.newCaretPosition; - el.selectionEnd=value.newCaretPosition; - that.fetchSuggestions(value.newCaretPosition); + if (this.suggestionFetcherEnabled) { + this.fetchSuggestions(value.newCaretPosition); + } } }); this.filteredSuggestions = this.suggestions.valueChanges.pipe( map(value => value) ); } - + onKey(event: any) { //console.log(event); if (event.key == "ArrowDown" || event.key == "ArrowUp"){ @@ -61,23 +68,21 @@ export class QueryAutocompleteComponent implements OnInit { const that = this; const query = typeof this.queryField.value == "string" ? this.queryField.value - : this.queryField.value.newQuery; + : this.queryField.value!.newQuery; this.plotService .autocomplete(query, caretIndex, ResultMode.CUT_AT_DOT) - .subscribe( - (data: AutocompleteResult) => {// success path - //console.log(JSON.stringify(data.proposals)); + .subscribe({ + next: (data: AutocompleteResult) => { that.suggestions.setValue(data.proposals); - that.autocomplete.openPanel(); }, - (error:any) => console.log(error) + error: (error:any) => console.log(error) + } ); } displaySuggestion(suggestion?: Suggestion): string { - //console.log("suggestion: "+JSON.stringify(suggestion)); return suggestion ? suggestion.newQuery : ''; } } diff --git a/pdb-js/src/app/visualization-page/visualization-page.component.html b/pdb-js/src/app/visualization-page/visualization-page.component.html index 91c9c30..29735e4 100644 --- a/pdb-js/src/app/visualization-page/visualization-page.component.html +++ b/pdb-js/src/app/visualization-page/visualization-page.component.html @@ -52,7 +52,7 @@ - Gallery + Gallery Split By: diff --git a/pdb-js/src/app/visualization-page/visualization-page.component.scss b/pdb-js/src/app/visualization-page/visualization-page.component.scss index 7bda29b..6d6b50a 100644 --- a/pdb-js/src/app/visualization-page/visualization-page.component.scss +++ b/pdb-js/src/app/visualization-page/visualization-page.component.scss @@ -15,11 +15,11 @@ grid: "query-box query-box date-box" auto "filters results results" 1fr - / 25.5em 3fr 24em; + / 25.5em 3fr 23.5em; } } -@media screen and (max-width: 1000px) { +@media screen and (max-width: 900px) { #visualization { display: grid; margin: 0; @@ -27,7 +27,7 @@ grid: "query-box" auto "date-box" auto - "filters" auto + "filters" min-content "results" 1fr / 1fr; } diff --git a/pdb-js/src/app/visualization-page/visualization-page.component.ts b/pdb-js/src/app/visualization-page/visualization-page.component.ts index b47b543..4e54369 100644 --- a/pdb-js/src/app/visualization-page/visualization-page.component.ts +++ b/pdb-js/src/app/visualization-page/visualization-page.component.ts @@ -1,13 +1,12 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; -import { PlotService, PlotType, PlotRequest, PlotResponse, TagField, FilterDefaults, DataType, YAxisDefinition, AxesTypes, PlotConfig, RenderOptions, RenderOptionsMap } from '../plot.service'; -import { UntypedFormControl, Validators } from '@angular/forms'; +import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core'; +import { PlotService, PlotType, PlotRequest, TagField, FilterDefaults, DataType, AxesTypes, PlotConfig, RenderOptions, RenderOptionsMap, Suggestion } from '../plot.service'; +import { UntypedFormControl, } from '@angular/forms'; import { MatSnackBar } from '@angular/material/snack-bar'; import { LimitByComponent } from '../limit-by/limit-by.component'; import { YAxisDefinitionComponent } from '../y-axis-definition/y-axis-definition.component'; import { QueryAutocompleteComponent } from '../query-autocomplete/query-autocomplete.component'; -import { PlotViewComponent, SelectionRange, DateAnchor, LoadingEvent } from '../plot-view/plot-view.component'; +import { PlotViewComponent, LoadingEvent } from '../plot-view/plot-view.component'; import { GalleryViewComponent } from '../gallery-view/gallery-view.component'; -import * as moment from 'moment'; import { WidgetDimensions } from '../dashboard.service'; @Component({ @@ -15,14 +14,20 @@ import { WidgetDimensions } from '../dashboard.service'; templateUrl: './visualization-page.component.html', styleUrls: ['./visualization-page.component.scss'] }) -export class VisualizationPageComponent implements OnInit { +export class VisualizationPageComponent implements OnInit, AfterViewInit { readonly DATE_PATTERN = "YYYY-MM-DD HH:mm:ss"; // for moment-JS + + @Input() + defaultConfig?: PlotConfig; + + @Input() + galleryEnabled = true; dateRange = new UntypedFormControl('2019-10-05 00:00:00 - 2019-10-11 23:59:59'); selectedPlotType = new Array(); - plotTypes: Array = []; + plotTypes: PlotType[] = []; tagFields: Array = new Array(); @@ -68,33 +73,68 @@ export class VisualizationPageComponent implements OnInit { } ngOnInit() { - const that = this; (window).initDatePicker(); this.plotTypes = this.plotService.getPlotTypes(); this.selectedPlotType.push(this.plotTypes[0]); - that.plotService.getFilterDefaults().subscribe(function(filterDefaults: FilterDefaults) { + this.plotService.getFilterDefaults().subscribe((filterDefaults: FilterDefaults) => { - filterDefaults.fields.forEach(function(name:string) { - that.tagFields.push(new TagField(name)); + filterDefaults.fields.forEach((name:string) => { + this.tagFields.push(new TagField(name)); }, (error: any) => { - that.showError(error.error.message); + this.showError(error.error.message); }); - that.groupBy = that.tagFields.filter(val => filterDefaults.groupBy.includes(val.name)); - that.splitBy = that.tagFields.find(val => filterDefaults.splitBy == val.name); - }); + const groupByDefaults = this.defaultConfig ? this.defaultConfig.groupBy : filterDefaults.groupBy; + this.groupBy = this.tagFields.filter(val => groupByDefaults.includes(val.name)); + this.splitBy = this.tagFields.find(val => filterDefaults.splitBy == val.name); + + if (this.defaultConfig) { + this.plot(); + } + }); + + } + +ngAfterViewInit(): void { + if (this.defaultConfig) { + const c = this.defaultConfig; + this.query.suggestionFetcherEnabled = false; + this.query.queryField.setValue(new Suggestion(c.query, c.query, c.query.length)); + this.query.suggestionFetcherEnabled = true; + + this.selectedPlotType = this.plotTypes.filter(pt => c.aggregates.includes(pt.id)); + this.changePlotType(this.selectedPlotType); + this.updateDateRange(c.dateRange, false); + this.limitbycomponent.limitBy = c.limitBy; + this.limitbycomponent.limit = c.limit; + this.y1AxisDefinitionComponent.yAxisScale = c.y1.axisScale; + this.y1AxisDefinitionComponent.minYValue = c.y1.rangeMin; + this.y1AxisDefinitionComponent.maxYValue = c.y1.rangeMax; + this.y1AxisDefinitionComponent.yAxisUnit = c.y1.rangeUnit; + + if (c.y2) { + this.y2AxisDefinitionComponent.yAxisScale = c.y2.axisScale; + this.y2AxisDefinitionComponent.minYValue = c.y2.rangeMin; + this.y2AxisDefinitionComponent.maxYValue = c.y2.rangeMax; + this.y2AxisDefinitionComponent.yAxisUnit = c.y2.rangeUnit; + } + } +} + loading(event: LoadingEvent) { this.plotJobActive = event.loading; } - updateDateRange(newDateRange: string) { + updateDateRange(newDateRange: string, updatePlot=true) { (document.getElementById("search-date-range")).value = newDateRange; - this.plot(); + if (updatePlot){ + this.plot(); + } } changePlotType(selectedPlotTypes: Array) { diff --git a/pdb-js/src/index.html b/pdb-js/src/index.html index cc3d665..0e83208 100644 --- a/pdb-js/src/index.html +++ b/pdb-js/src/index.html @@ -48,9 +48,6 @@ } $( document ).ready(function() { - //initDatePicker(); - - initInvaders('results'); document.addEventListener("invadersPause", function(event) { pauseInvaders();