diff --git a/src/QueryEditor/EventAssetProperties.tsx b/src/QueryEditor/EventAssetProperties.tsx index faab85a..3e72232 100644 --- a/src/QueryEditor/EventAssetProperties.tsx +++ b/src/QueryEditor/EventAssetProperties.tsx @@ -63,7 +63,9 @@ export const EventAssetProperties = (props: Props): React.JSX.Element => { const getSelectedAssetProperties = (): AssetProperty[] => { const assetPropertiesSet = new Set() - const selectedAssetProperties = props.selectedAssetProperties.flatMap((e) => props.datasource.multiSelectReplace(e)) + const selectedAssetProperties = props.selectedAssetProperties.flatMap((e) => + props.datasource.multiSelectReplace(e, {}) + ) for (const assetProperty of assetProperties) { const propertySelected = diff --git a/src/QueryEditor/Events.tsx b/src/QueryEditor/Events.tsx index ec298c9..7f57e11 100644 --- a/src/QueryEditor/Events.tsx +++ b/src/QueryEditor/Events.tsx @@ -75,7 +75,7 @@ export const Events = (props: Props): JSX.Element => { } const getSelectedAssets = (selected: string | undefined, assets: Asset[]): Asset[] => { - const replacedAssets = props.datasource.multiSelectReplace(selected) + const replacedAssets = props.datasource.multiSelectReplace(selected, {}) return matchedAssets(replacedAssets, assets) } @@ -133,6 +133,7 @@ export const Events = (props: Props): JSX.Element => { Condition: tag.condition || '', Operator: tag.operator || '=', Value: tag.value, + ScopedVars: {}, } filter.push(eventPropertyFilter) }) diff --git a/src/QueryEditor/Measurements.tsx b/src/QueryEditor/Measurements.tsx index 42b7474..ee31485 100644 --- a/src/QueryEditor/Measurements.tsx +++ b/src/QueryEditor/Measurements.tsx @@ -114,6 +114,7 @@ export const Measurements = (props: Props): React.JSX.Element => { const filter: MeasurementFilter = { Keyword: props.query.Regex, DatabaseUUIDs: props.query.Databases, + ScopedVars: {}, } const measurementKeys = await props.datasource.getTagKeysForMeasurements(filter) measurementKeys.forEach((e) => options.add(e)) @@ -134,6 +135,7 @@ export const Measurements = (props: Props): React.JSX.Element => { const filter: MeasurementFilter = { Keyword: props.query.Regex, DatabaseUUIDs: props.query.Databases, + ScopedVars: {}, } const tagValues = await props.datasource.getTagValuesForMeasurements(filter, key) tagValues.forEach((e) => options.add(e)) diff --git a/src/datasource.ts b/src/datasource.ts index 0253cba..9fba905 100644 --- a/src/datasource.ts +++ b/src/datasource.ts @@ -1,4 +1,4 @@ -import { CoreApp, DataQueryRequest, DataSourceInstanceSettings } from '@grafana/data' +import { CoreApp, DataQueryRequest, DataSourceInstanceSettings, ScopedVars } from '@grafana/data' import { DataSourceWithBackend, TemplateSrv, getTemplateSrv } from '@grafana/runtime' import { VariableSupport } from 'variable_support' import { AnnotationsQueryEditor } from 'AnnotationsQueryEditor/AnnotationsQueryEditor' @@ -71,53 +71,67 @@ export class DataSource extends DataSourceWithBackend this.multiSelectReplace(e)) + assetMeasurementQuery.Assets = assetMeasurementQuery.Assets?.flatMap((e) => + this.multiSelectReplace(e, request.scopedVars) + ) assetMeasurementQuery.AssetProperties = assetMeasurementQuery.AssetProperties.flatMap((e) => { - return this.multiSelectReplace(e) + return this.multiSelectReplace(e, request.scopedVars) }) - assetMeasurementQuery.Options = this.templateReplaceQueryOptions(assetMeasurementQuery.Options) + assetMeasurementQuery.Options = this.templateReplaceQueryOptions( + assetMeasurementQuery.Options, + request.scopedVars + ) target.query = assetMeasurementQuery break } case 'MeasurementQuery': { const measurementQuery = target.query as MeasurementQuery - measurementQuery.Databases = measurementQuery.Databases?.flatMap((e) => this.multiSelectReplace(e)) - measurementQuery.Measurements = measurementQuery.Measurements?.flatMap((m) => this.multiSelectReplace(m)) - measurementQuery.Options = this.templateReplaceQueryOptions(measurementQuery.Options) + measurementQuery.Databases = measurementQuery.Databases?.flatMap((e) => + this.multiSelectReplace(e, request.scopedVars) + ) + measurementQuery.Measurements = measurementQuery.Measurements?.flatMap((m) => + this.multiSelectReplace(m, request.scopedVars) + ) + measurementQuery.Options = this.templateReplaceQueryOptions(measurementQuery.Options, request.scopedVars) target.query = measurementQuery break } case 'RawQuery': { const rawQuery = target.query as RawQuery - rawQuery.TimeseriesDatabase = this.templateSrv.replace(rawQuery.TimeseriesDatabase) - rawQuery.Query = this.templateSrv.replace(rawQuery.Query) + rawQuery.TimeseriesDatabase = this.templateSrv.replace(rawQuery.TimeseriesDatabase, request.scopedVars) + rawQuery.Query = this.templateSrv.replace(rawQuery.Query, request.scopedVars) target.query = rawQuery break } case 'EventQuery': { const eventQuery = target.query as EventQuery - eventQuery.Assets = eventQuery.Assets?.flatMap((e) => this.multiSelectReplace(e)) - eventQuery.EventTypes = eventQuery.EventTypes?.flatMap((e) => this.multiSelectReplace(e)) - eventQuery.Statuses = eventQuery.Statuses?.flatMap((e) => this.multiSelectReplace(e)) - eventQuery.Properties = eventQuery.Properties?.flatMap((e) => this.multiSelectReplace(e)) + eventQuery.Assets = eventQuery.Assets?.flatMap((e) => this.multiSelectReplace(e, request.scopedVars)) + eventQuery.EventTypes = eventQuery.EventTypes?.flatMap((e) => + this.multiSelectReplace(e, request.scopedVars) + ) + eventQuery.Statuses = eventQuery.Statuses?.flatMap((e) => this.multiSelectReplace(e, request.scopedVars)) + eventQuery.Properties = eventQuery.Properties?.flatMap((e) => + this.multiSelectReplace(e, request.scopedVars) + ) eventQuery.PropertyFilter = eventQuery.PropertyFilter?.map((e) => { - e.Property = this.templateSrv.replace(e.Property) + e.Property = this.templateSrv.replace(e.Property, request.scopedVars) if (e.Value === 'select tag value') { return e } switch (e.Datatype) { case PropertyDatatype.Number: - e.Value = parseFloat(this.templateSrv.replace(String(e.Value))) + e.Value = parseFloat(this.templateSrv.replace(String(e.Value), request.scopedVars)) break case PropertyDatatype.Bool: - e.Value = this.templateSrv.replace(String(e.Value)) === 'true' + e.Value = this.templateSrv.replace(String(e.Value), request.scopedVars) === 'true' break case PropertyDatatype.String: - e.Value = this.templateSrv.replace(String(e.Value)) + e.Value = this.templateSrv.replace(String(e.Value), request.scopedVars) break } return e @@ -134,18 +148,18 @@ export class DataSource extends DataSourceWithBackend this.multiSelectReplace(e)) + options.GroupBy = options.GroupBy?.flatMap((e) => this.multiSelectReplace(e, scopedVars)) } if (options.Tags) { const tags: Attributes = {} for (const [key, value] of Object.entries(options.Tags)) { - tags[this.templateSrv.replace(key)] = this.templateSrv.replace(value) + tags[this.templateSrv.replace(key, scopedVars)] = this.templateSrv.replace(value, scopedVars) } options.Tags = tags } @@ -153,12 +167,12 @@ export class DataSource extends DataSourceWithBackend this.multiSelectReplace(e)) - filter.Keyword = this.templateSrv.replace(filter.Keyword) + filter.DatabaseUUIDs = filter.DatabaseUUIDs?.flatMap((e) => this.multiSelectReplace(e, filter.ScopedVars)) + filter.Keyword = this.templateSrv.replace(filter.Keyword, filter.ScopedVars) return filter } @@ -214,7 +228,7 @@ export class DataSource extends DataSourceWithBackend this.multiSelectReplace(e)) + const parentUUIDs = filter.ParentUUIDs.flatMap((e) => this.multiSelectReplace(e, filter.ScopedVars)) if (parentUUIDs.some((e) => e === '')) { // empty string means there is no parent selected return [] @@ -223,7 +237,7 @@ export class DataSource extends DataSourceWithBackend this.multiSelectReplace(e)) + params.AssetUUIDs = filter.AssetUUIDs.flatMap((e) => this.multiSelectReplace(e, filter.ScopedVars)) } } return this.getResource('asset-properties', params) @@ -260,7 +274,7 @@ export class DataSource extends DataSourceWithBackend - this.multiSelectReplace(e) + this.multiSelectReplace(e, filter.ScopedVars) ) } params = { diff --git a/src/types.ts b/src/types.ts index 9ced194..490d77e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import { DataSourceJsonData } from '@grafana/data' +import { DataSourceJsonData, ScopedVars } from '@grafana/data' import { DataQuery } from '@grafana/schema' export const labelWidth = 25 @@ -128,7 +128,11 @@ export enum EventTypePropertyType { Periodic = 'periodic', } -export interface MeasurementFilter { +export interface ResourceFilter { + ScopedVars?: ScopedVars +} + +export interface MeasurementFilter extends ResourceFilter { Keyword?: string DatabaseUUIDs?: string[] CollectorUUID?: string @@ -136,32 +140,32 @@ export interface MeasurementFilter { Statuses?: string[] } -export interface AssetFilter { +export interface AssetFilter extends ResourceFilter { Keyword?: string Path?: string ParentUUIDs?: string[] UseAssetPath?: boolean } -export interface AssetPropertyFilter { +export interface AssetPropertyFilter extends ResourceFilter { AssetUUIDs?: string[] Recursive?: boolean } -export interface TimeseriesDatabaseFilter { +export interface TimeseriesDatabaseFilter extends ResourceFilter { Keyword?: string } -export interface EventTypeFilter { +export interface EventTypeFilter extends ResourceFilter { Keyword?: string } -export interface EventTypePropertiesFilter { +export interface EventTypePropertiesFilter extends ResourceFilter { EventTypeUUIDs?: string[] Types?: string[] } -export interface EventPropertyFilter { +export interface EventPropertyFilter extends ResourceFilter { Property: string Datatype: string Value?: string | number | boolean diff --git a/src/variable_support.ts b/src/variable_support.ts index 6aead5a..e446337 100644 --- a/src/variable_support.ts +++ b/src/variable_support.ts @@ -1,6 +1,6 @@ import { forkJoin, from, map, of, Observable } from 'rxjs' -import { CustomVariableSupport, DataQueryRequest, DataQueryResponse, MetricFindValue } from '@grafana/data' +import { CustomVariableSupport, DataQueryRequest, DataQueryResponse, MetricFindValue, ScopedVars } from '@grafana/data' import { DataSource } from 'datasource' import { VariableQueryEditor } from 'CustomVariableEditor/VariableEditor' import { @@ -33,7 +33,7 @@ export interface DataAPI { getEventTypes(filter?: EventTypeFilter): Promise getEventTypeProperties(filter?: EventTypePropertiesFilter): Promise getEventConfigurations(): Promise - multiSelectReplace(value: string | undefined): string[] + multiSelectReplace(value: string | undefined, scopedVars: ScopedVars): string[] } export class VariableSupport extends CustomVariableSupport { @@ -50,6 +50,7 @@ export class VariableSupport extends CustomVariableSupport { case 'MeasurementQuery': { const filter = { ...request.targets[0].filter, + ScopedVars: request.scopedVars, } if (!filter) { return of({ data: [] }) @@ -61,7 +62,9 @@ export class VariableSupport extends CustomVariableSupport { } if (filter.DatabaseUUIDs) { - filter.DatabaseUUIDs = filter.DatabaseUUIDs?.flatMap((e) => this.dataAPI.multiSelectReplace(e)) + filter.DatabaseUUIDs = filter.DatabaseUUIDs?.flatMap((e) => + this.dataAPI.multiSelectReplace(e, request.scopedVars) + ) } return forkJoin({ @@ -85,32 +88,53 @@ export class VariableSupport extends CustomVariableSupport { case 'AssetQuery': { const filter = { ...request.targets[0].filter, + ScopedVars: request.scopedVars, } const useAssetPath = filter.UseAssetPath ?? false return from(this.dataAPI.getAssets(filter)).pipe( map((values) => { - return { data: values.map((v) => ({ text: useAssetPath ? v.AssetPath ?? v.Name : v.Name, value: v.UUID })) } + return { + data: values.map((v) => ({ + text: useAssetPath ? v.AssetPath ?? v.Name : v.Name, + value: v.UUID, + })), + } }) ) } case 'EventTypeQuery': { - return from(this.dataAPI.getEventTypes(request.targets[0].filter)).pipe( + const filter = { + ...request.targets[0].filter, + ScopedVars: request.scopedVars, + } + + return from(this.dataAPI.getEventTypes(filter)).pipe( map((values) => { return { data: values.map((v) => ({ text: v.Name, value: v.UUID })) } }) ) } case 'DatabaseQuery': { - return from(this.dataAPI.getTimeseriesDatabases(request.targets[0].filter)).pipe( + const filter = { + ...request.targets[0].filter, + ScopedVars: request.scopedVars, + } + + return from(this.dataAPI.getTimeseriesDatabases(filter)).pipe( map((values) => { return { data: values.map((v) => ({ text: v.Name, value: v.UUID })) } }) ) } case 'EventTypePropertyQuery': { + const filter = { + ...request.targets[0].filter, + ScopedVars: request.scopedVars, + } + return forkJoin({ eventTypes: this.dataAPI.getEventTypes(), - eventTypeProperties: this.dataAPI.getEventTypeProperties(request.targets[0].filter), + eventTypeProperties: this.dataAPI.getEventTypeProperties(filter), }).pipe( map((values) => { return { @@ -129,9 +153,10 @@ export class VariableSupport extends CustomVariableSupport { case 'AssetPropertyQuery': { const filter = { ...request.targets[0].filter, + ScopedVars: request.scopedVars, } if (filter.AssetUUIDs) { - filter.AssetUUIDs = filter.AssetUUIDs.flatMap((e) => this.dataAPI.multiSelectReplace(e)) + filter.AssetUUIDs = filter.AssetUUIDs.flatMap((e) => this.dataAPI.multiSelectReplace(e, request.scopedVars)) } return from(this.dataAPI.getAssetProperties(filter)).pipe( map((values) => {