import { ComponentType } from 'react'; import { Observable } from 'rxjs'; import { CustomVariableSupport, DataQuery, DataQueryRequest, DataQueryResponse, DataSourceApi, DataSourceJsonData, DataSourceRef, MetricFindValue, StandardVariableQuery, StandardVariableSupport, VariableModel, VariableSupportType, } from '@grafana/data'; import { LEGACY_VARIABLE_QUERY_EDITOR_NAME } from './editor/LegacyVariableQueryEditor'; import { AdHocVariableModel, ConstantVariableModel, QueryVariableModel, VariableQueryEditorType, VariableQueryEditorProps, VariableWithMultiSupport, VariableWithOptions, } from './types'; export const isQuery = (model: VariableModel): model is QueryVariableModel => { return model.type === 'query'; }; export const isAdHoc = (model: VariableModel): model is AdHocVariableModel => { return model.type === 'adhoc'; }; export const isConstant = (model: VariableModel): model is ConstantVariableModel => { return model.type === 'constant'; }; export const isMulti = (model: VariableModel): model is VariableWithMultiSupport => { const withMulti = model as VariableWithMultiSupport; return withMulti.hasOwnProperty('multi') && typeof withMulti.multi === 'boolean'; }; export const hasOptions = (model: VariableModel): model is VariableWithOptions => { return hasObjectProperty(model, 'options'); }; export const hasCurrent = (model: VariableModel): model is VariableWithOptions => { return hasObjectProperty(model, 'current'); }; function hasObjectProperty(model: VariableModel, property: string): model is VariableWithOptions { if (!model) { return false; } const withProperty = model as Record; return withProperty.hasOwnProperty(property) && typeof withProperty[property] === 'object'; } export function isLegacyAdHocDataSource(datasource: null | DataSourceRef | string): datasource is string { if (datasource === null) { return false; } return typeof datasource === 'string'; } interface DataSourceWithLegacyVariableSupport< TQuery extends DataQuery = DataQuery, TOptions extends DataSourceJsonData = DataSourceJsonData > extends DataSourceApi { metricFindQuery(query: any, options?: any): Promise; variables: undefined; } interface DataSourceWithStandardVariableSupport< TQuery extends DataQuery = DataQuery, TOptions extends DataSourceJsonData = DataSourceJsonData > extends DataSourceApi { variables: { getType(): VariableSupportType; toDataQuery(query: StandardVariableQuery): TQuery; query(request: DataQueryRequest): Observable; }; } interface DataSourceWithCustomVariableSupport< VariableQuery extends DataQuery = any, TQuery extends DataQuery = DataQuery, TOptions extends DataSourceJsonData = DataSourceJsonData > extends DataSourceApi { variables: { getType(): VariableSupportType; editor: VariableQueryEditorType; query(request: DataQueryRequest): Observable; }; } interface DataSourceWithDatasourceVariableSupport< TQuery extends DataQuery = DataQuery, TOptions extends DataSourceJsonData = DataSourceJsonData > extends DataSourceApi { variables: { getType(): VariableSupportType; }; } /* * The following guard function are both TypeScript type guards. * They also make the basis for the logic used by variableQueryRunner and determining which QueryEditor to use * */ export const hasLegacyVariableSupport = < TQuery extends DataQuery = DataQuery, TOptions extends DataSourceJsonData = DataSourceJsonData >( datasource: DataSourceApi ): datasource is DataSourceWithLegacyVariableSupport => { return Boolean(datasource.metricFindQuery) && !Boolean(datasource.variables); }; export const hasStandardVariableSupport = < TQuery extends DataQuery = DataQuery, TOptions extends DataSourceJsonData = DataSourceJsonData >( datasource: DataSourceApi ): datasource is DataSourceWithStandardVariableSupport => { if (!datasource.variables) { return false; } if (datasource.variables.getType() !== VariableSupportType.Standard) { return false; } const variableSupport = datasource.variables as StandardVariableSupport>; return Boolean(variableSupport.toDataQuery); }; export const hasCustomVariableSupport = < TQuery extends DataQuery = DataQuery, TOptions extends DataSourceJsonData = DataSourceJsonData >( datasource: DataSourceApi ): datasource is DataSourceWithCustomVariableSupport => { if (!datasource.variables) { return false; } if (datasource.variables.getType() !== VariableSupportType.Custom) { return false; } const variableSupport = datasource.variables as CustomVariableSupport>; return Boolean(variableSupport.query) && Boolean(variableSupport.editor); }; export const hasDatasourceVariableSupport = < TQuery extends DataQuery = DataQuery, TOptions extends DataSourceJsonData = DataSourceJsonData >( datasource: DataSourceApi ): datasource is DataSourceWithDatasourceVariableSupport => { if (!datasource.variables) { return false; } return datasource.variables.getType() === VariableSupportType.Datasource; }; export function isLegacyQueryEditor< TQuery extends DataQuery = DataQuery, TOptions extends DataSourceJsonData = DataSourceJsonData >( component: VariableQueryEditorType, datasource: DataSourceApi ): component is ComponentType { if (!component) { return false; } return component.displayName === LEGACY_VARIABLE_QUERY_EDITOR_NAME || hasLegacyVariableSupport(datasource); } export function isQueryEditor< TQuery extends DataQuery = DataQuery, TOptions extends DataSourceJsonData = DataSourceJsonData >( component: VariableQueryEditorType, datasource: DataSourceApi ): component is VariableQueryEditorType { if (!component) { return false; } return ( component.displayName !== LEGACY_VARIABLE_QUERY_EDITOR_NAME && (hasDatasourceVariableSupport(datasource) || hasStandardVariableSupport(datasource) || hasCustomVariableSupport(datasource)) ); }