diff --git a/pdb-js/src/app/app-routing.module.ts b/pdb-js/src/app/app-routing.module.ts
index 3b81758..a011b96 100644
--- a/pdb-js/src/app/app-routing.module.ts
+++ b/pdb-js/src/app/app-routing.module.ts
@@ -6,6 +6,7 @@ import { UploadPageComponent } from './upload-page/upload-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';
+import { CustomizableGridComponent } from './customizable-grid/customizable-grid.component';
const routes: Routes = [
@@ -14,6 +15,7 @@ const routes: Routes = [
{ path: 'dashboard', component: DashboardPageComponent},
{ path: 'dashboard/:id', component: DashboardComponent},
{ path: 'upload', component: UploadPageComponent },
+ { path: 'grid', component: CustomizableGridComponent },
{ path: 'help', component: HelpPageComponent },
// { path: '**', component: PageNotFoundComponent }
];
diff --git a/pdb-js/src/app/app.module.ts b/pdb-js/src/app/app.module.ts
index 5d5c494..ad24a88 100644
--- a/pdb-js/src/app/app.module.ts
+++ b/pdb-js/src/app/app.module.ts
@@ -33,12 +33,16 @@ import { DashboardPageComponent } from './dashboard-page/dashboard-page.componen
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 {MatBadgeModule} from '@angular/material/badge';
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';
import { PlotWidgetComponent } from './dashboard-page/dashboard/plot-widget/plot-widget.component';
import { FullScreenPlotDialogComponent } from './dashboard-page/dashboard/full-screen-plot-dialog/full-screen-plot-dialog.component';
+import { CustomizableGridComponent } from './customizable-grid/customizable-grid.component';
+
+import {DragDropModule} from '@angular/cdk/drag-drop';
@NgModule({
declarations: [
@@ -63,14 +67,17 @@ import { FullScreenPlotDialogComponent } from './dashboard-page/dashboard/full-s
TextWidgetComponent,
AddPlotDialogComponent,
PlotWidgetComponent,
- FullScreenPlotDialogComponent
+ FullScreenPlotDialogComponent,
+ CustomizableGridComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
ReactiveFormsModule,
+ DragDropModule,
MatAutocompleteModule,
+ MatBadgeModule,
MatButtonModule,
MatCheckboxModule,
MatDialogModule,
diff --git a/pdb-js/src/app/customizable-grid/customizable-grid.component.html b/pdb-js/src/app/customizable-grid/customizable-grid.component.html
new file mode 100644
index 0000000..54126b4
--- /dev/null
+++ b/pdb-js/src/app/customizable-grid/customizable-grid.component.html
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
diff --git a/pdb-js/src/app/customizable-grid/customizable-grid.component.spec.ts b/pdb-js/src/app/customizable-grid/customizable-grid.component.spec.ts
new file mode 100644
index 0000000..8e0cda2
--- /dev/null
+++ b/pdb-js/src/app/customizable-grid/customizable-grid.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CustomizableGridComponent } from './customizable-grid.component';
+
+describe('CustomizableGridComponent', () => {
+ let component: CustomizableGridComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ CustomizableGridComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(CustomizableGridComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/pdb-js/src/app/customizable-grid/customizable-grid.component.ts b/pdb-js/src/app/customizable-grid/customizable-grid.component.ts
new file mode 100644
index 0000000..3639956
--- /dev/null
+++ b/pdb-js/src/app/customizable-grid/customizable-grid.component.ts
@@ -0,0 +1,24 @@
+import { Component } from '@angular/core';
+import {CdkDragDrop, moveItemInArray, transferArrayItem} from '@angular/cdk/drag-drop';
+
+@Component({
+ selector: 'app-customizable-grid',
+ templateUrl: './customizable-grid.component.html'
+})
+export class CustomizableGridComponent {
+ todo = ['Get to work', 'Pick up groceries', 'Go home', 'Fall asleep'];
+ done = ['Get up', 'Brush teeth', 'Take a shower', 'Check e-mail', 'Walk dog'];
+
+ 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,
+ );
+ }
+ }
+}
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 9517a7f..cdd06ae 100644
--- a/pdb-js/src/app/dashboard-page/dashboard-page.component.html
+++ b/pdb-js/src/app/dashboard-page/dashboard-page.component.html
@@ -1,27 +1,28 @@
@@ -39,6 +40,11 @@
0" mat-table [dataSource]="dataSource" >
+
+
+ |
+  |
+
Name |
diff --git a/pdb-js/src/app/dashboard-page/dashboard-page.component.ts b/pdb-js/src/app/dashboard-page/dashboard-page.component.ts
index 65e0165..05e78fd 100644
--- a/pdb-js/src/app/dashboard-page/dashboard-page.component.ts
+++ b/pdb-js/src/app/dashboard-page/dashboard-page.component.ts
@@ -10,7 +10,7 @@ import { NewDashboardComponent } from './new-dashboard/new-dashboard.component';
})
export class DashboardPageComponent implements OnInit {
- displayedColumns: string[] = ['name', 'description'];
+ displayedColumns: string[] = [/*'icon',*/ 'name', 'description'];
dataSource: Dashboard[] = [];
loading = true;
error = "";
diff --git a/pdb-js/src/app/dashboard-page/dashboard/dashboard.component.html b/pdb-js/src/app/dashboard-page/dashboard/dashboard.component.html
index bc36cd7..446c272 100644
--- a/pdb-js/src/app/dashboard-page/dashboard/dashboard.component.html
+++ b/pdb-js/src/app/dashboard-page/dashboard/dashboard.component.html
@@ -22,6 +22,10 @@
.content {
padding: 0.5em;
}
+ .dashboard-column {
+ display: flex;
+ flex-direction: column;
+ }
@@ -40,6 +44,25 @@
{{dashboard.name}}
{{dashboard.description}}
-
-
+
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 872c093..d55558b 100644
--- a/pdb-js/src/app/dashboard-page/dashboard/dashboard.component.ts
+++ b/pdb-js/src/app/dashboard-page/dashboard/dashboard.component.ts
@@ -1,9 +1,10 @@
+import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import { HttpErrorResponse } from '@angular/common/http';
-import { Component, OnInit } from '@angular/core';
+import { Component, ElementRef, 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, PlotSize, PlotWidget, PlotWidgetRenderData, TextWidget } from 'src/app/dashboard.service';
+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';
@@ -25,29 +26,31 @@ export class DashboardComponent implements OnInit {
private service: DashboardService,
private dialog: MatDialog,
private snackBar: MatSnackBar,
- private plotService: PlotService) {}
+ 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.dashboard = dashboard;
+ this.repairArrangement();
- dashboard.plots.forEach(p => {
- this.plotWidgetRenderData.push(new PlotWidgetRenderData(p));
- });
+ 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";
+ 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[]) {
@@ -84,35 +87,63 @@ export class DashboardComponent implements OnInit {
'fullScreen': new RenderOptions(fullHeight,fullWidth, false, true)
}
);
- return request;
- }
+ return request;
+ }
- height(size: PlotSize): number{
- switch (size) {
- case 'SMALL':
- return 300;
- case 'MEDIUM':
- return 400;
- case 'LARGE':
- return 600;
+ 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;
+ 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('MEDIUM', text));
+ this.dashboard!.texts.push(new TextWidget(crypto.randomUUID(),'MEDIUM', text));
});
}
@@ -121,11 +152,28 @@ export class DashboardComponent implements OnInit {
width: 'calc(100% - 1em)',
height: 'calc(100% - 1em)'
}).afterClosed().subscribe((config: PlotConfig) => {
- this.dashboard!.plots.push(new PlotWidget('MEDIUM', config));
+ 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","", {
@@ -135,4 +183,37 @@ export class DashboardComponent implements OnInit {
}
});
}
+
+ 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);
+ }
}
diff --git a/pdb-js/src/app/dashboard-page/dashboard/text-widget/text-widget.component.html b/pdb-js/src/app/dashboard-page/dashboard/text-widget/text-widget.component.html
index 1cbcf0b..0bfee8a 100644
--- a/pdb-js/src/app/dashboard-page/dashboard/text-widget/text-widget.component.html
+++ b/pdb-js/src/app/dashboard-page/dashboard/text-widget/text-widget.component.html
@@ -2,6 +2,7 @@
:host {
display: block;
margin-top: 1em;
+ background-color: aliceblue;
}
{{line}}
diff --git a/pdb-js/src/app/dashboard.service.ts b/pdb-js/src/app/dashboard.service.ts
index cef4c3e..3eb0881 100644
--- a/pdb-js/src/app/dashboard.service.ts
+++ b/pdb-js/src/app/dashboard.service.ts
@@ -32,26 +32,36 @@ export class DashboardCreationData{
constructor(public name: string, public description: string){}
}
+export interface HasId {
+ id: string;
+}
+
export class Dashboard{
- constructor(public id: string, public name: string, public description: string, public texts: TextWidget[], public plots: PlotWidget[]){}
+ constructor(
+ public id: string,
+ public name: string,
+ public description: string,
+ public texts: TextWidget[],
+ public plots: PlotWidget[],
+ public arrangement: string[][]){}
}
export class DashboardList{
constructor(public dashboards: [Dashboard]){}
}
-export abstract class BaseWidget {
- constructor(public type: PlotType, public size: PlotSize) {}
+export abstract class BaseWidget implements HasId {
+ constructor(public id: string, public type: PlotType, public size: PlotSize) {}
}
export class TextWidget extends BaseWidget {
- constructor(override size: PlotSize, public text: string) {
- super('TEXT', size);
+ constructor(override id: string, override size: PlotSize, public text: string) {
+ super(id, 'TEXT', size);
}
}
export class PlotWidget extends BaseWidget {
- constructor(override size: PlotSize, public config: PlotConfig) {
- super('PLOT', size);
+ constructor(override id: string, override size: PlotSize, public config: PlotConfig) {
+ super(id, 'PLOT', size);
}
}
diff --git a/pdb-js/src/assets/img/dashboard-outline.svg b/pdb-js/src/assets/img/dashboard-outline.svg
new file mode 100644
index 0000000..073fc3e
--- /dev/null
+++ b/pdb-js/src/assets/img/dashboard-outline.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/pdb-js/src/styles.scss b/pdb-js/src/styles.scss
index 3946345..9ea1147 100644
--- a/pdb-js/src/styles.scss
+++ b/pdb-js/src/styles.scss
@@ -141,6 +141,12 @@ mat-option.mat-option.mat-active {
background-color: #ccc;
}
+
+a ,a:visited {
+ color: blue;
+ text-decoration: none;
+}
+
a.external-link:after {
background: transparent url('/assets/img/external-link.svg') no-repeat center bottom;
background-size: 0.8em;
diff --git a/pdb-ui/src/main/java/org/lucares/pdbui/dashboard/BaseDashboardWidget.java b/pdb-ui/src/main/java/org/lucares/pdbui/dashboard/BaseDashboardWidget.java
index 87732f8..1496d56 100644
--- a/pdb-ui/src/main/java/org/lucares/pdbui/dashboard/BaseDashboardWidget.java
+++ b/pdb-ui/src/main/java/org/lucares/pdbui/dashboard/BaseDashboardWidget.java
@@ -1,7 +1,11 @@
package org.lucares.pdbui.dashboard;
+import java.util.UUID;
+
public abstract class BaseDashboardWidget {
+ private String id = UUID.randomUUID().toString();
+
private DashboardWidgetType type;
private DashboardWidgetSize size;
@@ -15,6 +19,14 @@ public abstract class BaseDashboardWidget {
this.size = size;
}
+ public String getId() {
+ return id;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
+
public DashboardWidgetType getType() {
return type;
}
diff --git a/pdb-ui/src/main/java/org/lucares/pdbui/dashboard/Dashboard.java b/pdb-ui/src/main/java/org/lucares/pdbui/dashboard/Dashboard.java
index 6c1cb5a..559deac 100644
--- a/pdb-ui/src/main/java/org/lucares/pdbui/dashboard/Dashboard.java
+++ b/pdb-ui/src/main/java/org/lucares/pdbui/dashboard/Dashboard.java
@@ -24,6 +24,8 @@ public class Dashboard {
private List plots = new ArrayList<>();
+ private List> arrangement = new ArrayList<>();
+
public Dashboard() {
super();
@@ -77,4 +79,12 @@ public class Dashboard {
public List getPlots() {
return plots;
}
+
+ public List> getArrangement() {
+ return arrangement;
+ }
+
+ public void setArrangement(final List> arrangement) {
+ this.arrangement = arrangement;
+ }
}