Browse Source

UI: Add flot datakey and latest datakey settings forms

pull/6545/head
Igor Kulikov 4 years ago
parent
commit
8fdf12bb2a
  1. 12
      application/src/main/data/json/system/widget_bundles/charts.json
  2. 814
      ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts
  3. 15
      ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts
  4. 24
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-bar-key-settings.component.html
  5. 55
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-bar-key-settings.component.ts
  6. 238
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html
  7. 333
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts
  8. 47
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html
  9. 74
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.ts
  10. 24
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-line-key-settings.component.html
  11. 55
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-line-key-settings.component.ts
  12. 57
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html
  13. 40
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss
  14. 136
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts
  15. 1
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts
  16. 30
      ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts
  17. 35
      ui-ngx/src/assets/locale/locale.constant-en_US.json

12
application/src/main/data/json/system/widget_bundles/charts.json

@ -146,10 +146,12 @@
"resources": [],
"templateHtml": "",
"templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n",
"controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'state'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.flot.latestDataUpdate();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.typeParameters = function() {\n return {\n stateData: true,\n hasAdditionalLatestDataKeys: true\n };\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true, 'graph');\n}\n\nself.getLatestDataKeySettingsSchema = function() {\n return TbFlot.latestDatakeySettingsSchema();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n",
"controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'state'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.flot.latestDataUpdate();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.typeParameters = function() {\n return {\n stateData: true,\n hasAdditionalLatestDataKeys: true\n };\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n",
"settingsSchema": "{}",
"dataKeySettingsSchema": "{}",
"settingsDirective": "tb-flot-line-widget-settings",
"dataKeySettingsDirective": "tb-flot-line-key-settings",
"latestDataKeySettingsDirective": "tb-flot-latest-key-settings",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\",\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":false,\"tooltipIndividual\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"smoothLines\":false},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"direction\":\"column\",\",position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false}}"
}
},
@ -165,11 +167,13 @@
"resources": [],
"templateHtml": "",
"templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n",
"controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.flot.latestDataUpdate();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true, 'graph');\n}\n\nself.getLatestDataKeySettingsSchema = function() {\n return TbFlot.latestDatakeySettingsSchema();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: true\n };\n}\n",
"controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.flot.latestDataUpdate();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: true\n };\n}\n",
"settingsSchema": "{}",
"dataKeySettingsSchema": "{}",
"latestDataKeySettingsSchema": "{}",
"settingsDirective": "tb-flot-line-widget-settings",
"dataKeySettingsDirective": "tb-flot-line-key-settings",
"latestDataKeySettingsDirective": "tb-flot-latest-key-settings",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"legend\":{\"show\":true,\"position\":\"nw\",\"backgroundColor\":\"#f0f0f0\",\"backgroundOpacity\":0.85,\"labelBoxBorderColor\":\"rgba(1, 1, 1, 0.45)\"},\"decimals\":1,\"stack\":false,\"tooltipIndividual\":false},\"title\":\"Timeseries Line Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}"
}
},
@ -185,10 +189,12 @@
"resources": [],
"templateHtml": "",
"templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n",
"controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'bar'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.flot.latestDataUpdate();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(false, 'bar');\n}\n\nself.getLatestDataKeySettingsSchema = function() {\n return TbFlot.latestDatakeySettingsSchema();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: true\n };\n}\n",
"controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'bar'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.flot.latestDataUpdate();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: true\n };\n}\n",
"settingsSchema": "{}",
"dataKeySettingsSchema": "{}",
"settingsDirective": "tb-flot-bar-widget-settings",
"dataKeySettingsDirective": "tb-flot-bar-key-settings",
"latestDataKeySettingsDirective": "tb-flot-latest-key-settings",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000},\"aggregation\":{\"limit\":200,\"type\":\"AVG\"}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":true,\"tooltipIndividual\":false,\"defaultBarWidth\":600},\"title\":\"Timeseries Bar Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{}}"
}
}

814
ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts

@ -18,7 +18,6 @@
/// <reference path="../../../../../../../src/typings/jquery.flot.typings.d.ts" />
import { DataKey, Datasource, DatasourceData, JsonSettingsSchema } from '@shared/models/widget.models';
import * as moment_ from 'moment';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { ComparisonDuration } from '@shared/models/time/time.models';
@ -163,13 +162,15 @@ export interface TbFlotLabelPatternSettings {
settings?: any;
}
export interface TbFlotGraphSettings extends TbFlotBaseSettings, TbFlotThresholdsSettings, TbFlotComparisonSettings, TbFlotCustomLegendSettings {
export interface TbFlotGraphSettings extends TbFlotBaseSettings,
TbFlotThresholdsSettings, TbFlotComparisonSettings, TbFlotCustomLegendSettings {
smoothLines: boolean;
}
export declare type BarAlignment = 'left' | 'right' | 'center';
export interface TbFlotBarSettings extends TbFlotBaseSettings, TbFlotThresholdsSettings, TbFlotComparisonSettings, TbFlotCustomLegendSettings {
export interface TbFlotBarSettings extends TbFlotBaseSettings,
TbFlotThresholdsSettings, TbFlotComparisonSettings, TbFlotCustomLegendSettings {
defaultBarWidth: number;
barAlignment: BarAlignment;
}
@ -183,7 +184,7 @@ export interface TbFlotPieSettings {
color: string;
width: number;
};
showTooltip: boolean,
showTooltip: boolean;
showLabels: boolean;
fontColor: string;
fontSize: number;
@ -241,480 +242,6 @@ export interface TbFlotLatestKeySettings {
thresholdColor: string;
}
export function flotSettingsSchema(chartType: ChartType): JsonSettingsSchema {
const schema: JsonSettingsSchema = {
schema: {
type: 'object',
title: 'Settings',
properties: {
}
}
};
const properties: any = schema.schema.properties;
properties.stack = {
title: 'Stacking',
type: 'boolean',
default: false
};
if (chartType === 'graph') {
properties.smoothLines = {
title: 'Display smooth (curved) lines',
type: 'boolean',
default: false
};
}
if (chartType === 'bar') {
properties.defaultBarWidth = {
title: 'Default bar width for non-aggregated data (milliseconds)',
type: 'number',
default: 600
};
properties.barAlignment = {
title: 'Bar alignment',
type: 'string',
default: 'left'
};
}
if (chartType === 'graph' || chartType === 'bar') {
properties.thresholdsLineWidth = {
title: 'Default line width for all thresholds',
type: 'number'
};
}
properties.shadowSize = {
title: 'Shadow size',
type: 'number',
default: 4
};
properties.fontColor = {
title: 'Font color',
type: 'string',
default: '#545454'
};
properties.fontSize = {
title: 'Font size',
type: 'number',
default: 10
};
properties.tooltipIndividual = {
title: 'Hover individual points',
type: 'boolean',
default: false
};
properties.tooltipCumulative = {
title: 'Show cumulative values in stacking mode',
type: 'boolean',
default: false
};
properties.tooltipValueFormatter = {
title: 'Tooltip value format function, f(value)',
type: 'string',
default: ''
};
properties.hideZeros = {
title: 'Hide zero/false values from tooltip',
type: 'boolean',
default: false
};
properties.showTooltip = {
title: 'Show tooltip',
type: 'boolean',
default: true
};
properties.grid = {
title: 'Grid settings',
type: 'object',
properties: {
color: {
title: 'Primary color',
type: 'string',
default: '#545454'
},
backgroundColor: {
title: 'Background color',
type: 'string',
default: null
},
tickColor: {
title: 'Ticks color',
type: 'string',
default: '#DDDDDD'
},
outlineWidth: {
title: 'Grid outline/border width (px)',
type: 'number',
default: 1
},
verticalLines: {
title: 'Show vertical lines',
type: 'boolean',
default: true
},
horizontalLines: {
title: 'Show horizontal lines',
type: 'boolean',
default: true
}
}
};
properties.xaxis = {
title: 'X axis settings',
type: 'object',
properties: {
showLabels: {
title: 'Show labels',
type: 'boolean',
default: true
},
title: {
title: 'Axis title',
type: 'string',
default: null
},
color: {
title: 'Ticks color',
type: 'string',
default: null
}
}
};
properties.yaxis = {
title: 'Y axis settings',
type: 'object',
properties: {
min: {
title: 'Minimum value on the scale',
type: 'number',
default: null
},
max: {
title: 'Maximum value on the scale',
type: 'number',
default: null
},
showLabels: {
title: 'Show labels',
type: 'boolean',
default: true
},
title: {
title: 'Axis title',
type: 'string',
default: null
},
color: {
title: 'Ticks color',
type: 'string',
default: null
},
ticksFormatter: {
title: 'Ticks formatter function, f(value)',
type: 'string',
default: ''
},
tickDecimals: {
title: 'The number of decimals to display',
type: 'number',
default: 0
},
tickSize: {
title: 'Step size between ticks',
type: 'number',
default: null
}
}
};
schema.schema.required = [];
schema.form = ['stack'];
if (chartType === 'graph') {
schema.form.push('smoothLines');
}
if (chartType === 'bar') {
schema.form.push('defaultBarWidth');
schema.form.push({
key: 'barAlignment',
type: 'rc-select',
multiple: false,
items: [
{
value: 'left',
label: 'Left'
},
{
value: 'right',
label: 'Right'
},
{
value: 'center',
label: 'Center'
}
]
});
}
if (chartType === 'graph' || chartType === 'bar') {
schema.form.push('thresholdsLineWidth');
}
schema.form.push('shadowSize');
schema.form.push({
key: 'fontColor',
type: 'color'
});
schema.form.push('fontSize');
schema.form.push('tooltipIndividual');
schema.form.push('tooltipCumulative');
schema.form.push({
key: 'tooltipValueFormatter',
type: 'javascript',
helpId: 'widget/lib/flot/tooltip_value_format_fn'
});
schema.form.push('hideZeros');
schema.form.push('showTooltip');
schema.form.push({
key: 'grid',
items: [
{
key: 'grid.color',
type: 'color'
},
{
key: 'grid.backgroundColor',
type: 'color'
},
{
key: 'grid.tickColor',
type: 'color'
},
'grid.outlineWidth',
'grid.verticalLines',
'grid.horizontalLines'
]
});
schema.form.push({
key: 'xaxis',
items: [
'xaxis.showLabels',
'xaxis.title',
{
key: 'xaxis.color',
type: 'color'
}
]
});
schema.form.push({
key: 'yaxis',
items: [
'yaxis.min',
'yaxis.max',
'yaxis.tickDecimals',
'yaxis.tickSize',
'yaxis.showLabels',
'yaxis.title',
{
key: 'yaxis.color',
type: 'color'
},
{
key: 'yaxis.ticksFormatter',
type: 'javascript',
helpId: 'widget/lib/flot/ticks_formatter_fn'
}
]
});
if (chartType === 'graph' || chartType === 'bar') {
schema.groupInfoes = [{
formIndex: 0,
GroupTitle: 'Common Settings'
}];
schema.form = [schema.form];
schema.schema.properties = {...schema.schema.properties, ...chartSettingsSchemaForComparison.schema.properties, ...chartSettingsSchemaForCustomLegend.schema.properties};
schema.schema.required = schema.schema.required.concat(chartSettingsSchemaForComparison.schema.required, chartSettingsSchemaForCustomLegend.schema.required);
schema.form.push(chartSettingsSchemaForComparison.form, chartSettingsSchemaForCustomLegend.form);
schema.groupInfoes.push({
formIndex: schema.groupInfoes.length,
GroupTitle: 'Comparison Settings'
});
schema.groupInfoes.push({
formIndex: schema.groupInfoes.length,
GroupTitle: 'Custom Legend Settings'
});
}
return schema;
}
const chartSettingsSchemaForComparison: JsonSettingsSchema = {
schema: {
title: 'Comparison Settings',
type: 'object',
properties: {
comparisonEnabled: {
title: 'Enable comparison',
type: 'boolean',
default: false
},
timeForComparison: {
title: 'Time to show historical data',
type: 'string',
default: 'previousInterval'
},
comparisonCustomIntervalValue: {
title: 'Custom interval value (ms)',
type: 'number',
default: 7200000
},
xaxisSecond: {
title: 'Second X axis',
type: 'object',
properties: {
axisPosition: {
title: 'Axis position',
type: 'string',
default: 'top'
},
showLabels: {
title: 'Show labels',
type: 'boolean',
default: true
},
title: {
title: 'Axis title',
type: 'string',
default: null
}
}
}
},
required: []
},
form: [
'comparisonEnabled',
{
key: 'timeForComparison',
type: 'rc-select',
multiple: false,
items: [
{
value: 'previousInterval',
label: 'Previous interval (default)'
},
{
value: 'days',
label: 'Day ago'
},
{
value: 'weeks',
label: 'Week ago'
},
{
value: 'months',
label: 'Month ago'
},
{
value: 'years',
label: 'Year ago'
},
{
value: 'customInterval',
label: 'Custom interval'
}
]
},
{
key: 'comparisonCustomIntervalValue',
condition: 'model.timeForComparison === "customInterval"'
},
{
key: 'xaxisSecond',
items: [
{
key: 'xaxisSecond.axisPosition',
type: 'rc-select',
multiple: false,
items: [
{
value: 'top',
label: 'Top (default)'
},
{
value: 'bottom',
label: 'Bottom'
}
]
},
'xaxisSecond.showLabels',
'xaxisSecond.title',
]
}
]
};
const chartSettingsSchemaForCustomLegend: JsonSettingsSchema = {
schema: {
title: 'Custom Legend Settings',
type: 'object',
properties: {
customLegendEnabled: {
title: 'Enable custom legend (this will allow you to use attribute/timeseries values in key labels)',
type: 'boolean',
default: false
},
dataKeysListForLabels: {
title: 'Datakeys list to use in labels',
type: 'array',
items: {
type: 'object',
properties: {
name: {
title: 'Key name',
type: 'string'
},
type: {
title: 'Key type',
type: 'string',
default: 'attribute'
}
},
required: [
'name'
]
}
}
},
required: []
},
form: [
'customLegendEnabled',
{
key: 'dataKeysListForLabels',
condition: 'model.customLegendEnabled === true',
items: [
{
key: 'dataKeysListForLabels[].type',
type: 'rc-select',
multiple: false,
items: [
{
value: 'attribute',
label: 'Attribute'
},
{
value: 'timeseries',
label: 'Timeseries'
}
]
},
'dataKeysListForLabels[].name'
]
}
]
};
export const flotPieSettingsSchema: JsonSettingsSchema = {
schema: {
type: 'object',
@ -833,334 +360,3 @@ export const flotPieDatakeySettingsSchema: JsonSettingsSchema = {
'removeFromLegend'
]
};
export function flotDatakeySettingsSchema(defaultShowLines: boolean, chartType: ChartType): JsonSettingsSchema {
const schema: JsonSettingsSchema = {
schema: {
type: 'object',
title: 'DataKeySettings',
properties: {
excludeFromStacking: {
title: 'Exclude from stacking(available in "Stacking" mode)',
type: 'boolean',
default: false
},
hideDataByDefault: {
title: 'Data is hidden by default',
type: 'boolean',
default: false
},
disableDataHiding: {
title: 'Disable data hiding',
type: 'boolean',
default: false
},
removeFromLegend: {
title: 'Remove datakey from legend',
type: 'boolean',
default: false
},
showLines: {
title: 'Show lines',
type: 'boolean',
default: defaultShowLines
},
fillLines: {
title: 'Fill lines',
type: 'boolean',
default: false
},
showPoints: {
title: 'Show points',
type: 'boolean',
default: false
},
showPointShape: {
title: 'Select point shape:',
type: 'string',
default: 'circle'
},
pointShapeFormatter: {
title: 'Point shape format function, f(ctx, x, y, radius, shadow)',
type: 'string',
default: 'var size = radius * Math.sqrt(Math.PI) / 2;\n' +
'ctx.moveTo(x - size, y - size);\n' +
'ctx.lineTo(x + size, y + size);\n' +
'ctx.moveTo(x - size, y + size);\n' +
'ctx.lineTo(x + size, y - size);'
},
showPointsLineWidth: {
title: 'Line width of points',
type: 'number',
default: 5
},
showPointsRadius: {
title: 'Radius of points',
type: 'number',
default: 3
},
tooltipValueFormatter: {
title: 'Tooltip value format function, f(value)',
type: 'string',
default: ''
},
showSeparateAxis: {
title: 'Show separate axis',
type: 'boolean',
default: false
},
axisMin: {
title: 'Minimum value on the axis scale',
type: 'number',
default: null
},
axisMax: {
title: 'Maximum value on the axis scale',
type: 'number',
default: null
},
axisTitle: {
title: 'Axis title',
type: 'string',
default: ''
},
axisTickDecimals: {
title: 'Axis tick number of digits after floating point',
type: 'number',
default: null
},
axisTickSize: {
title: 'Axis step size between ticks',
type: 'number',
default: null
},
axisPosition: {
title: 'Axis position',
type: 'string',
default: 'left'
},
axisTicksFormatter: {
title: 'Ticks formatter function, f(value)',
type: 'string',
default: ''
}
},
required: ['showLines', 'fillLines', 'showPoints']
},
form: [
'hideDataByDefault',
'disableDataHiding',
'removeFromLegend',
'excludeFromStacking',
'showLines',
'fillLines',
'showPoints',
{
key: 'showPointShape',
type: 'rc-select',
multiple: false,
items: [
{
value: 'circle',
label: 'Circle'
},
{
value: 'cross',
label: 'Cross'
},
{
value: 'diamond',
label: 'Diamond'
},
{
value: 'square',
label: 'Square'
},
{
value: 'triangle',
label: 'Triangle'
},
{
value: 'custom',
label: 'Custom function'
}
]
},
{
key: 'pointShapeFormatter',
type: 'javascript',
helpId: 'widget/lib/flot/point_shape_format_fn'
},
'showPointsLineWidth',
'showPointsRadius',
{
key: 'tooltipValueFormatter',
type: 'javascript',
helpId: 'widget/lib/flot/tooltip_value_format_fn'
},
'showSeparateAxis',
'axisMin',
'axisMax',
'axisTitle',
'axisTickDecimals',
'axisTickSize',
{
key: 'axisPosition',
type: 'rc-select',
multiple: false,
items: [
{
value: 'left',
label: 'Left'
},
{
value: 'right',
label: 'Right'
}
]
},
{
key: 'axisTicksFormatter',
type: 'javascript',
helpId: 'widget/lib/flot/ticks_formatter_fn'
}
]
};
const properties = schema.schema.properties;
if (chartType === 'graph' || chartType === 'bar') {
properties.thresholds = {
title: 'Thresholds',
type: 'array',
items: {
title: 'Threshold',
type: 'object',
properties: {
thresholdValueSource: {
title: 'Threshold value source',
type: 'string',
default: 'predefinedValue'
},
thresholdEntityAlias: {
title: 'Thresholds source entity alias',
type: 'string'
},
thresholdAttribute: {
title: 'Threshold source entity attribute',
type: 'string'
},
thresholdValue: {
title: 'Threshold value (if predefined value is selected)',
type: 'number'
},
lineWidth: {
title: 'Line width',
type: 'number'
},
color: {
title: 'Color',
type: 'string'
}
}
},
required: []
};
schema.form.push({
key: 'thresholds',
items: [
{
key: 'thresholds[].thresholdValueSource',
type: 'rc-select',
multiple: false,
items: [
{
value: 'predefinedValue',
label: 'Predefined value (Default)'
},
{
value: 'entityAttribute',
label: 'Value taken from entity attribute'
}
]
},
'thresholds[].thresholdValue',
'thresholds[].thresholdEntityAlias',
'thresholds[].thresholdAttribute',
{
key: 'thresholds[].color',
type: 'color'
},
'thresholds[].lineWidth'
]
});
properties.comparisonSettings = {
title: 'Comparison Settings',
type: 'object',
properties: {
showValuesForComparison: {
title: 'Show historical values for comparison',
type: 'boolean',
default: true
},
comparisonValuesLabel: {
title: 'Historical values label',
type: 'string',
default: ''
},
color: {
title: 'Color',
type: 'string',
default: ''
}
},
required: ['showValuesForComparison']
};
schema.form.push({
key: 'comparisonSettings',
items: [
'comparisonSettings.showValuesForComparison',
'comparisonSettings.comparisonValuesLabel',
{
key: 'comparisonSettings.color',
type: 'color'
}
]
});
}
return schema;
}
export const flotLatestDatakeySettingsSchema: JsonSettingsSchema = {
schema: {
type: 'object',
title: 'LatestDataKeySettings',
properties: {
useAsThreshold: {
title: 'Use key value as threshold',
type: 'boolean',
default: false
},
thresholdLineWidth: {
title: 'Threshold line width',
type: 'number'
},
thresholdColor: {
title: 'Threshold color',
type: 'string'
}
}
},
form: [
'useAsThreshold',
{
key: 'thresholdLineWidth',
condition: 'model.useAsThreshold === true'
},
{
key: 'thresholdColor',
type: 'color',
condition: 'model.useAsThreshold === true'
},
]
};

15
ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts

@ -38,10 +38,8 @@ import {
} from '@app/shared/models/widget.models';
import {
ChartType,
flotDatakeySettingsSchema, flotLatestDatakeySettingsSchema,
flotPieDatakeySettingsSchema,
flotPieSettingsSchema,
flotSettingsSchema,
TbFlotAxisOptions,
TbFlotHoverInfo,
TbFlotKeySettings, TbFlotLatestKeySettings,
@ -69,7 +67,6 @@ const moment = moment_;
const flotPieSettingsSchemaValue = flotPieSettingsSchema;
const flotPieDatakeySettingsSchemaValue = flotPieDatakeySettingsSchema;
const latestDatakeySettingsSchemaValue = flotLatestDatakeySettingsSchema;
export class TbFlot {
@ -141,18 +138,6 @@ export class TbFlot {
return flotPieDatakeySettingsSchemaValue;
}
static settingsSchema(chartType: ChartType): JsonSettingsSchema {
return flotSettingsSchema(chartType);
}
static datakeySettingsSchema(defaultShowLines: boolean, chartType: ChartType): JsonSettingsSchema {
return flotDatakeySettingsSchema(defaultShowLines, chartType);
}
static latestDatakeySettingsSchema(): JsonSettingsSchema {
return latestDatakeySettingsSchemaValue;
}
constructor(private ctx: WidgetContext, private readonly chartType: ChartType) {
this.chartType = this.chartType || 'line';
this.settings = ctx.settings as TbFlotSettings;

24
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-bar-key-settings.component.html

@ -0,0 +1,24 @@
<!--
Copyright © 2016-2022 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<section [formGroup]="flotBarKeySettingsForm" fxLayout="column">
<tb-flot-key-settings formControlName="flotKeySettings"
[aliasController]="aliasController"
[chartType]="'bar'">
</tb-flot-key-settings>
</section>

55
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-bar-key-settings.component.ts

@ -0,0 +1,55 @@
///
/// Copyright © 2016-2022 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component } from '@angular/core';
import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { flotDataKeyDefaultSettings } from '@home/components/widget/lib/settings/chart/flot-key-settings.component';
@Component({
selector: 'tb-flot-bar-key-settings',
templateUrl: './flot-bar-key-settings.component.html',
styleUrls: []
})
export class FlotBarKeySettingsComponent extends WidgetSettingsComponent {
flotBarKeySettingsForm: FormGroup;
constructor(protected store: Store<AppState>,
private fb: FormBuilder) {
super(store);
}
protected settingsForm(): FormGroup {
return this.flotBarKeySettingsForm;
}
protected defaultSettings(): WidgetSettings {
return flotDataKeyDefaultSettings('bar');
}
protected onSettingsSet(settings: WidgetSettings) {
this.flotBarKeySettingsForm = this.fb.group({
flotKeySettings: [settings, []]
});
}
protected prepareOutputSettings(settings: any): WidgetSettings {
return settings.flotKeySettings;
}
}

238
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html

@ -0,0 +1,238 @@
<!--
Copyright © 2016-2022 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<section class="tb-widget-settings" [formGroup]="flotKeySettingsFormGroup" fxLayout="column">
<fieldset class="fields-group" fxLayout="column">
<legend class="group-title" translate>widgets.chart.common-settings</legend>
<mat-checkbox formControlName="hideDataByDefault" style="margin-bottom: 16px;">
{{ 'widgets.chart.data-is-hidden-by-default' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="disableDataHiding" style="margin-bottom: 16px;">
{{ 'widgets.chart.disable-data-hiding' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="removeFromLegend" style="margin-bottom: 16px;">
{{ 'widgets.chart.remove-from-legend' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="excludeFromStacking" style="margin-bottom: 16px;">
{{ 'widgets.chart.exclude-from-stacking' | translate }}
</mat-checkbox>
</fieldset>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.chart.line-settings</legend>
<mat-expansion-panel class="tb-settings" [expanded]="flotKeySettingsFormGroup.get('showLines').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="showLines" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.chart.show-line' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<section fxFlex fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.line-width</mat-label>
<input matInput type="number" min="0" formControlName="lineWidth">
</mat-form-field>
<mat-checkbox fxFlex formControlName="fillLines" style="margin-bottom: 16px;">
{{ 'widgets.chart.fill-line' | translate }}
</mat-checkbox>
</section>
</ng-template>
</mat-expansion-panel>
</fieldset>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.chart.points-settings</legend>
<mat-expansion-panel class="tb-settings" [expanded]="flotKeySettingsFormGroup.get('showPoints').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="showPoints" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.chart.show-points' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<section fxLayout="column">
<section fxFlex fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.points-line-width</mat-label>
<input matInput type="number" min="0" formControlName="showPointsLineWidth">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.points-radius</mat-label>
<input matInput type="number" min="0" formControlName="showPointsRadius">
</mat-form-field>
</section>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.point-shape</mat-label>
<mat-select formControlName="showPointShape">
<mat-option [value]="'circle'">
{{ 'widgets.chart.point-shape-circle' | translate }}
</mat-option>
<mat-option [value]="'cross'">
{{ 'widgets.chart.point-shape-cross' | translate }}
</mat-option>
<mat-option [value]="'diamond'">
{{ 'widgets.chart.point-shape-diamond' | translate }}
</mat-option>
<mat-option [value]="'square'">
{{ 'widgets.chart.point-shape-square' | translate }}
</mat-option>
<mat-option [value]="'triangle'">
{{ 'widgets.chart.point-shape-triangle' | translate }}
</mat-option>
<mat-option [value]="'custom'">
{{ 'widgets.chart.point-shape-custom' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-js-func [fxShow]="flotKeySettingsFormGroup.get('showPointShape').value === 'custom'"
formControlName="pointShapeFormatter"
[globalVariables]="functionScopeVariables"
[functionArgs]="['ctx', 'x', 'y', 'radius', 'shadow']"
functionTitle="{{ 'widgets.chart.point-shape-draw-function' | translate }}"
helpId="widget/lib/flot/point_shape_format_fn">
</tb-js-func>
</section>
</ng-template>
</mat-expansion-panel>
</fieldset>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.chart.tooltip-settings</legend>
<tb-js-func
formControlName="tooltipValueFormatter"
[globalVariables]="functionScopeVariables"
[functionArgs]="['value']"
functionTitle="{{ 'widgets.chart.tooltip-value-format-function' | translate }}"
helpId="widget/lib/flot/tooltip_value_format_fn">
</tb-js-func>
</fieldset>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.chart.yaxis-settings</legend>
<mat-slide-toggle formControlName="showSeparateAxis" class="slide-block">
{{ 'widgets.chart.show-separate-axis' | translate }}
</mat-slide-toggle>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.axis-title</mat-label>
<input matInput formControlName="axisTitle">
</mat-form-field>
<section fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.min-scale-value</mat-label>
<input matInput type="number" formControlName="axisMin">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.max-scale-value</mat-label>
<input matInput type="number" formControlName="axisMax">
</mat-form-field>
</section>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.axis-position</mat-label>
<mat-select formControlName="axisPosition">
<mat-option [value]="'left'">
{{ 'widgets.chart.axis-position-left' | translate }}
</mat-option>
<mat-option [value]="'right'">
{{ 'widgets.chart.axis-position-right' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.chart.yaxis-tick-labels-settings</legend>
<section fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.tick-step-size</mat-label>
<input matInput type="number" formControlName="axisTickSize">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.number-of-decimals</mat-label>
<input matInput type="number" min="0" formControlName="axisTickDecimals">
</mat-form-field>
</section>
<tb-js-func
formControlName="axisTicksFormatter"
[globalVariables]="functionScopeVariables"
[functionArgs]="['value']"
functionTitle="{{ 'widgets.chart.ticks-formatter-function' | translate }}"
helpId="widget/lib/flot/ticks_formatter_fn">
</tb-js-func>
</fieldset>
</fieldset>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.chart.thresholds</legend>
<div fxLayout="column">
<div class="tb-control-list tb-drop-list" cdkDropList cdkDropListOrientation="vertical"
(cdkDropListDropped)="thresholdDrop($event)">
<div cdkDrag class="tb-draggable" *ngFor="let thresholdControl of thresholdsFormArray().controls; trackBy: trackByThreshold;
let $index = index; last as isLast;"
fxLayout="column" [ngStyle]="!isLast ? {paddingBottom: '8px'} : {}">
<tb-flot-threshold [formControl]="thresholdControl"
[expanded]="thresholdControl.new"
[aliasController]="aliasController"
(removeThreshold)="removeThreshold($index)">
</tb-flot-threshold>
</div>
</div>
<div *ngIf="!thresholdsFormArray().controls.length">
<span translate fxLayoutAlign="center center"
class="tb-prompt">widgets.chart.no-thresholds</span>
</div>
<div style="padding-top: 16px;">
<button mat-raised-button color="primary"
type="button"
(click)="addThreshold()">
<span translate>widgets.chart.add-threshold</span>
</button>
</div>
</div>
</fieldset>
<fieldset class="fields-group fields-group-slider" formGroupName="comparisonSettings" >
<legend class="group-title" translate>widgets.chart.comparison-settings</legend>
<mat-expansion-panel class="tb-settings" [expanded]="flotKeySettingsFormGroup.get('comparisonSettings.showValuesForComparison').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="showValuesForComparison" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.chart.show-values-for-comparison' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<section fxFlex fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.comparison-values-label</mat-label>
<input matInput formControlName="comparisonValuesLabel">
</mat-form-field>
<tb-color-input fxFlex
formControlName="color"
label="{{ 'widgets.chart.color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
</section>
</ng-template>
</mat-expansion-panel>
</fieldset>
</section>

333
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts

@ -0,0 +1,333 @@
///
/// Copyright © 2016-2022 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component, forwardRef, Input, OnInit } from '@angular/core';
import {
AbstractControl,
ControlValueAccessor,
FormArray,
FormBuilder,
FormControl,
FormGroup,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
Validator,
Validators
} from '@angular/forms';
import { PageComponent } from '@shared/components/page.component';
import { ChartType, TbFlotKeySettings, TbFlotKeyThreshold } from '@home/components/widget/lib/flot-widget.models';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { TranslateService } from '@ngx-translate/core';
import { WidgetService } from '@core/http/widget.service';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { IAliasController } from 'src/app/core/api/widget-api.models';
export function flotDataKeyDefaultSettings(chartType: ChartType): TbFlotKeySettings {
const settings: TbFlotKeySettings = {
// Common settings
hideDataByDefault: false,
disableDataHiding: false,
removeFromLegend: false,
excludeFromStacking: false,
// Line settings
showLines: chartType === 'graph',
lineWidth: 1,
fillLines: false,
// Points settings
showPoints: false,
showPointsLineWidth: 5,
showPointsRadius: 3,
showPointShape: 'circle',
pointShapeFormatter: 'var size = radius * Math.sqrt(Math.PI) / 2;\n' +
'ctx.moveTo(x - size, y - size);\n' +
'ctx.lineTo(x + size, y + size);\n' +
'ctx.moveTo(x - size, y + size);\n' +
'ctx.lineTo(x + size, y - size);',
// Tooltip settings
tooltipValueFormatter: '',
// Y axis settings
showSeparateAxis: false,
axisTitle: '',
axisMin: null,
axisMax: null,
axisPosition: 'left',
// --> Y axis tick labels settings
axisTickSize: null,
axisTickDecimals: null,
axisTicksFormatter: '',
// Thresholds
thresholds: [],
// Comparison settings
comparisonSettings: {
showValuesForComparison: true,
comparisonValuesLabel: '',
color: ''
}
};
return settings;
}
@Component({
selector: 'tb-flot-key-settings',
templateUrl: './flot-key-settings.component.html',
styleUrls: ['./../widget-settings.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FlotKeySettingsComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => FlotKeySettingsComponent),
multi: true,
}
]
})
export class FlotKeySettingsComponent extends PageComponent implements OnInit, ControlValueAccessor, Validator {
@Input()
disabled: boolean;
@Input()
chartType: ChartType;
@Input()
aliasController: IAliasController;
functionScopeVariables = this.widgetService.getWidgetScopeVariables();
private modelValue: TbFlotKeySettings;
private propagateChange = null;
public flotKeySettingsFormGroup: FormGroup;
constructor(protected store: Store<AppState>,
private translate: TranslateService,
private widgetService: WidgetService,
private fb: FormBuilder) {
super(store);
}
ngOnInit(): void {
this.flotKeySettingsFormGroup = this.fb.group({
// Common settings
hideDataByDefault: [false, []],
disableDataHiding: [false, []],
removeFromLegend: [false, []],
excludeFromStacking: [false, []],
// Line settings
showLines: [this.chartType === 'graph', []],
lineWidth: [1, [Validators.min(0)]],
fillLines: [false, []],
// Points settings
showPoints: [false, []],
showPointsLineWidth: [5, [Validators.min(0)]],
showPointsRadius: [3, [Validators.min(0)]],
showPointShape: ['circle', []],
pointShapeFormatter: ['', []],
// Tooltip settings
tooltipValueFormatter: ['', []],
// Y axis settings
showSeparateAxis: [false, []],
axisTitle: [null, []],
axisMin: [null, []],
axisMax: [null, []],
axisPosition: ['left', []],
// --> Y axis tick labels settings
axisTickSize: [null, [Validators.min(0)]],
axisTickDecimals: [null, [Validators.min(0)]],
axisTicksFormatter: ['', []],
// Thresholds
thresholds: this.fb.array([]),
// Comparison settings
comparisonSettings: this.fb.group({
showValuesForComparison: [true, []],
comparisonValuesLabel: ['', []],
color: ['', []]
})
});
this.flotKeySettingsFormGroup.get('showLines').valueChanges.subscribe(() => {
this.updateValidators(true);
});
this.flotKeySettingsFormGroup.get('showPoints').valueChanges.subscribe(() => {
this.updateValidators(true);
});
this.flotKeySettingsFormGroup.get('comparisonSettings.showValuesForComparison').valueChanges.subscribe(() => {
this.updateValidators(true);
});
this.flotKeySettingsFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
this.updateValidators(false);
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (isDisabled) {
this.flotKeySettingsFormGroup.disable({emitEvent: false});
} else {
this.flotKeySettingsFormGroup.enable({emitEvent: false});
}
}
writeValue(value: TbFlotKeySettings): void {
const thresholds = value?.thresholds;
this.modelValue = value;
this.flotKeySettingsFormGroup.patchValue(
value, {emitEvent: false}
);
const thresholdsControls: Array<AbstractControl> = [];
if (thresholds && thresholds.length) {
thresholds.forEach((threshold) => {
thresholdsControls.push(this.fb.control(threshold, []));
});
}
this.flotKeySettingsFormGroup.setControl('thresholds', this.fb.array(thresholdsControls), {emitEvent: false});
this.updateValidators(false);
}
validate(c: FormControl) {
return (this.flotKeySettingsFormGroup.valid) ? null : {
flotKeySettings: {
valid: false,
},
};
}
private updateModel() {
const value: TbFlotKeySettings = this.flotKeySettingsFormGroup.value;
this.modelValue = value;
this.propagateChange(this.modelValue);
}
private updateValidators(emitEvent?: boolean): void {
const showLines: boolean = this.flotKeySettingsFormGroup.get('showLines').value;
const showPoints: boolean = this.flotKeySettingsFormGroup.get('showPoints').value;
const showValuesForComparison: boolean = this.flotKeySettingsFormGroup.get('comparisonSettings.showValuesForComparison').value;
if (showLines) {
this.flotKeySettingsFormGroup.get('lineWidth').enable({emitEvent});
this.flotKeySettingsFormGroup.get('fillLines').enable({emitEvent});
} else {
this.flotKeySettingsFormGroup.get('lineWidth').disable({emitEvent});
this.flotKeySettingsFormGroup.get('fillLines').disable({emitEvent});
}
if (showPoints) {
this.flotKeySettingsFormGroup.get('showPointsLineWidth').enable({emitEvent});
this.flotKeySettingsFormGroup.get('showPointsRadius').enable({emitEvent});
this.flotKeySettingsFormGroup.get('showPointShape').enable({emitEvent});
this.flotKeySettingsFormGroup.get('pointShapeFormatter').enable({emitEvent});
} else {
this.flotKeySettingsFormGroup.get('showPointsLineWidth').disable({emitEvent});
this.flotKeySettingsFormGroup.get('showPointsRadius').disable({emitEvent});
this.flotKeySettingsFormGroup.get('showPointShape').disable({emitEvent});
this.flotKeySettingsFormGroup.get('pointShapeFormatter').disable({emitEvent});
}
if (showValuesForComparison) {
this.flotKeySettingsFormGroup.get('comparisonSettings.comparisonValuesLabel').enable({emitEvent});
this.flotKeySettingsFormGroup.get('comparisonSettings.color').enable({emitEvent});
} else {
this.flotKeySettingsFormGroup.get('comparisonSettings.comparisonValuesLabel').disable({emitEvent});
this.flotKeySettingsFormGroup.get('comparisonSettings.color').disable({emitEvent});
}
this.flotKeySettingsFormGroup.get('lineWidth').updateValueAndValidity({emitEvent: false});
this.flotKeySettingsFormGroup.get('fillLines').updateValueAndValidity({emitEvent: false});
this.flotKeySettingsFormGroup.get('showPointsLineWidth').updateValueAndValidity({emitEvent: false});
this.flotKeySettingsFormGroup.get('showPointsRadius').updateValueAndValidity({emitEvent: false});
this.flotKeySettingsFormGroup.get('showPointShape').updateValueAndValidity({emitEvent: false});
this.flotKeySettingsFormGroup.get('pointShapeFormatter').updateValueAndValidity({emitEvent: false});
this.flotKeySettingsFormGroup.get('comparisonSettings.comparisonValuesLabel').updateValueAndValidity({emitEvent: false});
this.flotKeySettingsFormGroup.get('comparisonSettings.color').updateValueAndValidity({emitEvent: false});
}
thresholdsFormArray(): FormArray {
return this.flotKeySettingsFormGroup.get('thresholds') as FormArray;
}
public trackByThreshold(index: number, thresholdControl: AbstractControl): any {
return thresholdControl;
}
public removeThreshold(index: number) {
(this.flotKeySettingsFormGroup.get('thresholds') as FormArray).removeAt(index);
}
public addThreshold() {
const threshold: TbFlotKeyThreshold = {
thresholdValueSource: 'predefinedValue',
thresholdEntityAlias: null,
thresholdAttribute: null,
thresholdValue: null,
lineWidth: null,
color: null
};
const thresholdsArray = this.flotKeySettingsFormGroup.get('thresholds') as FormArray;
const thresholdControl = this.fb.control(threshold, []);
(thresholdControl as any).new = true;
thresholdsArray.push(thresholdControl);
this.flotKeySettingsFormGroup.updateValueAndValidity();
}
thresholdDrop(event: CdkDragDrop<string[]>) {
const thresholdsArray = this.flotKeySettingsFormGroup.get('thresholds') as FormArray;
const threshold = thresholdsArray.at(event.previousIndex);
thresholdsArray.removeAt(event.previousIndex);
thresholdsArray.insert(event.currentIndex, threshold);
}
}

47
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html

@ -0,0 +1,47 @@
<!--
Copyright © 2016-2022 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<section class="tb-widget-settings" [formGroup]="flotLatestKeySettingsForm" fxLayout="column">
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.chart.threshold-settings</legend>
<mat-expansion-panel class="tb-settings" [expanded]="flotLatestKeySettingsForm.get('useAsThreshold').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="useAsThreshold" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.chart.use-as-threshold' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<section fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.threshold-line-width</mat-label>
<input type="number" min="0" matInput formControlName="thresholdLineWidth">
</mat-form-field>
<tb-color-input fxFlex
formControlName="thresholdColor"
label="{{ 'widgets.chart.threshold-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
</section>
</ng-template>
</mat-expansion-panel>
</fieldset>
</section>

74
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.ts

@ -0,0 +1,74 @@
///
/// Copyright © 2016-2022 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component } from '@angular/core';
import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@Component({
selector: 'tb-flot-latest-key-settings',
templateUrl: './flot-latest-key-settings.component.html',
styleUrls: ['./../widget-settings.scss']
})
export class FlotLatestKeySettingsComponent extends WidgetSettingsComponent {
flotLatestKeySettingsForm: FormGroup;
constructor(protected store: Store<AppState>,
private fb: FormBuilder) {
super(store);
}
protected settingsForm(): FormGroup {
return this.flotLatestKeySettingsForm;
}
protected defaultSettings(): WidgetSettings {
return {
useAsThreshold: false,
thresholdLineWidth: null,
thresholdColor: null
};
}
protected onSettingsSet(settings: WidgetSettings) {
this.flotLatestKeySettingsForm = this.fb.group({
useAsThreshold: [settings.useAsThreshold, []],
thresholdLineWidth: [settings.thresholdLineWidth, [Validators.min(0)]],
thresholdColor: [settings.thresholdColor, []]
});
}
protected validatorTriggers(): string[] {
return ['useAsThreshold'];
}
protected updateValidators(emitEvent: boolean) {
const useAsThreshold: boolean = this.flotLatestKeySettingsForm.get('useAsThreshold').value;
if (useAsThreshold) {
this.flotLatestKeySettingsForm.get('thresholdLineWidth').enable();
this.flotLatestKeySettingsForm.get('thresholdColor').enable();
} else {
this.flotLatestKeySettingsForm.get('thresholdLineWidth').disable();
this.flotLatestKeySettingsForm.get('thresholdColor').disable();
}
this.flotLatestKeySettingsForm.get('thresholdLineWidth').updateValueAndValidity({emitEvent});
this.flotLatestKeySettingsForm.get('thresholdColor').updateValueAndValidity({emitEvent});
}
}

24
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-line-key-settings.component.html

@ -0,0 +1,24 @@
<!--
Copyright © 2016-2022 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<section [formGroup]="flotLineKeySettingsForm" fxLayout="column">
<tb-flot-key-settings formControlName="flotKeySettings"
[aliasController]="aliasController"
[chartType]="'graph'">
</tb-flot-key-settings>
</section>

55
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-line-key-settings.component.ts

@ -0,0 +1,55 @@
///
/// Copyright © 2016-2022 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component } from '@angular/core';
import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { flotDataKeyDefaultSettings } from '@home/components/widget/lib/settings/chart/flot-key-settings.component';
@Component({
selector: 'tb-flot-line-key-settings',
templateUrl: './flot-line-key-settings.component.html',
styleUrls: []
})
export class FlotLineKeySettingsComponent extends WidgetSettingsComponent {
flotLineKeySettingsForm: FormGroup;
constructor(protected store: Store<AppState>,
private fb: FormBuilder) {
super(store);
}
protected settingsForm(): FormGroup {
return this.flotLineKeySettingsForm;
}
protected defaultSettings(): WidgetSettings {
return flotDataKeyDefaultSettings('graph');
}
protected onSettingsSet(settings: WidgetSettings) {
this.flotLineKeySettingsForm = this.fb.group({
flotKeySettings: [settings, []]
});
}
protected prepareOutputSettings(settings: any): WidgetSettings {
return settings.flotKeySettings;
}
}

57
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html

@ -0,0 +1,57 @@
<!--
Copyright © 2016-2022 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<mat-expansion-panel class="flot-threshold" fxFlex [formGroup]="thresholdFormGroup" [(expanded)]="expanded">
<mat-expansion-panel-header>
<div fxFlex fxLayout="row" fxLayoutAlign="start center">
<mat-panel-title>
<div fxLayout="row" fxFlex fxLayoutAlign="start center">
<div>{{ thresholdText() }}</div>
<div class="tb-color-preview" style="margin-left: 6px;">
<div class="tb-color-result" [ngStyle]="{background: thresholdFormGroup.get('color').value}"></div>
</div>
</div>
</mat-panel-title>
<span fxFlex></span>
<button *ngIf="!disabled" mat-icon-button style="min-width: 40px;"
type="button"
(click)="removeThreshold.emit()"
matTooltip="{{ 'action.remove' | translate }}"
matTooltipPosition="above">
<mat-icon>delete</mat-icon>
</button>
</div>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div fxLayout="column" fxLayoutGap="0.5em">
<mat-divider></mat-divider>
<section class="tb-widget-settings" fxLayout="column">
<tb-value-source [aliasController]="aliasController" formControlName="valueSource"></tb-value-source>
<section fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.line-width</mat-label>
<input type="number" min="0" matInput formControlName="lineWidth">
</mat-form-field>
<tb-color-input fxFlex
formControlName="color"
label="{{ 'widgets.chart.color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
</section>
</section>
</div>
</ng-template>
</mat-expansion-panel>

40
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss

@ -0,0 +1,40 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
display: block;
.mat-expansion-panel {
box-shadow: none;
&.flot-threshold {
border: 1px groove rgba(0, 0, 0, .25);
.mat-expansion-panel-header {
padding: 0 24px 0 8px;
&.mat-expanded {
height: 48px;
}
}
}
}
}
:host ::ng-deep {
.mat-expansion-panel {
&.flot-threshold {
.mat-expansion-panel-body {
padding: 0 8px 8px;
}
}
}
}

136
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts

@ -0,0 +1,136 @@
///
/// Copyright © 2016-2022 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { ValueSourceProperty } from '@home/components/widget/lib/settings/common/value-source.component';
import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { TranslateService } from '@ngx-translate/core';
import { isNumber } from '@core/utils';
import { IAliasController } from '@core/api/widget-api.models';
import { TbFlotKeyThreshold } from '@home/components/widget/lib/flot-widget.models';
@Component({
selector: 'tb-flot-threshold',
templateUrl: './flot-threshold.component.html',
styleUrls: ['./flot-threshold.component.scss', './../widget-settings.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FlotThresholdComponent),
multi: true
}
]
})
export class FlotThresholdComponent extends PageComponent implements OnInit, ControlValueAccessor {
@Input()
disabled: boolean;
@Input()
expanded = false;
@Input()
aliasController: IAliasController;
@Output()
removeThreshold = new EventEmitter();
private modelValue: TbFlotKeyThreshold;
private propagateChange = null;
public thresholdFormGroup: FormGroup;
constructor(protected store: Store<AppState>,
private translate: TranslateService,
private fb: FormBuilder) {
super(store);
}
ngOnInit(): void {
this.thresholdFormGroup = this.fb.group({
valueSource: [null, []],
lineWidth: [null, [Validators.min(0)]],
color: [null, []]
});
this.thresholdFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (isDisabled) {
this.thresholdFormGroup.disable({emitEvent: false});
} else {
this.thresholdFormGroup.enable({emitEvent: false});
}
}
writeValue(value: TbFlotKeyThreshold): void {
this.modelValue = value;
const valueSource: ValueSourceProperty = {
valueSource: value?.thresholdValueSource,
entityAlias: value?.thresholdEntityAlias,
attribute: value?.thresholdAttribute,
value: value?.thresholdValue
};
this.thresholdFormGroup.patchValue(
{valueSource, lineWidth: value?.lineWidth, color: value?.color}, {emitEvent: false}
);
}
thresholdText(): string {
const value: ValueSourceProperty = this.thresholdFormGroup.get('valueSource').value;
return this.valueSourcePropertyText(value);
}
private valueSourcePropertyText(source?: ValueSourceProperty): string {
if (source) {
if (source.valueSource === 'predefinedValue') {
return `${isNumber(source.value) ? source.value : 0}`;
} else if (source.valueSource === 'entityAttribute') {
const alias = source.entityAlias || 'Undefined';
const key = source.attribute || 'Undefined';
return `${alias}.${key}`;
}
}
return 'Undefined';
}
private updateModel() {
const value: {valueSource: ValueSourceProperty, lineWidth: number, color: string} = this.thresholdFormGroup.value;
this.modelValue = {
thresholdValueSource: value?.valueSource?.valueSource,
thresholdEntityAlias: value?.valueSource?.entityAlias,
thresholdAttribute: value?.valueSource?.attribute,
thresholdValue: value?.valueSource?.value,
lineWidth: value?.lineWidth,
color: value?.color
};
this.propagateChange(this.modelValue);
}
}

1
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts

@ -34,7 +34,6 @@ import { AppState } from '@core/core.state';
import { TranslateService } from '@ngx-translate/core';
import { ComparisonDuration } from '@shared/models/time/time.models';
import { WidgetService } from '@core/http/widget.service';
import { fixedColorLevelValidator } from '@home/components/widget/lib/settings/gauge/fixed-color-level.component';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import {
LabelDataKey,

30
ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts

@ -83,6 +83,17 @@ import { LabelDataKeyComponent } from '@home/components/widget/lib/settings/char
import {
FlotBarWidgetSettingsComponent
} from '@home/components/widget/lib/settings/chart/flot-bar-widget-settings.component';
import { FlotThresholdComponent } from '@home/components/widget/lib/settings/chart/flot-threshold.component';
import { FlotKeySettingsComponent } from '@home/components/widget/lib/settings/chart/flot-key-settings.component';
import {
FlotLineKeySettingsComponent
} from '@home/components/widget/lib/settings/chart/flot-line-key-settings.component';
import {
FlotBarKeySettingsComponent
} from '@home/components/widget/lib/settings/chart/flot-bar-key-settings.component';
import {
FlotLatestKeySettingsComponent
} from '@home/components/widget/lib/settings/chart/flot-latest-key-settings.component';
@NgModule({
declarations: [
@ -113,7 +124,12 @@ import {
FlotWidgetSettingsComponent,
LabelDataKeyComponent,
FlotLineWidgetSettingsComponent,
FlotBarWidgetSettingsComponent
FlotBarWidgetSettingsComponent,
FlotThresholdComponent,
FlotKeySettingsComponent,
FlotLineKeySettingsComponent,
FlotBarKeySettingsComponent,
FlotLatestKeySettingsComponent
],
imports: [
CommonModule,
@ -148,7 +164,12 @@ import {
FlotWidgetSettingsComponent,
LabelDataKeyComponent,
FlotLineWidgetSettingsComponent,
FlotBarWidgetSettingsComponent
FlotBarWidgetSettingsComponent,
FlotThresholdComponent,
FlotKeySettingsComponent,
FlotLineKeySettingsComponent,
FlotBarKeySettingsComponent,
FlotLatestKeySettingsComponent
]
})
export class WidgetSettingsModule {
@ -174,5 +195,8 @@ export const widgetSettingsComponentsMap: {[key: string]: Type<IWidgetSettingsCo
'tb-analogue-compass-widget-settings': AnalogueCompassWidgetSettingsComponent,
'tb-digital-gauge-widget-settings': DigitalGaugeWidgetSettingsComponent,
'tb-flot-line-widget-settings': FlotLineWidgetSettingsComponent,
'tb-flot-bar-widget-settings': FlotBarWidgetSettingsComponent
'tb-flot-bar-widget-settings': FlotBarWidgetSettingsComponent,
'tb-flot-line-key-settings': FlotLineKeySettingsComponent,
'tb-flot-bar-key-settings': FlotBarKeySettingsComponent,
'tb-flot-latest-key-settings': FlotLatestKeySettingsComponent
};

35
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -3242,7 +3242,40 @@
"key-type-timeseries": "Timeseries",
"label-keys-list": "Keys list to use in labels",
"no-label-keys": "No keys configured",
"add-label-key": "Add new key"
"add-label-key": "Add new key",
"line-width": "Line width",
"color": "Color",
"data-is-hidden-by-default": "Data is hidden by default",
"disable-data-hiding": "Disable data hiding",
"remove-from-legend": "Remove datakey from legend",
"exclude-from-stacking": "Exclude from stacking(available in \"Stacking\" mode)",
"line-settings": "Line settings",
"show-line": "Show line",
"fill-line": "Fill line",
"points-settings": "Points settings",
"show-points": "Show points",
"points-line-width": "Line width of points",
"points-radius": "Radius of points",
"point-shape": "Point shape",
"point-shape-circle": "Circle",
"point-shape-cross": "Cross",
"point-shape-diamond": "Diamond",
"point-shape-square": "Square",
"point-shape-triangle": "Triangle",
"point-shape-custom": "Custom function",
"point-shape-draw-function": "Point shape draw function",
"show-separate-axis": "Show separate axis",
"axis-position-left": "Left",
"axis-position-right": "Right",
"thresholds": "Thresholds",
"no-thresholds": "No thresholds configured",
"add-threshold": "Add new threshold",
"show-values-for-comparison": "Show historical values for comparison",
"comparison-values-label": "Historical values label",
"threshold-settings": "Threshold settings",
"use-as-threshold": "Use key value as threshold",
"threshold-line-width": "Threshold line width",
"threshold-color": "Threshold color"
},
"dashboard-state": {
"dashboard-state-settings": "Dashboard state settings",

Loading…
Cancel
Save