From 77477f69ee1e98e8461454aa5cc47902692cedee Mon Sep 17 00:00:00 2001 From: Chantsova Ekaterina Date: Wed, 22 Jul 2020 11:33:22 +0300 Subject: [PATCH] Flot: add ability to use attributes in datakeys labels --- .../widget/lib/flot-widget.models.ts | 87 ++++++++++++++++-- .../home/components/widget/lib/flot-widget.ts | 88 ++++++++++++++++++- 2 files changed, 169 insertions(+), 6 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts index 6726931576..450219681a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts @@ -19,6 +19,7 @@ import { DataKey, Datasource, DatasourceData, JsonSettingsSchema } from '@shared/models/widget.models'; import * as moment_ from 'moment'; +import { DataKeyType } from "@shared/models/telemetry/telemetry.models"; export declare type ChartType = 'line' | 'pie' | 'bar' | 'state' | 'graph'; @@ -149,13 +150,24 @@ export interface TbFlotThresholdsSettings { thresholdsLineWidth: number; } -export interface TbFlotGraphSettings extends TbFlotBaseSettings, TbFlotThresholdsSettings, TbFlotComparisonSettings { +export interface TbFlotCustomLegendSettings { + customLegendEnabled: boolean; + dataKeysListForLabels: Array; +} + +export interface TbFlotLabelPatternSettings { + name: string; + type: DataKeyType; + settings?: object +} + +export interface TbFlotGraphSettings extends TbFlotBaseSettings, TbFlotThresholdsSettings, TbFlotComparisonSettings, TbFlotCustomLegendSettings { smoothLines: boolean; } export declare type BarAlignment = 'left' | 'right' | 'center'; -export interface TbFlotBarSettings extends TbFlotBaseSettings, TbFlotThresholdsSettings, TbFlotComparisonSettings { +export interface TbFlotBarSettings extends TbFlotBaseSettings, TbFlotThresholdsSettings, TbFlotComparisonSettings, TbFlotCustomLegendSettings { defaultBarWidth: number; barAlignment: BarAlignment; } @@ -503,13 +515,17 @@ export function flotSettingsSchema(chartType: ChartType): JsonSettingsSchema { GroupTitle: 'Common Settings' }]; schema.form = [schema.form]; - schema.schema.properties = {...schema.schema.properties, ...chartSettingsSchemaForComparison.schema.properties}; - schema.schema.required = schema.schema.required.concat(chartSettingsSchemaForComparison.schema.required); - schema.form.push(chartSettingsSchemaForComparison.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; } @@ -603,6 +619,67 @@ const chartSettingsSchemaForComparison: JsonSettingsSchema = { ] }; +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', diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts index 8692b48c4f..1d00ee307e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts @@ -16,7 +16,15 @@ import { WidgetContext } from '@home/models/widget-component.models'; -import { deepClone, isDefined, isEqual, isNumber, isUndefined } from '@app/core/utils'; +import { + createLabelFromDatasource, + deepClone, + insertVariable, + isDefined, + isEqual, + isNumber, + isUndefined +} from '@app/core/utils'; import { IWidgetSubscription, WidgetSubscriptionOptions } from '@core/api/widget-api.models'; import { DataKey, @@ -88,6 +96,9 @@ export class TbFlot { private thresholdsSourcesSubscription: IWidgetSubscription; private predefinedThresholds: TbFlotThresholdMarking[]; + private labelPatternsSourcesSubscription: IWidgetSubscription; + private labelPatternsSourcesData: DatasourceData[]; + private plotInited = false; private plot: JQueryPlot; @@ -369,6 +380,20 @@ export class TbFlot { const yaxesMap: {[units: string]: TbFlotAxisOptions} = {}; const predefinedThresholds: TbFlotThresholdMarking[] = []; const thresholdsDatasources: Datasource[] = []; + if (this.settings.customLegendEnabled) { + this.labelPatternsSourcesData = []; + const labelPatternsDatasources: Datasource[] = []; + subscription.datasources.forEach((item) => { + let datasource: Datasource = { + type: item.type, + entityType: item.entityType, + entityId: item.entityId, + dataKeys: this.settings.dataKeysListForLabels + }; + labelPatternsDatasources.push(datasource); + }); + this.subscribeForLabelPatternsSources(labelPatternsDatasources); + } let tooltipValueFormatFunction: TooltipValueFormatFunction = null; if (this.settings.tooltipValueFormatter && this.settings.tooltipValueFormatter.length) { @@ -506,6 +531,9 @@ export class TbFlot { } } } + if (this.labelPatternsSourcesData?.length) { + this.substituteLabelPatterns(series, i); + } } this.subscribeForThresholdsAttributes(thresholdsDatasources); @@ -569,6 +597,10 @@ export class TbFlot { this.yaxes[yaxisIndex].keysInfo[i].hidden = series.dataKey.hidden; axisVisibilityChanged = true; } + + if (this.labelPatternsSourcesData?.length) { + this.substituteLabelPatterns(series, i); + } } if (axisVisibilityChanged) { this.options.yaxes.length = 0; @@ -849,6 +881,60 @@ export class TbFlot { } } + private subscribeForLabelPatternsSources(datasources: Datasource[]) { + const labelPatternsSourcesSubscriptionOptions: WidgetSubscriptionOptions = { + datasources, + useDashboardTimewindow: false, + type: widgetType.latest, + callbacks: { + onDataUpdated: (subscription) => { + this.labelPatternsParamsDataUpdated(subscription.data) + } + } + }; + this.ctx.subscriptionApi.createSubscription(labelPatternsSourcesSubscriptionOptions, true).subscribe( + (subscription) => { + this.labelPatternsSourcesSubscription = subscription; + } + ); + } + + private labelPatternsParamsDataUpdated(data: DatasourceData[]) { + this.labelPatternsSourcesData = data; + for (let i = 0; i < this.subscription.data.length; i++) { + const series = this.subscription.data[i] as TbFlotSeries; + this.substituteLabelPatterns(series, i); + } + this.updateData(); + this.ctx.detectChanges(); + } + + private substituteLabelPatterns(series: TbFlotSeries, seriesIndex: number) { + let seriesLabelPatternsSourcesData = this.labelPatternsSourcesData.filter((item) => { + return item.datasource.entityId === series.datasource.entityId; + }); + let label = createLabelFromDatasource(series.datasource, series.dataKey.pattern); + for (let i = 0; i < seriesLabelPatternsSourcesData.length; i++) { + let keyData = seriesLabelPatternsSourcesData[i]; + if (keyData && keyData.data && keyData.data[0]) { + let attrValue = keyData.data[0][1]; + let attrName = keyData.dataKey.name; + if (isDefined(attrValue) && (attrValue !== null)) { + label = insertVariable(label, attrName, attrValue); + } + } + } + if (isDefined(this.subscription.legendData)) { + let targetLegendKeyIndex = this.subscription.legendData.keys.findIndex((key) => { + return key.dataIndex === seriesIndex; + }); + if (targetLegendKeyIndex !== -1) { + this.subscription.legendData.keys[targetLegendKeyIndex].dataKey.label = label; + } + } + series.dataKey.label = label; + } + private seriesInfoDiv(label: string, color: string, value: any, units: string, trackDecimals: number, active: boolean, percent: number, valueFormatFunction: TooltipValueFormatFunction): JQuery {