dashboard #1
@@ -6,6 +6,7 @@ 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 { DashboardPageComponent } from './dashboard-page/dashboard-page.component';
|
||||||
import { DashboardComponent } from './dashboard-page/dashboard/dashboard.component';
|
import { DashboardComponent } from './dashboard-page/dashboard/dashboard.component';
|
||||||
|
import { CustomizableGridComponent } from './customizable-grid/customizable-grid.component';
|
||||||
|
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
@@ -14,6 +15,7 @@ const routes: Routes = [
|
|||||||
{ path: 'dashboard', component: DashboardPageComponent},
|
{ path: 'dashboard', component: DashboardPageComponent},
|
||||||
{ path: 'dashboard/:id', component: DashboardComponent},
|
{ path: 'dashboard/:id', component: DashboardComponent},
|
||||||
{ path: 'upload', component: UploadPageComponent },
|
{ path: 'upload', component: UploadPageComponent },
|
||||||
|
{ path: 'grid', component: CustomizableGridComponent },
|
||||||
{ path: 'help', component: HelpPageComponent },
|
{ path: 'help', component: HelpPageComponent },
|
||||||
// { path: '**', component: PageNotFoundComponent }
|
// { path: '**', component: PageNotFoundComponent }
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -33,12 +33,16 @@ import { DashboardPageComponent } from './dashboard-page/dashboard-page.componen
|
|||||||
import { NewDashboardComponent } from './dashboard-page/new-dashboard/new-dashboard.component';
|
import { NewDashboardComponent } from './dashboard-page/new-dashboard/new-dashboard.component';
|
||||||
import { MatDialogModule, MAT_DIALOG_DEFAULT_OPTIONS } from '@angular/material/dialog';
|
import { MatDialogModule, MAT_DIALOG_DEFAULT_OPTIONS } from '@angular/material/dialog';
|
||||||
import {MatTableModule} from '@angular/material/table';
|
import {MatTableModule} from '@angular/material/table';
|
||||||
|
import {MatBadgeModule} from '@angular/material/badge';
|
||||||
import { DashboardComponent } from './dashboard-page/dashboard/dashboard.component';
|
import { DashboardComponent } from './dashboard-page/dashboard/dashboard.component';
|
||||||
import { AddTextDialogComponent } from './dashboard-page/dashboard/add-text-dialog/add-text-dialog.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 { TextWidgetComponent } from './dashboard-page/dashboard/text-widget/text-widget.component';
|
||||||
import { AddPlotDialogComponent } from './dashboard-page/dashboard/add-plot-dialog/add-plot-dialog.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 { 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 { 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({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -63,14 +67,17 @@ import { FullScreenPlotDialogComponent } from './dashboard-page/dashboard/full-s
|
|||||||
TextWidgetComponent,
|
TextWidgetComponent,
|
||||||
AddPlotDialogComponent,
|
AddPlotDialogComponent,
|
||||||
PlotWidgetComponent,
|
PlotWidgetComponent,
|
||||||
FullScreenPlotDialogComponent
|
FullScreenPlotDialogComponent,
|
||||||
|
CustomizableGridComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
|
DragDropModule,
|
||||||
MatAutocompleteModule,
|
MatAutocompleteModule,
|
||||||
|
MatBadgeModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
<style>
|
||||||
|
.customizable-grid {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.draggable {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border: solid 1px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-small {
|
||||||
|
width: 300px;
|
||||||
|
height: 300px;
|
||||||
|
|
||||||
|
background-color: rgb(158, 240, 189);
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-middle {
|
||||||
|
width: 600px;
|
||||||
|
height: 300px;
|
||||||
|
background-color: darksalmon;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-container {
|
||||||
|
width: 400px;
|
||||||
|
max-width: 100%;
|
||||||
|
margin: 0 25px 25px 0;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-list {
|
||||||
|
border: solid 1px #ccc;
|
||||||
|
min-height: 60px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-box {
|
||||||
|
padding: 20px 10px;
|
||||||
|
border-bottom: solid 1px #ccc;
|
||||||
|
color: rgba(0, 0, 0, 0.87);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: move;
|
||||||
|
background: white;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cdk-drag-preview {
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
|
||||||
|
0 8px 10px 1px rgba(0, 0, 0, 0.14),
|
||||||
|
0 3px 14px 2px rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cdk-drag-placeholder {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cdk-drag-animating {
|
||||||
|
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-box:last-child {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
|
||||||
|
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<!--
|
||||||
|
<div class="customizable-grid">
|
||||||
|
<div class="draggable draggable-small"></div>
|
||||||
|
<div class="draggable draggable-middle"></div>
|
||||||
|
<div class="draggable draggable-small"></div>
|
||||||
|
<div class="draggable draggable-middle"></div>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<div class="example-container">
|
||||||
|
<h2>To do</h2>
|
||||||
|
|
||||||
|
<div
|
||||||
|
cdkDropList
|
||||||
|
#todoList="cdkDropList"
|
||||||
|
[cdkDropListData]="todo"
|
||||||
|
[cdkDropListConnectedTo]="[doneList]"
|
||||||
|
class="example-list"
|
||||||
|
(cdkDropListDropped)="drop($event)">
|
||||||
|
<div class="example-box" *ngFor="let item of todo" cdkDrag>{{item}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="example-container">
|
||||||
|
<h2>Done</h2>
|
||||||
|
|
||||||
|
<div
|
||||||
|
cdkDropList
|
||||||
|
#doneList="cdkDropList"
|
||||||
|
[cdkDropListData]="done"
|
||||||
|
[cdkDropListConnectedTo]="[todoList]"
|
||||||
|
class="example-list"
|
||||||
|
(cdkDropListDropped)="drop($event)">
|
||||||
|
<div class="example-box" *ngFor="let item of done" cdkDrag>{{item}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@@ -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<CustomizableGridComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ CustomizableGridComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(CustomizableGridComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -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<string[]>) {
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.center {
|
.center {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
@@ -39,6 +40,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<table *ngIf="dataSource.length > 0" mat-table [dataSource]="dataSource" >
|
<table *ngIf="dataSource.length > 0" mat-table [dataSource]="dataSource" >
|
||||||
|
|
||||||
|
<!-- Icon Column -->
|
||||||
|
<ng-container matColumnDef="icon">
|
||||||
|
<th mat-header-cell *matHeaderCellDef></th>
|
||||||
|
<td mat-cell *matCellDef="let element"><a [routerLink]="['/dashboard', element.id]"><img src="assets/img/dashboard-outline.svg"/></a></td>
|
||||||
|
</ng-container>
|
||||||
<!-- Name Column -->
|
<!-- Name Column -->
|
||||||
<ng-container matColumnDef="name">
|
<ng-container matColumnDef="name">
|
||||||
<th mat-header-cell *matHeaderCellDef> Name </th>
|
<th mat-header-cell *matHeaderCellDef> Name </th>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { NewDashboardComponent } from './new-dashboard/new-dashboard.component';
|
|||||||
})
|
})
|
||||||
export class DashboardPageComponent implements OnInit {
|
export class DashboardPageComponent implements OnInit {
|
||||||
|
|
||||||
displayedColumns: string[] = ['name', 'description'];
|
displayedColumns: string[] = [/*'icon',*/ 'name', 'description'];
|
||||||
dataSource: Dashboard[] = [];
|
dataSource: Dashboard[] = [];
|
||||||
loading = true;
|
loading = true;
|
||||||
error = "";
|
error = "";
|
||||||
|
|||||||
@@ -22,6 +22,10 @@
|
|||||||
.content {
|
.content {
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
}
|
}
|
||||||
|
.dashboard-column {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div *ngIf="dashboard === undefined && !error" class="center">
|
<div *ngIf="dashboard === undefined && !error" class="center">
|
||||||
@@ -40,6 +44,25 @@
|
|||||||
<h1>{{dashboard.name}}</h1>
|
<h1>{{dashboard.name}}</h1>
|
||||||
<p>{{dashboard.description}}</p>
|
<p>{{dashboard.description}}</p>
|
||||||
|
|
||||||
<app-text-widget *ngFor="let textWidget of dashboard.texts" [text]="textWidget.text"></app-text-widget>
|
<div cdkDropListGroup>
|
||||||
<app-plot-widget *ngFor="let p of plotWidgetRenderData" [data]="p"></app-plot-widget>
|
<!-- All lists in here will be connected. -->
|
||||||
|
<div
|
||||||
|
cdkDropList
|
||||||
|
class="dashboard-column"
|
||||||
|
*ngFor="let column of dashboard.arrangement"
|
||||||
|
[cdkDropListData]="column"
|
||||||
|
(cdkDropListDropped)="drop($event)">
|
||||||
|
<div
|
||||||
|
cdkDrag
|
||||||
|
*ngFor="let id of column"
|
||||||
|
[attr.widget-id]="id">
|
||||||
|
<app-text-widget
|
||||||
|
*ngIf="isTextWidget(id)"
|
||||||
|
[text]="getTextWidget(id)!.text"></app-text-widget>
|
||||||
|
<app-plot-widget
|
||||||
|
*ngIf="isPlotWidget(id)"
|
||||||
|
[data]="getPlotWidget(id)!"></app-plot-widget>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
|
||||||
import { HttpErrorResponse } from '@angular/common/http';
|
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 { MatDialog } from '@angular/material/dialog';
|
||||||
import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar';
|
import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
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 { PlotConfig, PlotRequest, PlotResponse, PlotService, RenderOptions } from 'src/app/plot.service';
|
||||||
import { AddPlotDialogComponent } from './add-plot-dialog/add-plot-dialog.component';
|
import { AddPlotDialogComponent } from './add-plot-dialog/add-plot-dialog.component';
|
||||||
import { AddTextDialogComponent } from './add-text-dialog/add-text-dialog.component';
|
import { AddTextDialogComponent } from './add-text-dialog/add-text-dialog.component';
|
||||||
@@ -25,12 +26,14 @@ export class DashboardComponent implements OnInit {
|
|||||||
private service: DashboardService,
|
private service: DashboardService,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private snackBar: MatSnackBar,
|
private snackBar: MatSnackBar,
|
||||||
private plotService: PlotService) {}
|
private plotService: PlotService,
|
||||||
|
private element: ElementRef) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.service.getDashboard(<string>this.route.snapshot.paramMap.get("id")).subscribe({
|
this.service.getDashboard(<string>this.route.snapshot.paramMap.get("id")).subscribe({
|
||||||
'next':(dashboard: Dashboard) => {
|
'next':(dashboard: Dashboard) => {
|
||||||
this.dashboard = dashboard;
|
this.dashboard = dashboard;
|
||||||
|
this.repairArrangement();
|
||||||
|
|
||||||
dashboard.plots.forEach(p => {
|
dashboard.plots.forEach(p => {
|
||||||
this.plotWidgetRenderData.push(new PlotWidgetRenderData(p));
|
this.plotWidgetRenderData.push(new PlotWidgetRenderData(p));
|
||||||
@@ -108,11 +111,39 @@ export class DashboardComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
addText() {
|
||||||
this.dialog.open(AddTextDialogComponent,{
|
this.dialog.open(AddTextDialogComponent,{
|
||||||
width: '600px'
|
width: '600px'
|
||||||
}).afterClosed().subscribe((text: string) => {
|
}).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)',
|
width: 'calc(100% - 1em)',
|
||||||
height: 'calc(100% - 1em)'
|
height: 'calc(100% - 1em)'
|
||||||
}).afterClosed().subscribe((config: PlotConfig) => {
|
}).afterClosed().subscribe((config: PlotConfig) => {
|
||||||
this.dashboard!.plots.push(new PlotWidget('MEDIUM', config));
|
this.dashboard!.plots.push(new PlotWidget(crypto.randomUUID(), 'MEDIUM', config));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
|
const arrangement = <string[][]>[];
|
||||||
|
const dashboardColumns = (<HTMLElement>this.element.nativeElement).querySelectorAll('.dashboard-column');
|
||||||
|
for(let i =0; i < dashboardColumns.length; i++){
|
||||||
|
const ids = [];
|
||||||
|
const column = <HTMLDivElement>dashboardColumns.item(i);
|
||||||
|
for(let c = 0; c <column.children.length; c++) {
|
||||||
|
const element = <Element>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({
|
this.service.saveDashboard(this.dashboard!).subscribe({
|
||||||
'complete': () => {
|
'complete': () => {
|
||||||
this.snackBar.open("saved dashboard","", {
|
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<string[]>) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
|
background-color: aliceblue;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<p *ngFor="let line of lines()">{{line}}</p>
|
<p *ngFor="let line of lines()">{{line}}</p>
|
||||||
|
|||||||
@@ -32,26 +32,36 @@ export class DashboardCreationData{
|
|||||||
constructor(public name: string, public description: string){}
|
constructor(public name: string, public description: string){}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface HasId {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class Dashboard{
|
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{
|
export class DashboardList{
|
||||||
constructor(public dashboards: [Dashboard]){}
|
constructor(public dashboards: [Dashboard]){}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class BaseWidget {
|
export abstract class BaseWidget implements HasId {
|
||||||
constructor(public type: PlotType, public size: PlotSize) {}
|
constructor(public id: string, public type: PlotType, public size: PlotSize) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TextWidget extends BaseWidget {
|
export class TextWidget extends BaseWidget {
|
||||||
constructor(override size: PlotSize, public text: string) {
|
constructor(override id: string, override size: PlotSize, public text: string) {
|
||||||
super('TEXT', size);
|
super(id, 'TEXT', size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class PlotWidget extends BaseWidget {
|
export class PlotWidget extends BaseWidget {
|
||||||
constructor(override size: PlotSize, public config: PlotConfig) {
|
constructor(override id: string, override size: PlotSize, public config: PlotConfig) {
|
||||||
super('PLOT', size);
|
super(id, 'PLOT', size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1
pdb-js/src/assets/img/dashboard-outline.svg
Normal file
1
pdb-js/src/assets/img/dashboard-outline.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M19 5v2h-4V5h4M9 5v6H5V5h4m10 8v6h-4v-6h4M9 17v2H5v-2h4M21 3h-8v6h8V3zM11 3H3v10h8V3zm10 8h-8v10h8V11zm-10 4H3v6h8v-6z"/></svg>
|
||||||
|
After Width: | Height: | Size: 258 B |
@@ -141,6 +141,12 @@ mat-option.mat-option.mat-active {
|
|||||||
background-color: #ccc;
|
background-color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a ,a:visited {
|
||||||
|
color: blue;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
a.external-link:after {
|
a.external-link:after {
|
||||||
background: transparent url('/assets/img/external-link.svg') no-repeat center bottom;
|
background: transparent url('/assets/img/external-link.svg') no-repeat center bottom;
|
||||||
background-size: 0.8em;
|
background-size: 0.8em;
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
package org.lucares.pdbui.dashboard;
|
package org.lucares.pdbui.dashboard;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public abstract class BaseDashboardWidget {
|
public abstract class BaseDashboardWidget {
|
||||||
|
|
||||||
|
private String id = UUID.randomUUID().toString();
|
||||||
|
|
||||||
private DashboardWidgetType type;
|
private DashboardWidgetType type;
|
||||||
|
|
||||||
private DashboardWidgetSize size;
|
private DashboardWidgetSize size;
|
||||||
@@ -15,6 +19,14 @@ public abstract class BaseDashboardWidget {
|
|||||||
this.size = size;
|
this.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(final String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
public DashboardWidgetType getType() {
|
public DashboardWidgetType getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ public class Dashboard {
|
|||||||
|
|
||||||
private List<PlotWidget> plots = new ArrayList<>();
|
private List<PlotWidget> plots = new ArrayList<>();
|
||||||
|
|
||||||
|
private List<List<String>> arrangement = new ArrayList<>();
|
||||||
|
|
||||||
public Dashboard() {
|
public Dashboard() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -77,4 +79,12 @@ public class Dashboard {
|
|||||||
public List<PlotWidget> getPlots() {
|
public List<PlotWidget> getPlots() {
|
||||||
return plots;
|
return plots;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<List<String>> getArrangement() {
|
||||||
|
return arrangement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setArrangement(final List<List<String>> arrangement) {
|
||||||
|
this.arrangement = arrangement;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user