You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2020/02/15 10:41:14 UTC

[incubator-streampipes] branch dev updated: STREAMPIPES-58: Compute correct widget size for dashboard widgets

This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git


The following commit(s) were added to refs/heads/dev by this push:
     new 19a3c7e  STREAMPIPES-58: Compute correct widget size for dashboard widgets
19a3c7e is described below

commit 19a3c7e07a21fdea130f9c94e402b191183fa20a
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Sat Feb 15 11:40:56 2020 +0100

    STREAMPIPES-58: Compute correct widget size for dashboard widgets
---
 .../components/grid/dashboard-grid.component.html  |  6 ++--
 .../components/grid/dashboard-grid.component.ts    | 16 +++++++--
 .../widget/dashboard-widget.component.css          | 15 ++++++++-
 .../widget/dashboard-widget.component.html         | 25 ++++++++------
 .../widget/dashboard-widget.component.ts           |  6 ++--
 .../widgets/base/base-ngx-charts-widget.ts         | 22 +++++++++++--
 .../components/widgets/base/base-widget.ts         | 38 ++++++++++++++++++++--
 .../widgets/gauge/gauge-widget.component.css       | 11 +++++++
 .../widgets/gauge/gauge-widget.component.html      | 25 ++++++++------
 .../widgets/gauge/gauge-widget.component.ts        |  4 +--
 .../widgets/line/line-widget.component.css         |  5 ---
 .../widgets/line/line-widget.component.html        | 15 +++------
 .../components/widgets/number/number-config.ts     |  6 +---
 .../widgets/number/number-widget.component.css     |  1 -
 .../widgets/number/number-widget.component.html    |  6 ++--
 .../widgets/number/number-widget.component.ts      |  4 ---
 .../dashboard-v2/registry/widget-config-builder.ts | 30 +++++++++++++++--
 .../sdk/extractor/static-property-extractor.ts     |  4 +++
 18 files changed, 174 insertions(+), 65 deletions(-)

diff --git a/ui/src/app/dashboard-v2/components/grid/dashboard-grid.component.html b/ui/src/app/dashboard-v2/components/grid/dashboard-grid.component.html
index 7db7753..3bd89ed 100644
--- a/ui/src/app/dashboard-v2/components/grid/dashboard-grid.component.html
+++ b/ui/src/app/dashboard-v2/components/grid/dashboard-grid.component.html
@@ -3,10 +3,10 @@
     <h3>{{dashboard.description}}</h3>
 </div>
 <gridster [options]="options" [ngClass]="editMode ? 'edit' : ''">
-    <ng-container *ngFor="let item of dashboard.widgets">
-        <gridster-item [item]="item">
+    <ng-container *ngFor="let item of dashboard.widgets;let i=index">
+        <gridster-item [item]="item" #gridsterItemComponent>
             <dashboard-widget (deleteCallback)="removeItem($event)" [item]="item" [widget]="item"
-            [editMode]="editMode"></dashboard-widget>
+            [editMode]="editMode" [gridsterItemComponent]="gridsterItemComponent"></dashboard-widget>
         </gridster-item>
     </ng-container>
 </gridster>
\ No newline at end of file
diff --git a/ui/src/app/dashboard-v2/components/grid/dashboard-grid.component.ts b/ui/src/app/dashboard-v2/components/grid/dashboard-grid.component.ts
index 8b6fdaf..c1463f2 100644
--- a/ui/src/app/dashboard-v2/components/grid/dashboard-grid.component.ts
+++ b/ui/src/app/dashboard-v2/components/grid/dashboard-grid.component.ts
@@ -1,8 +1,17 @@
-import {AfterViewInit, Component, Input, OnChanges, OnInit, SimpleChanges} from "@angular/core";
+import {
+    AfterViewInit,
+    Component,
+    Input,
+    OnChanges,
+    OnInit,
+    QueryList,
+    SimpleChanges,
+    ViewChildren
+} from "@angular/core";
 import {Dashboard, DashboardConfig, DashboardItem} from "../../models/dashboard.model";
 import {GridsterInfo} from "../../models/gridster-info.model";
 import {ResizeService} from "../../services/resize.service";
-import {GridType} from "angular-gridster2";
+import {GridsterItemComponent, GridType} from "angular-gridster2";
 import {DashboardService} from "../../services/dashboard.service";
 import {RefreshDashboardService} from "../../services/refresh-dashboard.service";
 
@@ -16,6 +25,9 @@ export class DashboardGridComponent implements OnInit, OnChanges {
     @Input() editMode: boolean;
     @Input() dashboard: Dashboard;
     options: DashboardConfig;
+    loaded: boolean = false;
+
+    @ViewChildren(GridsterItemComponent) gridsterItemComponents: QueryList<GridsterItemComponent>;
 
     constructor(private resizeService: ResizeService,
                 private dashboardService: DashboardService,
diff --git a/ui/src/app/dashboard-v2/components/widget/dashboard-widget.component.css b/ui/src/app/dashboard-v2/components/widget/dashboard-widget.component.css
index 2e70039..5a10c6a 100644
--- a/ui/src/app/dashboard-v2/components/widget/dashboard-widget.component.css
+++ b/ui/src/app/dashboard-v2/components/widget/dashboard-widget.component.css
@@ -2,10 +2,18 @@
     height:100%;
 }
 
+.h-40 {
+    height:40px;
+}
+
 .p-0 {
     padding:0;
 }
 
+.p-20 {
+    padding: 20px;
+}
+
 .m-0 {
     margin:0;
 }
@@ -23,4 +31,9 @@
 
 .box .row.header {
     flex: 0 1 auto;
-}
\ No newline at end of file
+}
+
+/*::ng-deep .ngx-charts {*/
+/*    margin-left:0px;*/
+/*    margin-top:20px;*/
+/*}*/
\ No newline at end of file
diff --git a/ui/src/app/dashboard-v2/components/widget/dashboard-widget.component.html b/ui/src/app/dashboard-v2/components/widget/dashboard-widget.component.html
index d4d491a..55c12d2 100644
--- a/ui/src/app/dashboard-v2/components/widget/dashboard-widget.component.html
+++ b/ui/src/app/dashboard-v2/components/widget/dashboard-widget.component.html
@@ -1,6 +1,6 @@
 <div style="height:100%;">
     <div class="box">
-        <div class="assemblyOptions sp-blue-bg m-0 row header" *ngIf="editMode">
+        <div class="assemblyOptions sp-blue-bg m-0 row header h-40" *ngIf="editMode">
             <div fxFlex="100" layout="row" fxLayoutAlign="end center">
                 <button mat-button mat-icon-button color="white">
                     <i class="material-icons">settings</i>
@@ -14,23 +14,28 @@
             <!--        <div *ngIf="widget."></div>-->
             <div *ngIf="widgetLoaded" class="h-100">
                 <div *ngIf="widget.widgetType === 'number'" class="h-100 p-0">
-                    <number-widget [gridsterItem]="item" [widget]="widget"
-                                   [widgetConfig]="configuredWidget"></number-widget>
+                    <number-widget [gridsterItemComponent]="gridsterItemComponent" [gridsterItem]="item"
+                                   [widget]="widget" [editMode]="editMode"
+                                   [widgetConfig]="configuredWidget" class="h-100"></number-widget>
                 </div>
                 <div *ngIf="widget.widgetType === 'line'" class="h-100 p-0">
-                    <line-widget [gridsterItem]="item" [widget]="widget" [widgetConfig]="configuredWidget"></line-widget>
+                    <line-widget [gridsterItemComponent]="gridsterItemComponent" [editMode]="editMode"
+                                 [gridsterItem]="item" [widget]="widget" [widgetConfig]="configuredWidget" class="h-100"></line-widget>
                 </div>
                 <div *ngIf="widget.widgetType === 'table'" class="h-100 p-0">
-                    <table-widget [gridsterItem]="item" [widget]="widget"
-                                  [widgetConfig]="configuredWidget"></table-widget>
+                    <table-widget [gridsterItemComponent]="gridsterItemComponent"
+                                  [gridsterItem]="item" [widget]="widget" [editMode]="editMode"
+                                  [widgetConfig]="configuredWidget" class="h-100"></table-widget>
                 </div>
                 <div *ngIf="widget.widgetType === 'gauge'" class="h-100 p-0">
-                    <gauge-widget [gridsterItem]="item" [widget]="widget"
-                                  [widgetConfig]="configuredWidget"></gauge-widget>
+                    <gauge-widget [gridsterItemComponent]="gridsterItemComponent"
+                                  [gridsterItem]="item" [widget]="widget" [editMode]="editMode"
+                                  [widgetConfig]="configuredWidget" class="h-100"></gauge-widget>
                 </div>
                 <div *ngIf="widget.widgetType === 'image'" class="h-100 p-0">
-                    <image-widget [gridsterItem]="item" [widget]="widget"
-                                  [widgetConfig]="configuredWidget"></image-widget>
+                    <image-widget [gridsterItemComponent]="gridsterItemComponent"
+                                  [gridsterItem]="item" [widget]="widget" [editMode]="editMode"
+                                  [widgetConfig]="configuredWidget" class="h-100"></image-widget>
                 </div>
             </div>
         </div>
diff --git a/ui/src/app/dashboard-v2/components/widget/dashboard-widget.component.ts b/ui/src/app/dashboard-v2/components/widget/dashboard-widget.component.ts
index 82470e4..8255f20 100644
--- a/ui/src/app/dashboard-v2/components/widget/dashboard-widget.component.ts
+++ b/ui/src/app/dashboard-v2/components/widget/dashboard-widget.component.ts
@@ -1,10 +1,10 @@
-import {AfterViewInit, Component, EventEmitter, Input, OnInit, Output} from "@angular/core";
+import {AfterViewInit, Component, ElementRef, EventEmitter, Input, OnInit, Output} from "@angular/core";
 import {Dashboard, DashboardItem} from "../../models/dashboard.model";
 import {DashboardService} from "../../services/dashboard.service";
 import {DashboardImageComponent} from "../../../app-transport-monitoring/components/dashboard-image/dashboard-image.component";
 import {DashboardWidget} from "../../../core-model/dashboard/DashboardWidget";
 import {Subject} from "rxjs";
-import {GridsterItem} from "angular-gridster2";
+import {GridsterItem, GridsterItemComponent} from "angular-gridster2";
 import {GridsterInfo} from "../../models/gridster-info.model";
 import {ResizeService} from "../../services/resize.service";
 
@@ -18,6 +18,8 @@ export class DashboardWidgetComponent implements OnInit {
     @Input() widget: DashboardItem;
     @Input() editMode: boolean;
     @Input() item: GridsterItem;
+    @Input() gridsterItemComponent: GridsterItemComponent;
+
     @Output() deleteCallback: EventEmitter<DashboardItem> = new EventEmitter<DashboardItem>();
 
     widgetLoaded: boolean = false;
diff --git a/ui/src/app/dashboard-v2/components/widgets/base/base-ngx-charts-widget.ts b/ui/src/app/dashboard-v2/components/widgets/base/base-ngx-charts-widget.ts
index 783dcf3..4706448 100644
--- a/ui/src/app/dashboard-v2/components/widgets/base/base-ngx-charts-widget.ts
+++ b/ui/src/app/dashboard-v2/components/widgets/base/base-ngx-charts-widget.ts
@@ -2,19 +2,24 @@ import {BaseStreamPipesWidget} from "./base-widget";
 import {RxStompService} from "@stomp/ng2-stompjs";
 import {ResizeService} from "../../../services/resize.service";
 import {GridsterInfo} from "../../../models/gridster-info.model";
+import {GridsterItemComponent} from "angular-gridster2";
 
 export abstract class BaseNgxChartsStreamPipesWidget extends BaseStreamPipesWidget {
 
     view: any[] = [];
     displayChart: boolean = false;
 
+    colorScheme: any;
+
     constructor(rxStompService: RxStompService, protected resizeService: ResizeService) {
         super(rxStompService);
     }
 
     ngOnInit() {
         super.ngOnInit();
-        this.view = [this.gridsterItem.width, this.gridsterItem.height];
+        this.colorScheme = {domain: [this.selectedSecondaryTextColor, this.selectedPrimaryTextColor]};
+        this.view = [this.computeCurrentWidth(this.gridsterItemComponent),
+            this.computeCurrentHeight(this.gridsterItemComponent)];
         this.displayChart = true;
         this.resizeService.resizeSubject.subscribe(info => {
             this.onResize(info);
@@ -25,10 +30,23 @@ export abstract class BaseNgxChartsStreamPipesWidget extends BaseStreamPipesWidg
         if (info.gridsterItem.id === this.gridsterItem.id) {
             setTimeout(() => {
                 this.displayChart = false;
-                this.view = [info.gridsterItemComponent.width, info.gridsterItemComponent.height];
+                this.view = [this.computeCurrentWidth(info.gridsterItemComponent),
+                    this.computeCurrentHeight(info.gridsterItemComponent)];
                 this.displayChart = true;
             }, 100);
         }
     }
 
+    computeCurrentWidth(gridsterItemComponent: GridsterItemComponent): number {
+        return (gridsterItemComponent.width - (BaseNgxChartsStreamPipesWidget.PADDING * 2));
+    }
+
+    computeCurrentHeight(gridsterItemComponent: GridsterItemComponent): number {
+        return (gridsterItemComponent.height - (BaseNgxChartsStreamPipesWidget.PADDING * 2) - this.editModeOffset());
+    }
+
+    editModeOffset(): number {
+        return this.editMode ? BaseNgxChartsStreamPipesWidget.EDIT_HEADER_HEIGHT : 0;
+    }
+
 }
\ No newline at end of file
diff --git a/ui/src/app/dashboard-v2/components/widgets/base/base-widget.ts b/ui/src/app/dashboard-v2/components/widgets/base/base-widget.ts
index 4301c0c..e261683 100644
--- a/ui/src/app/dashboard-v2/components/widgets/base/base-widget.ts
+++ b/ui/src/app/dashboard-v2/components/widgets/base/base-widget.ts
@@ -5,21 +5,55 @@ import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-ex
 import {RxStompService} from "@stomp/ng2-stompjs";
 import {Message} from "@stomp/stompjs";
 import {Subscription} from "rxjs";
-import {GridsterItem} from "angular-gridster2";
+import {GridsterItem, GridsterItemComponent} from "angular-gridster2";
+import {WidgetConfigBuilder} from "../../../registry/widget-config-builder";
 
 export abstract class BaseStreamPipesWidget {
 
     @Input() widget: DashboardItem;
     @Input() widgetConfig: DashboardWidget;
     @Input() gridsterItem: GridsterItem;
+    @Input() gridsterItemComponent: GridsterItemComponent;
+    @Input() editMode: boolean;
+
+    static readonly PADDING: number = 20;
+    static readonly EDIT_HEADER_HEIGHT: number = 40;
 
     subscription: Subscription;
 
+    hasSelectableColorSettings: boolean;
+    hasTitlePanelSettings: boolean;
+
+    selectedBackgroundColor: string;
+    selectedPrimaryTextColor: string;
+    selectedSecondaryTextColor: string;
+    selectedTitle: string;
+
+    defaultBackgroundColor: string = "#1B1464";
+    defaultPrimaryTextColor: string = "#FFFFFF";
+    defaultSecondaryTextColor: string = "#39B54A";
+
     protected constructor(private rxStompService: RxStompService) {
     }
 
     ngOnInit(): void {
-        this.extractConfig(new StaticPropertyExtractor(this.widgetConfig.dashboardWidgetDataConfig.schema, this.widgetConfig.dashboardWidgetSettings.config));
+        let extractor: StaticPropertyExtractor = new StaticPropertyExtractor(this.widgetConfig.dashboardWidgetDataConfig.schema, this.widgetConfig.dashboardWidgetSettings.config);
+        if (extractor.hasStaticProperty(WidgetConfigBuilder.BACKGROUND_COLOR_KEY)) {
+            this.hasSelectableColorSettings = true;
+            this.selectedBackgroundColor = extractor.selectedColor(WidgetConfigBuilder.BACKGROUND_COLOR_KEY);
+            this.selectedPrimaryTextColor = extractor.selectedColor(WidgetConfigBuilder.PRIMARY_TEXT_COLOR_KEY);
+            this.selectedSecondaryTextColor = extractor.selectedColor(WidgetConfigBuilder.SECONDARY_TEXT_COLOR_KEY);
+        } else {
+            this.selectedBackgroundColor = this.defaultBackgroundColor;
+            this.selectedPrimaryTextColor = this.defaultPrimaryTextColor;
+            this.selectedSecondaryTextColor = this.defaultSecondaryTextColor;
+        }
+        if (extractor.hasStaticProperty(WidgetConfigBuilder.TITLE_KEY)) {
+            this.hasTitlePanelSettings = true;
+            this.selectedTitle = extractor.stringParameter(WidgetConfigBuilder.TITLE_KEY);
+        }
+
+        this.extractConfig(extractor);
         this.subscription = this.rxStompService.watch("/topic/" +this.widgetConfig.dashboardWidgetDataConfig.topic).subscribe((message: Message) => {
             this.onEvent(JSON.parse(message.body));
         });
diff --git a/ui/src/app/dashboard-v2/components/widgets/gauge/gauge-widget.component.css b/ui/src/app/dashboard-v2/components/widgets/gauge/gauge-widget.component.css
index e69de29..4f48d9a 100644
--- a/ui/src/app/dashboard-v2/components/widgets/gauge/gauge-widget.component.css
+++ b/ui/src/app/dashboard-v2/components/widgets/gauge/gauge-widget.component.css
@@ -0,0 +1,11 @@
+.main-panel {
+    width:100%;
+    height: 100%;
+    display:inline-grid;
+    align-content: center;
+}
+
+/*::ng-deep .ngx-charts {*/
+/*    margin-left:0px;*/
+/*    margin-top:20px;*/
+/*}*/
\ No newline at end of file
diff --git a/ui/src/app/dashboard-v2/components/widgets/gauge/gauge-widget.component.html b/ui/src/app/dashboard-v2/components/widgets/gauge/gauge-widget.component.html
index e066fd9..d77d3df 100644
--- a/ui/src/app/dashboard-v2/components/widgets/gauge/gauge-widget.component.html
+++ b/ui/src/app/dashboard-v2/components/widgets/gauge/gauge-widget.component.html
@@ -1,10 +1,15 @@
-<ngx-charts-gauge
-        [view]="view"
-        [results]="data"
-        [min]="min"
-        [max]="max"
-        [angleSpan]="240"
-        [startAngle]="-120"
-        [bigSegments]="10"
-        [smallSegments]="5">
-</ngx-charts-gauge>
\ No newline at end of file
+<div fxFlex="100" fxLayoutAlign="center center" fxLayout="column" class="main-panel"
+     [ngStyle]="{'background-color': selectedBackgroundColor, 'color': selectedPrimaryTextColor}">
+    <ngx-charts-gauge
+            [view]="view"
+            [scheme]="colorScheme"
+            [results]="data"
+            [min]="min"
+            [max]="max"
+            [angleSpan]="240"
+            [startAngle]="-120"
+            [bigSegments]="10"
+            [smallSegments]="5"
+            [ngStyle]="{'fill': selectedPrimaryTextColor}" *ngIf="displayChart">
+    </ngx-charts-gauge>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/dashboard-v2/components/widgets/gauge/gauge-widget.component.ts b/ui/src/app/dashboard-v2/components/widgets/gauge/gauge-widget.component.ts
index 432b614..7ee82fe 100644
--- a/ui/src/app/dashboard-v2/components/widgets/gauge/gauge-widget.component.ts
+++ b/ui/src/app/dashboard-v2/components/widgets/gauge/gauge-widget.component.ts
@@ -1,4 +1,4 @@
-import {Component, OnDestroy, OnInit} from "@angular/core";
+import {AfterViewInit, Component, ElementRef, OnDestroy, OnInit} from "@angular/core";
 import {BaseNgxChartsStreamPipesWidget} from "../base/base-ngx-charts-widget";
 import {RxStompService} from "@stomp/ng2-stompjs";
 import {ResizeService} from "../../../services/resize.service";
@@ -21,7 +21,7 @@ export class GaugeWidgetComponent extends BaseNgxChartsStreamPipesWidget impleme
 
     selectedProperty: string;
 
-    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
+    constructor(rxStompService: RxStompService, resizeService: ResizeService, private el: ElementRef) {
         super(rxStompService, resizeService);
     }
 
diff --git a/ui/src/app/dashboard-v2/components/widgets/line/line-widget.component.css b/ui/src/app/dashboard-v2/components/widgets/line/line-widget.component.css
index 65c8a0f..0f2195f 100644
--- a/ui/src/app/dashboard-v2/components/widgets/line/line-widget.component.css
+++ b/ui/src/app/dashboard-v2/components/widgets/line/line-widget.component.css
@@ -3,9 +3,4 @@
     height: 100%;
     display:inline-grid;
     align-content: center;
-}
-
-::ng-deep .ngx-charts {
-    margin-left: 15px;
-    margin-top: -10px;
 }
\ No newline at end of file
diff --git a/ui/src/app/dashboard-v2/components/widgets/line/line-widget.component.html b/ui/src/app/dashboard-v2/components/widgets/line/line-widget.component.html
index 1186c59..0d7e10f 100644
--- a/ui/src/app/dashboard-v2/components/widgets/line/line-widget.component.html
+++ b/ui/src/app/dashboard-v2/components/widgets/line/line-widget.component.html
@@ -1,8 +1,9 @@
-<div fxFlex="100" fxLayoutAlign="center center" fxLayout="column" class="main-panel">
+<div fxFlex="100" fxLayoutAlign="center center" fxLayout="column" class="main-panel" [ngStyle]="{'background-color': selectedBackgroundColor, 'color': selectedPrimaryTextColor}">
     <ngx-charts-line-chart *ngIf="displayChart"
                            [showXAxisLabel]="false"
                            [showYAxisLabel]="false"
-                           [timeline]="true"
+                           [scheme]="colorScheme"
+                           [timeline]="false"
                            [view]="view"
                            [autoScale]="true"
                            [xAxis]="true"
@@ -10,14 +11,8 @@
                            [tooltipDisabled]="true"
                            [animations]="false"
                            [xAxisTickFormatting]="timestampTickFormatting"
-                           [results]="multi" style="margin-top:10px;margin-bottom:10px;">
+                           [results]="multi" style="margin-top:10px;margin-bottom:10px;"
+                           [ngStyle]="{'fill': selectedPrimaryTextColor}">
     </ngx-charts-line-chart>
 </div>
-<!--<ngx-charts-number-card *ngIf="displayChart" #chart-->
-<!--                        [results]="[{'name' : 'test', 'value': 'ads'}]"-->
-<!--                        [scheme]="'cool'"-->
-<!--                        [cardColor]="'blue'"-->
-<!--                        [bandColor]="'rgb(27, 20, 100)'"-->
-<!--                        [view]="view">-->
-<!--</ngx-charts-number-card>-->
 
diff --git a/ui/src/app/dashboard-v2/components/widgets/number/number-config.ts b/ui/src/app/dashboard-v2/components/widgets/number/number-config.ts
index 0d49699..070e32e 100644
--- a/ui/src/app/dashboard-v2/components/widgets/number/number-config.ts
+++ b/ui/src/app/dashboard-v2/components/widgets/number/number-config.ts
@@ -6,22 +6,18 @@ import {WidgetConfig} from "../base/base-config";
 
 export class NumberConfig extends WidgetConfig {
 
-    static readonly TITLE_KEY: string = "title-key";
     static readonly NUMBER_MAPPING_KEY: string = "number-mapping";
-    static readonly COLOR_KEY: string = "color-key";
 
     constructor() {
         super();
     }
 
     getConfig(): DashboardWidgetSettings {
-        return WidgetConfigBuilder.create("number", "number")
+        return WidgetConfigBuilder.createWithSelectableColorsAndTitlePanel("number", "number")
             .requiredSchema(SchemaRequirementsBuilder
                 .create()
                 .requiredPropertyWithUnaryMapping(NumberConfig.NUMBER_MAPPING_KEY, "Select property", "", EpRequirements.numberReq())
                 .build())
-            .requiredTextParameter(NumberConfig.TITLE_KEY, "Title", "The title")
-            .requiredColorParameter(NumberConfig.COLOR_KEY, "Background color", "The background color", "#000000")
             .build();
     }
 
diff --git a/ui/src/app/dashboard-v2/components/widgets/number/number-widget.component.css b/ui/src/app/dashboard-v2/components/widgets/number/number-widget.component.css
index f8cf1c7..501a8ae 100644
--- a/ui/src/app/dashboard-v2/components/widgets/number/number-widget.component.css
+++ b/ui/src/app/dashboard-v2/components/widgets/number/number-widget.component.css
@@ -1,7 +1,6 @@
 .circleNumber {
     width:100%;
     height: 100%;
-    color: #fff;
     text-align: center;
     left: 50%;
     display:inline-grid;
diff --git a/ui/src/app/dashboard-v2/components/widgets/number/number-widget.component.html b/ui/src/app/dashboard-v2/components/widgets/number/number-widget.component.html
index 314de1e..c8882d9 100644
--- a/ui/src/app/dashboard-v2/components/widgets/number/number-widget.component.html
+++ b/ui/src/app/dashboard-v2/components/widgets/number/number-widget.component.html
@@ -1,6 +1,6 @@
-<div class="circleNumber" [ngStyle]="{'background-color': color}">
-    <div class="numberTitle">
-        {{title}}
+<div class="circleNumber" [ngStyle]="{'background-color': selectedBackgroundColor, 'color': selectedPrimaryTextColor}">
+    <div class="numberTitle" *ngIf="hasTitlePanelSettings">
+        {{selectedTitle}}
     </div>
     <div class="numberItem">
         <div *ngIf="isNumber(item)">{{item}}</div>
diff --git a/ui/src/app/dashboard-v2/components/widgets/number/number-widget.component.ts b/ui/src/app/dashboard-v2/components/widgets/number/number-widget.component.ts
index 1c127c1..59ea982 100644
--- a/ui/src/app/dashboard-v2/components/widgets/number/number-widget.component.ts
+++ b/ui/src/app/dashboard-v2/components/widgets/number/number-widget.component.ts
@@ -12,8 +12,6 @@ import {NumberConfig} from "./number-config";
 export class NumberWidgetComponent extends BaseStreamPipesWidget implements OnInit, OnDestroy {
 
     item: any;
-    title: string;
-    color: string = "green";
 
     selectedProperty: string;
 
@@ -30,8 +28,6 @@ export class NumberWidgetComponent extends BaseStreamPipesWidget implements OnIn
     }
 
     extractConfig(extractor: StaticPropertyExtractor) {
-        this.color = extractor.selectedColor(NumberConfig.COLOR_KEY);
-        this.title = extractor.singleValueParameter(NumberConfig.TITLE_KEY);
         this.selectedProperty = extractor.mappingPropertyValue(NumberConfig.NUMBER_MAPPING_KEY);
     }
 
diff --git a/ui/src/app/dashboard-v2/registry/widget-config-builder.ts b/ui/src/app/dashboard-v2/registry/widget-config-builder.ts
index d5872ea..eba4ea2 100644
--- a/ui/src/app/dashboard-v2/registry/widget-config-builder.ts
+++ b/ui/src/app/dashboard-v2/registry/widget-config-builder.ts
@@ -1,26 +1,50 @@
 import {FreeTextStaticProperty} from "../../connect/model/FreeTextStaticProperty";
 import {CollectedSchemaRequirements} from "../sdk/collected-schema-requirements";
-import {EventSchema} from "../../connect/schema-editor/model/EventSchema";
 import {DashboardWidgetSettings} from "../../core-model/dashboard/DashboardWidgetSettings";
-import {Vocabulary} from "../sdk/model/vocabulary";
 import {Datatypes} from "../sdk/model/datatypes";
 import {ColorPickerStaticProperty} from "../../connect/model/ColorPickerStaticProperty";
 
 export class WidgetConfigBuilder {
 
+    static readonly BACKGROUND_COLOR_KEY: string = "spi-background-color-key";
+    static readonly PRIMARY_TEXT_COLOR_KEY: string = "spi-primary-text-color-key";
+    static readonly SECONDARY_TEXT_COLOR_KEY: string = "spi-secondary-text-color-key";
+
+    static readonly TITLE_KEY: string = "title-key";
+
     private widget: DashboardWidgetSettings;
 
-    private constructor(widgetName: string, widgetLabel: string) {
+    private constructor(widgetName: string, widgetLabel: string, withColors?: boolean, withTitlePanel?: boolean) {
         this.widget = new DashboardWidgetSettings();
         this.widget.widgetLabel = widgetLabel;
         this.widget.widgetName = widgetName;
         this.widget.config = [];
+        if (withColors) {
+        this.requiredColorParameter(WidgetConfigBuilder.BACKGROUND_COLOR_KEY, "Background color", "The background" +
+            " color", "#000000");
+        this.requiredColorParameter(WidgetConfigBuilder.PRIMARY_TEXT_COLOR_KEY, "Primary text color", "The" +
+                " primary text color", "#707070");
+        this.requiredColorParameter(WidgetConfigBuilder.SECONDARY_TEXT_COLOR_KEY, "Secondary text color", "The" +
+            " secondary text" +
+            " color", "#bebebe")
+        }
+        if (withTitlePanel) {
+        this.requiredTextParameter(WidgetConfigBuilder.TITLE_KEY.TITLE_KEY, "Title", "The title")
+        }
     }
 
     static create(widgetName: string, widgetLabel: string): WidgetConfigBuilder {
         return new WidgetConfigBuilder(widgetName, widgetLabel);
     }
 
+    static createWithSelectableColors(widgetName: string, widgetLabel: string): WidgetConfigBuilder {
+        return new WidgetConfigBuilder(widgetName, widgetLabel, true);
+    }
+
+    static createWithSelectableColorsAndTitlePanel(widgetName: string, widgetLabel: string): WidgetConfigBuilder {
+        return new WidgetConfigBuilder(widgetName, widgetLabel, true, true);
+    }
+
     requiredTextParameter(id: string, label: string, description: string): WidgetConfigBuilder {
         let fst: FreeTextStaticProperty = this.prepareStaticProperty(id, label, description, Datatypes.String.toUri())
         this.widget.config.push(fst);
diff --git a/ui/src/app/dashboard-v2/sdk/extractor/static-property-extractor.ts b/ui/src/app/dashboard-v2/sdk/extractor/static-property-extractor.ts
index f17cb61..de7c084 100644
--- a/ui/src/app/dashboard-v2/sdk/extractor/static-property-extractor.ts
+++ b/ui/src/app/dashboard-v2/sdk/extractor/static-property-extractor.ts
@@ -12,6 +12,10 @@ export class StaticPropertyExtractor {
 
     }
 
+    hasStaticProperty(internalId: string): boolean {
+        return this.getStaticPropertyByName(internalId) !== undefined;
+    }
+
     mappingPropertyValue(internalId: string): string {
         let sp: MappingPropertyUnary = this.getStaticPropertyByName(internalId) as MappingPropertyUnary;
         return this.removePrefix(sp.selectedProperty);