dashboard #1
@@ -4,11 +4,15 @@ import { VisualizationPageComponent } from './visualization-page/visualization-p
|
|||||||
import { MainPageComponent } from './main-page/main-page.component';
|
import { MainPageComponent } from './main-page/main-page.component';
|
||||||
import { UploadPageComponent } from './upload-page/upload-page.component';
|
import { UploadPageComponent } from './upload-page/upload-page.component';
|
||||||
import { HelpPageComponent } from './help-page/help-page.component';
|
import { HelpPageComponent } from './help-page/help-page.component';
|
||||||
|
import { DashboardPageComponent } from './dashboard-page/dashboard-page.component';
|
||||||
|
import { DashboardComponent } from './dashboard-page/dashboard/dashboard.component';
|
||||||
|
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: '', component: MainPageComponent},
|
{ path: '', component: MainPageComponent},
|
||||||
{ path: 'vis', component: VisualizationPageComponent },
|
{ path: 'vis', component: VisualizationPageComponent },
|
||||||
|
{ path: 'dashboard', component: DashboardPageComponent},
|
||||||
|
{ path: 'dashboard/:id', component: DashboardComponent},
|
||||||
{ path: 'upload', component: UploadPageComponent },
|
{ path: 'upload', component: UploadPageComponent },
|
||||||
{ path: 'help', component: HelpPageComponent },
|
{ path: 'help', component: HelpPageComponent },
|
||||||
// { path: '**', component: PageNotFoundComponent }
|
// { path: '**', component: PageNotFoundComponent }
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
|
||||||
|
|
||||||
<div id="main-toolbar">
|
<div id="main-toolbar">
|
||||||
<a href="/" title="open main page"><img src="assets/img/home.svg" class="icon-small" aria-hidden="false" aria-label="go to main page" /></a>
|
<a href="/" title="Home"><img src="assets/img/home.svg" class="icon-small" aria-hidden="false" aria-label="go to home page" /></a>
|
||||||
<a href="/vis" title="open visualization page"><img src="assets/img/scatter-chart2.svg" class="icon-small" aria-hidden="false" aria-label="go to visualization page" /></a>
|
<a href="/vis" title="Visualization"><img src="assets/img/scatter-chart2.svg" class="icon-small" aria-hidden="false" aria-label="go to visualization page" /></a>
|
||||||
|
<a href="/dashboard" title="Dashboards"><img src="assets/img/dashboard-line.svg" class="icon-small" aria-hidden="false" aria-label="go to dashboard page" /></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
|
|||||||
@@ -29,6 +29,14 @@ import { PlotDetailsComponent } from './plot-details/plot-details.component';
|
|||||||
import { PlotViewComponent } from './plot-view/plot-view.component';
|
import { PlotViewComponent } from './plot-view/plot-view.component';
|
||||||
import { GalleryViewComponent, GalleryItemView, GalleryFilterView } from './gallery-view/gallery-view.component';
|
import { GalleryViewComponent, GalleryItemView, GalleryFilterView } from './gallery-view/gallery-view.component';
|
||||||
import { ImageToggleComponent } from './image-toggle/image-toggle.component';
|
import { ImageToggleComponent } from './image-toggle/image-toggle.component';
|
||||||
|
import { DashboardPageComponent } from './dashboard-page/dashboard-page.component';
|
||||||
|
import { NewDashboardComponent } from './dashboard-page/new-dashboard/new-dashboard.component';
|
||||||
|
import { MatDialogModule, MAT_DIALOG_DEFAULT_OPTIONS } from '@angular/material/dialog';
|
||||||
|
import {MatTableModule} from '@angular/material/table';
|
||||||
|
import { DashboardComponent } from './dashboard-page/dashboard/dashboard.component';
|
||||||
|
import { AddTextDialogComponent } from './dashboard-page/dashboard/add-text-dialog/add-text-dialog.component';
|
||||||
|
import { TextWidgetComponent } from './dashboard-page/dashboard/text-widget/text-widget.component';
|
||||||
|
import { AddPlotDialogComponent } from './dashboard-page/dashboard/add-plot-dialog/add-plot-dialog.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -45,7 +53,13 @@ import { ImageToggleComponent } from './image-toggle/image-toggle.component';
|
|||||||
GalleryViewComponent,
|
GalleryViewComponent,
|
||||||
GalleryItemView,
|
GalleryItemView,
|
||||||
GalleryFilterView,
|
GalleryFilterView,
|
||||||
ImageToggleComponent
|
ImageToggleComponent,
|
||||||
|
DashboardPageComponent,
|
||||||
|
NewDashboardComponent,
|
||||||
|
DashboardComponent,
|
||||||
|
AddTextDialogComponent,
|
||||||
|
TextWidgetComponent,
|
||||||
|
AddPlotDialogComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
@@ -55,6 +69,7 @@ import { ImageToggleComponent } from './image-toggle/image-toggle.component';
|
|||||||
MatAutocompleteModule,
|
MatAutocompleteModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
|
MatDialogModule,
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
@@ -62,11 +77,12 @@ import { ImageToggleComponent } from './image-toggle/image-toggle.component';
|
|||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatSnackBarModule,
|
MatSnackBarModule,
|
||||||
|
MatTableModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
HttpClientModule
|
HttpClientModule
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [{provide: MAT_DIALOG_DEFAULT_OPTIONS, useValue: {hasBackdrop: true}}],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
|||||||
26
pdb-js/src/app/dashboard-page/dashboard-page.component.html
Normal file
26
pdb-js/src/app/dashboard-page/dashboard-page.component.html
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
<div class="toolbar">
|
||||||
|
<button mat-stroked-button (click)="createNewDashboard()">New</button>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="loading">
|
||||||
|
loading
|
||||||
|
</div>
|
||||||
|
<div *ngIf="!loading">
|
||||||
|
<table mat-table [dataSource]="dataSource" >
|
||||||
|
|
||||||
|
<!-- Name Column -->
|
||||||
|
<ng-container matColumnDef="name">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Name </th>
|
||||||
|
<td mat-cell *matCellDef="let element"><a [routerLink]="['/dashboard', element.id]">{{element.name}}</a></td>
|
||||||
|
</ng-container>
|
||||||
|
<!-- Description Column -->
|
||||||
|
<ng-container matColumnDef="description">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>Description</th>
|
||||||
|
<td mat-cell *matCellDef="let element">{{element.description}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
:host {
|
||||||
|
height: calc(100% - 29px);
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { DashboardPageComponent } from './dashboard-page.component';
|
||||||
|
|
||||||
|
describe('DashboardPageComponent', () => {
|
||||||
|
let component: DashboardPageComponent;
|
||||||
|
let fixture: ComponentFixture<DashboardPageComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ DashboardPageComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(DashboardPageComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
49
pdb-js/src/app/dashboard-page/dashboard-page.component.ts
Normal file
49
pdb-js/src/app/dashboard-page/dashboard-page.component.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { Dashboard, DashboardCreationData, DashboardList, DashboardService } from '../dashboard.service';
|
||||||
|
import { NewDashboardComponent } from './new-dashboard/new-dashboard.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-dashboard-page',
|
||||||
|
templateUrl: './dashboard-page.component.html',
|
||||||
|
styleUrls: ['./dashboard-page.component.scss']
|
||||||
|
})
|
||||||
|
export class DashboardPageComponent implements OnInit {
|
||||||
|
|
||||||
|
displayedColumns: string[] = ['name', 'description'];
|
||||||
|
dataSource: Dashboard[] = [];
|
||||||
|
loading = true;
|
||||||
|
|
||||||
|
constructor(public dialog: MatDialog, private dashboardService: DashboardService){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.refreshTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshTable(){
|
||||||
|
|
||||||
|
this.loading = true;
|
||||||
|
this.dashboardService.getDashboards().subscribe((dashboardList: DashboardList) => {
|
||||||
|
this.dataSource = dashboardList.dashboards;
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createNewDashboard() {
|
||||||
|
const dialogRef = this.dialog.open(NewDashboardComponent, {
|
||||||
|
data: {name: "", description: ""},
|
||||||
|
hasBackdrop: true
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((result: DashboardCreationData) => {
|
||||||
|
console.log('The dialog was closed with result ', JSON.stringify(result));
|
||||||
|
this.dashboardService.createDashboard(result).subscribe(result => {
|
||||||
|
console.log(result);
|
||||||
|
|
||||||
|
this.refreshTable();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
pdb-visualization-page {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 150px);
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
div[mat-dialog-actions] {
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h1 mat-dialog-title>Add Plot</h1>
|
||||||
|
|
||||||
|
<pdb-visualization-page mat-dialog-content></pdb-visualization-page>
|
||||||
|
|
||||||
|
<div mat-dialog-actions align="end">
|
||||||
|
<button mat-button mat-dialog-close>Cancel</button>
|
||||||
|
<button mat-button mat-dialog-close (click)="onSaveClick()" cdkFocusInitial>Save</button>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AddPlotDialogComponent } from './add-plot-dialog.component';
|
||||||
|
|
||||||
|
describe('AddPlotDialogComponent', () => {
|
||||||
|
let component: AddPlotDialogComponent;
|
||||||
|
let fixture: ComponentFixture<AddPlotDialogComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ AddPlotDialogComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(AddPlotDialogComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { MatDialogRef } from '@angular/material/dialog';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-add-plot-dialog',
|
||||||
|
templateUrl: './add-plot-dialog.component.html',
|
||||||
|
styleUrls: ['./add-plot-dialog.component.scss']
|
||||||
|
})
|
||||||
|
export class AddPlotDialogComponent {
|
||||||
|
|
||||||
|
|
||||||
|
constructor(public dialogRef: MatDialogRef<string>){
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick(): void {
|
||||||
|
this.dialogRef.close("todo");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<h1 mat-dialog-title>Add Text</h1>
|
||||||
|
<div mat-dialog-content>
|
||||||
|
<mat-form-field appearance="fill">
|
||||||
|
<mat-label>Text</mat-label>
|
||||||
|
<textarea matInput [(ngModel)]="text"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div mat-dialog-actions align="end">
|
||||||
|
<button mat-button mat-dialog-close>Cancel</button>
|
||||||
|
<button mat-button mat-dialog-close (click)="onSaveClick()" cdkFocusInitial>Save</button>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
textarea {
|
||||||
|
height: 5em;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AddTextDialogComponent } from './add-text-dialog.component';
|
||||||
|
|
||||||
|
describe('AddTextDialogComponent', () => {
|
||||||
|
let component: AddTextDialogComponent;
|
||||||
|
let fixture: ComponentFixture<AddTextDialogComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ AddTextDialogComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(AddTextDialogComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { MatDialogRef } from '@angular/material/dialog';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-add-text-dialog',
|
||||||
|
templateUrl: './add-text-dialog.component.html',
|
||||||
|
styleUrls: ['./add-text-dialog.component.scss']
|
||||||
|
})
|
||||||
|
export class AddTextDialogComponent {
|
||||||
|
text = "";
|
||||||
|
|
||||||
|
constructor(public dialogRef: MatDialogRef<string>){
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick(): void {
|
||||||
|
this.dialogRef.close(this.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<div *ngIf="dashboard === undefined" class="spinner">
|
||||||
|
<mat-spinner></mat-spinner>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="dashboard !== undefined" class="content">
|
||||||
|
<div class="toolbar">
|
||||||
|
<button mat-stroked-button (click)="addText()">Add Text</button>
|
||||||
|
<button mat-stroked-button (click)="addPlot()">Add Plot</button>
|
||||||
|
<button mat-stroked-button (click)="save()">Save Dashboard</button>
|
||||||
|
</div>
|
||||||
|
<h1>{{dashboard.name}}</h1>
|
||||||
|
<p>{{dashboard.description}}</p>
|
||||||
|
|
||||||
|
<app-text-widget *ngFor="let textWidget of dashboard.texts" [text]="textWidget.text"></app-text-widget>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
:host {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
}
|
||||||
|
.spinner {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { DashboardComponent } from './dashboard.component';
|
||||||
|
|
||||||
|
describe('DashboardComponent', () => {
|
||||||
|
let component: DashboardComponent;
|
||||||
|
let fixture: ComponentFixture<DashboardComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ DashboardComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(DashboardComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { Dashboard, DashboardService, TextWidget } from 'src/app/dashboard.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',
|
||||||
|
styleUrls: ['./dashboard.component.scss']
|
||||||
|
})
|
||||||
|
export class DashboardComponent implements OnInit {
|
||||||
|
|
||||||
|
dashboard?: Dashboard = undefined;
|
||||||
|
|
||||||
|
constructor(private route: ActivatedRoute, private service: DashboardService, private dialog: MatDialog, private snackBar: MatSnackBar) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.service.getDashboard(<string>this.route.snapshot.paramMap.get("id")).subscribe((dashboard: Dashboard) => {
|
||||||
|
this.dashboard = dashboard;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addText() {
|
||||||
|
this.dialog.open(AddTextDialogComponent,{
|
||||||
|
width: '600px'
|
||||||
|
}).afterClosed().subscribe((text: string) => {
|
||||||
|
this.dashboard!.texts.push(new TextWidget('MEDIUM', text));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addPlot() {
|
||||||
|
this.dialog.open(AddPlotDialogComponent,{
|
||||||
|
width: 'calc(100% - 1em)',
|
||||||
|
//height: 'calc(100% - 1em)'
|
||||||
|
}).afterClosed().subscribe((text: string) => {
|
||||||
|
//this.dashboard!.texts.push(new TextWidget('MEDIUM', text));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
save() {
|
||||||
|
this.service.saveDashboard(this.dashboard!).subscribe({
|
||||||
|
'complete': () => {
|
||||||
|
this.snackBar.open("saved dashboard","", {
|
||||||
|
duration: 5000,
|
||||||
|
verticalPosition: 'top'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<p *ngFor="let line of lines()">{{line}}</p>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TextWidgetComponent } from './text-widget.component';
|
||||||
|
|
||||||
|
describe('TextWidgetComponent', () => {
|
||||||
|
let component: TextWidgetComponent;
|
||||||
|
let fixture: ComponentFixture<TextWidgetComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ TextWidgetComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(TextWidgetComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-text-widget',
|
||||||
|
templateUrl: './text-widget.component.html'
|
||||||
|
})
|
||||||
|
export class TextWidgetComponent {
|
||||||
|
@Input()
|
||||||
|
text = "";
|
||||||
|
|
||||||
|
lines(): string[]{
|
||||||
|
return this.text.split(/\r?\n/);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<h1 mat-dialog-title>Create a new dashboard</h1>
|
||||||
|
<div mat-dialog-content>
|
||||||
|
<mat-form-field appearance="fill">
|
||||||
|
<mat-label>Name</mat-label>
|
||||||
|
<input matInput [(ngModel)]="data.name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field appearance="fill">
|
||||||
|
<mat-label>Description</mat-label>
|
||||||
|
<textarea matInput [(ngModel)]="data.description"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div mat-dialog-actions align="end">
|
||||||
|
<button mat-button mat-dialog-close>Cancel</button>
|
||||||
|
<button mat-button mat-dialog-close (click)="onSaveClick()" cdkFocusInitial>Save</button>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
div[mat-dialog-content] {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { NewDashboardComponent } from './new-dashboard.component';
|
||||||
|
|
||||||
|
describe('NewDashboardComponent', () => {
|
||||||
|
let component: NewDashboardComponent;
|
||||||
|
let fixture: ComponentFixture<NewDashboardComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ NewDashboardComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(NewDashboardComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import {MatDialog, 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']
|
||||||
|
})
|
||||||
|
export class NewDashboardComponent {
|
||||||
|
constructor(public dialogRef: MatDialogRef<NewDashboardComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: DashboardCreationData,){
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick(): void {
|
||||||
|
this.dialogRef.close(this.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
16
pdb-js/src/app/dashboard.service.spec.ts
Normal file
16
pdb-js/src/app/dashboard.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { DashboardService } from './dashboard.service';
|
||||||
|
|
||||||
|
describe('DashboardService', () => {
|
||||||
|
let service: DashboardService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(DashboardService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
55
pdb-js/src/app/dashboard.service.ts
Normal file
55
pdb-js/src/app/dashboard.service.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class DashboardService {
|
||||||
|
|
||||||
|
constructor(private http: HttpClient) { }
|
||||||
|
|
||||||
|
createDashboard(data: DashboardCreationData): Observable<Dashboard>{
|
||||||
|
return this.http.post<Dashboard>('//'+window.location.hostname+':'+window.location.port+'/api/dashboards/', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDashboards(): Observable<DashboardList>{
|
||||||
|
return this.http.get<DashboardList>('//'+window.location.hostname+':'+window.location.port+'/api/dashboards/');
|
||||||
|
}
|
||||||
|
|
||||||
|
getDashboard(id: string): Observable<Dashboard>{
|
||||||
|
return this.http.get<Dashboard>('//'+window.location.hostname+':'+window.location.port+'/api/dashboards/'+id);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveDashboard(dashboard: Dashboard): Observable<Dashboard>{
|
||||||
|
return this.http.put<Dashboard>('//'+window.location.hostname+':'+window.location.port+'/api/dashboards/'+dashboard.id, dashboard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class DashboardCreationData{
|
||||||
|
constructor(public name: string, public description: string){}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Dashboard{
|
||||||
|
constructor(public id: string, public name: string, public description: string, public texts: [TextWidget]){}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DashboardList{
|
||||||
|
constructor(public dashboards: [Dashboard]){}
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class BaseWidget {
|
||||||
|
constructor(public type: 'TEXT'|'PLOT', public size: 'SMALL'|'MEDIUM'|'LARGE') {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TextWidget extends BaseWidget {
|
||||||
|
constructor(override size: 'SMALL'|'MEDIUM'|'LARGE', public text: string) {
|
||||||
|
super('TEXT', size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class PlotWidget extends BaseWidget {
|
||||||
|
constructor(override size: 'SMALL'|'MEDIUM'|'LARGE') {
|
||||||
|
super('PLOT', size);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,8 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div id="main-page-links">
|
<div id="main-page-links">
|
||||||
<a href="/vis" class="button-large" title="open visualization page"><img src="assets/img/scatter-chart2.svg" class="icon-large" aria-hidden="false" aria-label="go to visualization page" /></a>
|
<a [routerLink]="['/vis']" class="button-large" title="Visualization"><img src="assets/img/scatter-chart2.svg" class="icon-large" aria-hidden="false" aria-label="go to visualization page" /></a>
|
||||||
|
<a [routerLink]="['/dashboard']" class="button-large" title="Dashboards"><img src="assets/img/dashboard-line.svg" class="icon-large" aria-hidden="false" aria-label="go to dashboard page" /></a>
|
||||||
|
|
||||||
<!--a href="/upload" class="button-large" title="upload data"><img src="assets/img/upload.svg" class="icon-large" aria-hidden="false" aria-label="upload data" /></a-->
|
<!--a href="/upload" class="button-large" title="upload data"><img src="assets/img/upload.svg" class="icon-large" aria-hidden="false" aria-label="upload data" /></a-->
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -70,6 +70,9 @@ export class VisualizationPageComponent implements OnInit {
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
const that = this;
|
const that = this;
|
||||||
|
|
||||||
|
(<any>window).initDatePicker();
|
||||||
|
|
||||||
this.plotTypes = this.plotService.getPlotTypes();
|
this.plotTypes = this.plotService.getPlotTypes();
|
||||||
this.selectedPlotType.push(this.plotTypes[0]);
|
this.selectedPlotType.push(this.plotTypes[0]);
|
||||||
|
|
||||||
@@ -86,7 +89,7 @@ export class VisualizationPageComponent implements OnInit {
|
|||||||
that.splitBy = that.tagFields.find(val => filterDefaults.splitBy == val.name);
|
that.splitBy = that.tagFields.find(val => filterDefaults.splitBy == val.name);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
changePlotType(selectedPlotTypes: Array<PlotType>) {
|
changePlotType(selectedPlotTypes: Array<PlotType>) {
|
||||||
const compatiblePlotTypes = this.plotTypes.filter(pt => pt.compatible(selectedPlotTypes));
|
const compatiblePlotTypes = this.plotTypes.filter(pt => pt.compatible(selectedPlotTypes));
|
||||||
this.plotTypes.forEach(pt => pt.active=false);
|
this.plotTypes.forEach(pt => pt.active=false);
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
<body>
|
<body>
|
||||||
<app-root></app-root>
|
<app-root></app-root>
|
||||||
<script>
|
<script>
|
||||||
$( document ).ready(function() {
|
|
||||||
$('input[name="dates"]').daterangepicker({
|
function initDatePicker() {
|
||||||
|
$('input[name="dates"]').daterangepicker({
|
||||||
timePicker: true,
|
timePicker: true,
|
||||||
minDate: "2017-01-01",
|
minDate: "2017-01-01",
|
||||||
maxDate: "2029-12-31",
|
maxDate: "2029-12-31",
|
||||||
@@ -44,6 +45,10 @@
|
|||||||
'Last Year': [moment().subtract(1, 'year').startOf('year'),moment().subtract(1, 'year').endOf('year')],
|
'Last Year': [moment().subtract(1, 'year').startOf('year'),moment().subtract(1, 'year').endOf('year')],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$( document ).ready(function() {
|
||||||
|
//initDatePicker();
|
||||||
|
|
||||||
|
|
||||||
initInvaders('results');
|
initInvaders('results');
|
||||||
|
|||||||
@@ -15,4 +15,8 @@ public class NotFoundException extends RuntimeException {
|
|||||||
public NotFoundException(final Throwable cause) {
|
public NotFoundException(final Throwable cause) {
|
||||||
super(cause);
|
super(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NotFoundException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package org.lucares.pdbui.dashboard;
|
||||||
|
|
||||||
|
public abstract class BaseDashboardWidget {
|
||||||
|
|
||||||
|
private DashboardWidgetType type;
|
||||||
|
|
||||||
|
private DashboardWidgetSize size;
|
||||||
|
|
||||||
|
public BaseDashboardWidget() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseDashboardWidget(final DashboardWidgetType type, final DashboardWidgetSize size) {
|
||||||
|
this.type = type;
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DashboardWidgetType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(final DashboardWidgetType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DashboardWidgetSize getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(final DashboardWidgetSize size) {
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package org.lucares.pdbui.dashboard;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class Dashboard {
|
||||||
|
|
||||||
|
public static class ByNameComparator implements Comparator<Dashboard> {
|
||||||
|
@Override
|
||||||
|
public int compare(final Dashboard o1, final Dashboard o2) {
|
||||||
|
return o1.getName().compareToIgnoreCase(o2.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Comparator<Dashboard> BY_NAME = new ByNameComparator().thenComparing(Dashboard::getId);
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private List<TextWidget> texts = new ArrayList<>();
|
||||||
|
|
||||||
|
public Dashboard() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Dashboard creatNew(final String name, final String description) {
|
||||||
|
|
||||||
|
final Dashboard dashboard = new Dashboard();
|
||||||
|
dashboard.setId(UUID.randomUUID().toString());
|
||||||
|
dashboard.setName(name);
|
||||||
|
dashboard.setDescription(description);
|
||||||
|
return dashboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(final String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(final String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TextWidget> getTexts() {
|
||||||
|
return texts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTexts(final List<TextWidget> texts) {
|
||||||
|
this.texts = texts;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
package org.lucares.pdbui.dashboard;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.lucares.pdbui.BadRequest;
|
||||||
|
import org.lucares.pdbui.NotFoundException;
|
||||||
|
import org.lucares.utils.file.FileUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@EnableAutoConfiguration
|
||||||
|
@RequestMapping(path = "/api/dashboards")
|
||||||
|
@CrossOrigin(origins = { "http://localhost:4200", "http://127.0.0.1:4200" })
|
||||||
|
public class DashboardController {
|
||||||
|
|
||||||
|
private final Path baseDir;
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
private final ObjectWriter objectWriter = objectMapper.writerWithDefaultPrettyPrinter();
|
||||||
|
|
||||||
|
public DashboardController(@Value("${db.base}") final String dbBaseDir) throws IOException {
|
||||||
|
baseDir = Path.of(dbBaseDir).resolve("dashboards");
|
||||||
|
Files.createDirectories(baseDir);
|
||||||
|
objectMapper.setConfig(objectMapper.getSerializationConfig().with());
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(path = "/", //
|
||||||
|
method = RequestMethod.POST, //
|
||||||
|
consumes = MediaType.APPLICATION_JSON_VALUE, //
|
||||||
|
produces = MediaType.APPLICATION_JSON_VALUE //
|
||||||
|
)
|
||||||
|
@ResponseBody
|
||||||
|
@ResponseStatus(code = HttpStatus.CREATED)
|
||||||
|
public Dashboard createDashboard(@RequestBody final DashboardCreationData creationData) throws IOException {
|
||||||
|
|
||||||
|
final Dashboard dashboard = Dashboard.creatNew(creationData.getName(), creationData.getDescription());
|
||||||
|
return saveDashboard(dashboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(path = "/", method = RequestMethod.GET, //
|
||||||
|
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
@ResponseBody
|
||||||
|
public DashboardList getDashboards() throws IOException {
|
||||||
|
|
||||||
|
final List<Dashboard> dashboards = new ArrayList<>(Files.list(baseDir)//
|
||||||
|
.filter(p -> p.getFileName().toString().endsWith(".json"))//
|
||||||
|
.map(FileUtils::readSilent)//
|
||||||
|
.map(this::deserializeDashboard)//
|
||||||
|
.toList());
|
||||||
|
|
||||||
|
Collections.sort(dashboards, Dashboard.BY_NAME);
|
||||||
|
|
||||||
|
return new DashboardList(dashboards);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(path = "/{dashboardId}", method = RequestMethod.GET, //
|
||||||
|
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
@ResponseBody
|
||||||
|
public Dashboard getDashboard(@PathVariable("dashboardId") final String dashboardId) throws IOException {
|
||||||
|
|
||||||
|
final Path file = baseDir.resolve(dashboardId + ".json");
|
||||||
|
if (!Files.isReadable(file) || !Files.isRegularFile(file)) {
|
||||||
|
throw new NotFoundException("Not Found");
|
||||||
|
}
|
||||||
|
|
||||||
|
final String json = Files.readString(file, StandardCharsets.UTF_8);
|
||||||
|
return deserializeDashboard(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(path = "/{dashboardId}", method = RequestMethod.PUT, //
|
||||||
|
consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
@ResponseBody
|
||||||
|
public Dashboard updateDashboard(@PathVariable("dashboardId") final String dashboardId,
|
||||||
|
@RequestBody final Dashboard dashboard) throws IOException {
|
||||||
|
|
||||||
|
final Path file = baseDir.resolve(dashboardId + ".json");
|
||||||
|
if (!Files.isReadable(file) || !Files.isRegularFile(file)) {
|
||||||
|
throw new NotFoundException("Not Found");
|
||||||
|
}
|
||||||
|
if (!dashboardId.equals(dashboard.getId())) {
|
||||||
|
throw new BadRequest("Inconsistent dashboard id in URL and payload");
|
||||||
|
}
|
||||||
|
|
||||||
|
return saveDashboard(dashboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(path = "/{dashboardId}", method = RequestMethod.DELETE, //
|
||||||
|
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
@ResponseBody
|
||||||
|
public void deleteDashboard(@PathVariable("dashboardId") final String dashboardId) throws IOException {
|
||||||
|
final Path file = baseDir.resolve(dashboardId + ".json");
|
||||||
|
Files.deleteIfExists(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dashboard deserializeDashboard(final String json) {
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(json, Dashboard.class);
|
||||||
|
} catch (final JsonProcessingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dashboard saveDashboard(final Dashboard dashboard) throws JsonProcessingException, IOException {
|
||||||
|
final Path file = baseDir.resolve(dashboard.getId() + ".json");
|
||||||
|
final String dashboardJson = objectWriter.writeValueAsString(dashboard);
|
||||||
|
Files.writeString(file, dashboardJson, StandardCharsets.UTF_8);
|
||||||
|
return dashboard;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package org.lucares.pdbui.dashboard;
|
||||||
|
|
||||||
|
public class DashboardCreationData {
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
public DashboardCreationData() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DashboardCreationData(final String name, final String description) {
|
||||||
|
this.name = name;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(final String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.lucares.pdbui.dashboard;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DashboardList {
|
||||||
|
|
||||||
|
private List<Dashboard> dashboards;
|
||||||
|
|
||||||
|
public DashboardList() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DashboardList(final List<Dashboard> dashboards) {
|
||||||
|
this.dashboards = dashboards;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDashboards(final List<Dashboard> dashboards) {
|
||||||
|
this.dashboards = dashboards;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Dashboard> getDashboards() {
|
||||||
|
return dashboards;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.lucares.pdbui.dashboard;
|
||||||
|
|
||||||
|
public enum DashboardWidgetSize {
|
||||||
|
SMALL, MEDIUM, LARGE
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.lucares.pdbui.dashboard;
|
||||||
|
|
||||||
|
public enum DashboardWidgetType {
|
||||||
|
TEXT, PLOT
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.lucares.pdbui.dashboard;
|
||||||
|
|
||||||
|
public class PlotWidget extends BaseDashboardWidget {
|
||||||
|
|
||||||
|
public PlotWidget() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlotWidget(final DashboardWidgetSize size) {
|
||||||
|
super(DashboardWidgetType.PLOT, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package org.lucares.pdbui.dashboard;
|
||||||
|
|
||||||
|
public class Position {
|
||||||
|
private int x;
|
||||||
|
private int y;
|
||||||
|
|
||||||
|
public Position() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Position(final int x, final int y) {
|
||||||
|
super();
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setX(final int x) {
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setY(final int y) {
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return x + "," + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.lucares.pdbui.dashboard;
|
||||||
|
|
||||||
|
public class TextWidget extends BaseDashboardWidget {
|
||||||
|
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
public TextWidget() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextWidget(final DashboardWidgetSize size, final String text) {
|
||||||
|
super(DashboardWidgetType.TEXT, size);
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setText(final String text) {
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.lucares.utils.file;
|
package org.lucares.utils.file;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.FileVisitResult;
|
import java.nio.file.FileVisitResult;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -76,4 +77,12 @@ public class FileUtils {
|
|||||||
return files.collect(Collectors.toList());
|
return files.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String readSilent(final Path p) {
|
||||||
|
try {
|
||||||
|
return Files.readString(p, StandardCharsets.UTF_8);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user