Commit 77477f69ee1e98e8461454aa5cc47902692cedee
1 parent
4bea89a6
Flot: add ability to use attributes in datakeys labels
Showing
2 changed files
with
169 additions
and
6 deletions
@@ -19,6 +19,7 @@ | @@ -19,6 +19,7 @@ | ||
19 | 19 | ||
20 | import { DataKey, Datasource, DatasourceData, JsonSettingsSchema } from '@shared/models/widget.models'; | 20 | import { DataKey, Datasource, DatasourceData, JsonSettingsSchema } from '@shared/models/widget.models'; |
21 | import * as moment_ from 'moment'; | 21 | import * as moment_ from 'moment'; |
22 | +import { DataKeyType } from "@shared/models/telemetry/telemetry.models"; | ||
22 | 23 | ||
23 | export declare type ChartType = 'line' | 'pie' | 'bar' | 'state' | 'graph'; | 24 | export declare type ChartType = 'line' | 'pie' | 'bar' | 'state' | 'graph'; |
24 | 25 | ||
@@ -149,13 +150,24 @@ export interface TbFlotThresholdsSettings { | @@ -149,13 +150,24 @@ export interface TbFlotThresholdsSettings { | ||
149 | thresholdsLineWidth: number; | 150 | thresholdsLineWidth: number; |
150 | } | 151 | } |
151 | 152 | ||
152 | -export interface TbFlotGraphSettings extends TbFlotBaseSettings, TbFlotThresholdsSettings, TbFlotComparisonSettings { | 153 | +export interface TbFlotCustomLegendSettings { |
154 | + customLegendEnabled: boolean; | ||
155 | + dataKeysListForLabels: Array<TbFlotLabelPatternSettings>; | ||
156 | +} | ||
157 | + | ||
158 | +export interface TbFlotLabelPatternSettings { | ||
159 | + name: string; | ||
160 | + type: DataKeyType; | ||
161 | + settings?: object | ||
162 | +} | ||
163 | + | ||
164 | +export interface TbFlotGraphSettings extends TbFlotBaseSettings, TbFlotThresholdsSettings, TbFlotComparisonSettings, TbFlotCustomLegendSettings { | ||
153 | smoothLines: boolean; | 165 | smoothLines: boolean; |
154 | } | 166 | } |
155 | 167 | ||
156 | export declare type BarAlignment = 'left' | 'right' | 'center'; | 168 | export declare type BarAlignment = 'left' | 'right' | 'center'; |
157 | 169 | ||
158 | -export interface TbFlotBarSettings extends TbFlotBaseSettings, TbFlotThresholdsSettings, TbFlotComparisonSettings { | 170 | +export interface TbFlotBarSettings extends TbFlotBaseSettings, TbFlotThresholdsSettings, TbFlotComparisonSettings, TbFlotCustomLegendSettings { |
159 | defaultBarWidth: number; | 171 | defaultBarWidth: number; |
160 | barAlignment: BarAlignment; | 172 | barAlignment: BarAlignment; |
161 | } | 173 | } |
@@ -503,13 +515,17 @@ export function flotSettingsSchema(chartType: ChartType): JsonSettingsSchema { | @@ -503,13 +515,17 @@ export function flotSettingsSchema(chartType: ChartType): JsonSettingsSchema { | ||
503 | GroupTitle: 'Common Settings' | 515 | GroupTitle: 'Common Settings' |
504 | }]; | 516 | }]; |
505 | schema.form = [schema.form]; | 517 | schema.form = [schema.form]; |
506 | - schema.schema.properties = {...schema.schema.properties, ...chartSettingsSchemaForComparison.schema.properties}; | ||
507 | - schema.schema.required = schema.schema.required.concat(chartSettingsSchemaForComparison.schema.required); | ||
508 | - schema.form.push(chartSettingsSchemaForComparison.form); | 518 | + schema.schema.properties = {...schema.schema.properties, ...chartSettingsSchemaForComparison.schema.properties, ...chartSettingsSchemaForCustomLegend.schema.properties}; |
519 | + schema.schema.required = schema.schema.required.concat(chartSettingsSchemaForComparison.schema.required, chartSettingsSchemaForCustomLegend.schema.required); | ||
520 | + schema.form.push(chartSettingsSchemaForComparison.form, chartSettingsSchemaForCustomLegend.form); | ||
509 | schema.groupInfoes.push({ | 521 | schema.groupInfoes.push({ |
510 | formIndex: schema.groupInfoes.length, | 522 | formIndex: schema.groupInfoes.length, |
511 | GroupTitle:'Comparison Settings' | 523 | GroupTitle:'Comparison Settings' |
512 | }); | 524 | }); |
525 | + schema.groupInfoes.push({ | ||
526 | + formIndex: schema.groupInfoes.length, | ||
527 | + GroupTitle:'Custom Legend Settings' | ||
528 | + }); | ||
513 | } | 529 | } |
514 | return schema; | 530 | return schema; |
515 | } | 531 | } |
@@ -603,6 +619,67 @@ const chartSettingsSchemaForComparison: JsonSettingsSchema = { | @@ -603,6 +619,67 @@ const chartSettingsSchemaForComparison: JsonSettingsSchema = { | ||
603 | ] | 619 | ] |
604 | }; | 620 | }; |
605 | 621 | ||
622 | +const chartSettingsSchemaForCustomLegend: JsonSettingsSchema = { | ||
623 | + schema: { | ||
624 | + title: 'Custom Legend Settings', | ||
625 | + type: 'object', | ||
626 | + properties: { | ||
627 | + customLegendEnabled: { | ||
628 | + title: 'Enable custom legend (this will allow you to use attribute/timeseries values in key labels)', | ||
629 | + type: 'boolean', | ||
630 | + default: false | ||
631 | + }, | ||
632 | + dataKeysListForLabels: { | ||
633 | + title: 'Datakeys list to use in labels', | ||
634 | + type: 'array', | ||
635 | + items: { | ||
636 | + type: 'object', | ||
637 | + properties: { | ||
638 | + name: { | ||
639 | + title: 'Key name', | ||
640 | + type: 'string' | ||
641 | + }, | ||
642 | + type: { | ||
643 | + title: 'Key type', | ||
644 | + type: 'string', | ||
645 | + default: 'attribute' | ||
646 | + } | ||
647 | + }, | ||
648 | + required: [ | ||
649 | + 'name' | ||
650 | + ] | ||
651 | + } | ||
652 | + } | ||
653 | + }, | ||
654 | + required: [] | ||
655 | + }, | ||
656 | + form: [ | ||
657 | + 'customLegendEnabled', | ||
658 | + { | ||
659 | + key: 'dataKeysListForLabels', | ||
660 | + condition: 'model.customLegendEnabled === true', | ||
661 | + items: [ | ||
662 | + { | ||
663 | + key: 'dataKeysListForLabels[].type', | ||
664 | + type: 'rc-select', | ||
665 | + multiple: false, | ||
666 | + items: [ | ||
667 | + { | ||
668 | + value: 'attribute', | ||
669 | + label: 'Attribute' | ||
670 | + }, | ||
671 | + { | ||
672 | + value: 'timeseries', | ||
673 | + label: 'Timeseries' | ||
674 | + } | ||
675 | + ] | ||
676 | + }, | ||
677 | + 'dataKeysListForLabels[].name' | ||
678 | + ] | ||
679 | + } | ||
680 | + ] | ||
681 | +}; | ||
682 | + | ||
606 | export const flotPieSettingsSchema: JsonSettingsSchema = { | 683 | export const flotPieSettingsSchema: JsonSettingsSchema = { |
607 | schema: { | 684 | schema: { |
608 | type: 'object', | 685 | type: 'object', |
@@ -16,7 +16,15 @@ | @@ -16,7 +16,15 @@ | ||
16 | 16 | ||
17 | 17 | ||
18 | import { WidgetContext } from '@home/models/widget-component.models'; | 18 | import { WidgetContext } from '@home/models/widget-component.models'; |
19 | -import { deepClone, isDefined, isEqual, isNumber, isUndefined } from '@app/core/utils'; | 19 | +import { |
20 | + createLabelFromDatasource, | ||
21 | + deepClone, | ||
22 | + insertVariable, | ||
23 | + isDefined, | ||
24 | + isEqual, | ||
25 | + isNumber, | ||
26 | + isUndefined | ||
27 | +} from '@app/core/utils'; | ||
20 | import { IWidgetSubscription, WidgetSubscriptionOptions } from '@core/api/widget-api.models'; | 28 | import { IWidgetSubscription, WidgetSubscriptionOptions } from '@core/api/widget-api.models'; |
21 | import { | 29 | import { |
22 | DataKey, | 30 | DataKey, |
@@ -88,6 +96,9 @@ export class TbFlot { | @@ -88,6 +96,9 @@ export class TbFlot { | ||
88 | private thresholdsSourcesSubscription: IWidgetSubscription; | 96 | private thresholdsSourcesSubscription: IWidgetSubscription; |
89 | private predefinedThresholds: TbFlotThresholdMarking[]; | 97 | private predefinedThresholds: TbFlotThresholdMarking[]; |
90 | 98 | ||
99 | + private labelPatternsSourcesSubscription: IWidgetSubscription; | ||
100 | + private labelPatternsSourcesData: DatasourceData[]; | ||
101 | + | ||
91 | private plotInited = false; | 102 | private plotInited = false; |
92 | private plot: JQueryPlot; | 103 | private plot: JQueryPlot; |
93 | 104 | ||
@@ -369,6 +380,20 @@ export class TbFlot { | @@ -369,6 +380,20 @@ export class TbFlot { | ||
369 | const yaxesMap: {[units: string]: TbFlotAxisOptions} = {}; | 380 | const yaxesMap: {[units: string]: TbFlotAxisOptions} = {}; |
370 | const predefinedThresholds: TbFlotThresholdMarking[] = []; | 381 | const predefinedThresholds: TbFlotThresholdMarking[] = []; |
371 | const thresholdsDatasources: Datasource[] = []; | 382 | const thresholdsDatasources: Datasource[] = []; |
383 | + if (this.settings.customLegendEnabled) { | ||
384 | + this.labelPatternsSourcesData = []; | ||
385 | + const labelPatternsDatasources: Datasource[] = []; | ||
386 | + subscription.datasources.forEach((item) => { | ||
387 | + let datasource: Datasource = { | ||
388 | + type: item.type, | ||
389 | + entityType: item.entityType, | ||
390 | + entityId: item.entityId, | ||
391 | + dataKeys: this.settings.dataKeysListForLabels | ||
392 | + }; | ||
393 | + labelPatternsDatasources.push(datasource); | ||
394 | + }); | ||
395 | + this.subscribeForLabelPatternsSources(labelPatternsDatasources); | ||
396 | + } | ||
372 | 397 | ||
373 | let tooltipValueFormatFunction: TooltipValueFormatFunction = null; | 398 | let tooltipValueFormatFunction: TooltipValueFormatFunction = null; |
374 | if (this.settings.tooltipValueFormatter && this.settings.tooltipValueFormatter.length) { | 399 | if (this.settings.tooltipValueFormatter && this.settings.tooltipValueFormatter.length) { |
@@ -506,6 +531,9 @@ export class TbFlot { | @@ -506,6 +531,9 @@ export class TbFlot { | ||
506 | } | 531 | } |
507 | } | 532 | } |
508 | } | 533 | } |
534 | + if (this.labelPatternsSourcesData?.length) { | ||
535 | + this.substituteLabelPatterns(series, i); | ||
536 | + } | ||
509 | } | 537 | } |
510 | 538 | ||
511 | this.subscribeForThresholdsAttributes(thresholdsDatasources); | 539 | this.subscribeForThresholdsAttributes(thresholdsDatasources); |
@@ -569,6 +597,10 @@ export class TbFlot { | @@ -569,6 +597,10 @@ export class TbFlot { | ||
569 | this.yaxes[yaxisIndex].keysInfo[i].hidden = series.dataKey.hidden; | 597 | this.yaxes[yaxisIndex].keysInfo[i].hidden = series.dataKey.hidden; |
570 | axisVisibilityChanged = true; | 598 | axisVisibilityChanged = true; |
571 | } | 599 | } |
600 | + | ||
601 | + if (this.labelPatternsSourcesData?.length) { | ||
602 | + this.substituteLabelPatterns(series, i); | ||
603 | + } | ||
572 | } | 604 | } |
573 | if (axisVisibilityChanged) { | 605 | if (axisVisibilityChanged) { |
574 | this.options.yaxes.length = 0; | 606 | this.options.yaxes.length = 0; |
@@ -849,6 +881,60 @@ export class TbFlot { | @@ -849,6 +881,60 @@ export class TbFlot { | ||
849 | } | 881 | } |
850 | } | 882 | } |
851 | 883 | ||
884 | + private subscribeForLabelPatternsSources(datasources: Datasource[]) { | ||
885 | + const labelPatternsSourcesSubscriptionOptions: WidgetSubscriptionOptions = { | ||
886 | + datasources, | ||
887 | + useDashboardTimewindow: false, | ||
888 | + type: widgetType.latest, | ||
889 | + callbacks: { | ||
890 | + onDataUpdated: (subscription) => { | ||
891 | + this.labelPatternsParamsDataUpdated(subscription.data) | ||
892 | + } | ||
893 | + } | ||
894 | + }; | ||
895 | + this.ctx.subscriptionApi.createSubscription(labelPatternsSourcesSubscriptionOptions, true).subscribe( | ||
896 | + (subscription) => { | ||
897 | + this.labelPatternsSourcesSubscription = subscription; | ||
898 | + } | ||
899 | + ); | ||
900 | + } | ||
901 | + | ||
902 | + private labelPatternsParamsDataUpdated(data: DatasourceData[]) { | ||
903 | + this.labelPatternsSourcesData = data; | ||
904 | + for (let i = 0; i < this.subscription.data.length; i++) { | ||
905 | + const series = this.subscription.data[i] as TbFlotSeries; | ||
906 | + this.substituteLabelPatterns(series, i); | ||
907 | + } | ||
908 | + this.updateData(); | ||
909 | + this.ctx.detectChanges(); | ||
910 | + } | ||
911 | + | ||
912 | + private substituteLabelPatterns(series: TbFlotSeries, seriesIndex: number) { | ||
913 | + let seriesLabelPatternsSourcesData = this.labelPatternsSourcesData.filter((item) => { | ||
914 | + return item.datasource.entityId === series.datasource.entityId; | ||
915 | + }); | ||
916 | + let label = createLabelFromDatasource(series.datasource, series.dataKey.pattern); | ||
917 | + for (let i = 0; i < seriesLabelPatternsSourcesData.length; i++) { | ||
918 | + let keyData = seriesLabelPatternsSourcesData[i]; | ||
919 | + if (keyData && keyData.data && keyData.data[0]) { | ||
920 | + let attrValue = keyData.data[0][1]; | ||
921 | + let attrName = keyData.dataKey.name; | ||
922 | + if (isDefined(attrValue) && (attrValue !== null)) { | ||
923 | + label = insertVariable(label, attrName, attrValue); | ||
924 | + } | ||
925 | + } | ||
926 | + } | ||
927 | + if (isDefined(this.subscription.legendData)) { | ||
928 | + let targetLegendKeyIndex = this.subscription.legendData.keys.findIndex((key) => { | ||
929 | + return key.dataIndex === seriesIndex; | ||
930 | + }); | ||
931 | + if (targetLegendKeyIndex !== -1) { | ||
932 | + this.subscription.legendData.keys[targetLegendKeyIndex].dataKey.label = label; | ||
933 | + } | ||
934 | + } | ||
935 | + series.dataKey.label = label; | ||
936 | + } | ||
937 | + | ||
852 | private seriesInfoDiv(label: string, color: string, value: any, | 938 | private seriesInfoDiv(label: string, color: string, value: any, |
853 | units: string, trackDecimals: number, active: boolean, | 939 | units: string, trackDecimals: number, active: boolean, |
854 | percent: number, valueFormatFunction: TooltipValueFormatFunction): JQuery<HTMLElement> { | 940 | percent: number, valueFormatFunction: TooltipValueFormatFunction): JQuery<HTMLElement> { |