import { lastValueFrom } from 'rxjs'; import { DataFrame, DataLinkConfigOrigin } from '@grafana/data'; import { getBackendSrv, getDataSourceSrv } from '@grafana/runtime'; import { ExploreItemState } from 'app/types'; import { formatValueName } from '../explore/PrometheusListView/ItemLabels'; import { CreateCorrelationParams, CreateCorrelationResponse } from './types'; import { CorrelationData, CorrelationsData, CorrelationsResponse, getData, toEnrichedCorrelationsData, } from './useCorrelations'; type DataFrameRefIdToDataSourceUid = Record; /** * Creates data links from provided CorrelationData object * * @param dataFrames list of data frames to be processed * @param correlations list of of possible correlations that can be applied * @param dataFrameRefIdToDataSourceUid a map that for provided refId references corresponding data source ui */ export const attachCorrelationsToDataFrames = ( dataFrames: DataFrame[], correlations: CorrelationData[], dataFrameRefIdToDataSourceUid: DataFrameRefIdToDataSourceUid ): DataFrame[] => { dataFrames.forEach((dataFrame) => { const frameRefId = dataFrame.refId; if (!frameRefId) { return; } let dataSourceUid = dataFrameRefIdToDataSourceUid[frameRefId]; // rawPrometheus queries append a value to refId to a separate dataframe for the table view if (dataSourceUid === undefined && dataFrame.meta?.preferredVisualisationType === 'rawPrometheus') { const formattedRefID = formatValueName(frameRefId); dataSourceUid = dataFrameRefIdToDataSourceUid[formattedRefID]; } const sourceCorrelations = correlations.filter((correlation) => correlation.source.uid === dataSourceUid); decorateDataFrameWithInternalDataLinks(dataFrame, sourceCorrelations); }); return dataFrames; }; const decorateDataFrameWithInternalDataLinks = (dataFrame: DataFrame, correlations: CorrelationData[]) => { dataFrame.fields.forEach((field) => { field.config.links = field.config.links?.filter((link) => link.origin !== DataLinkConfigOrigin.Correlations) || []; correlations.map((correlation) => { if (correlation.config?.field === field.name) { const targetQuery = correlation.config?.target || {}; field.config.links!.push({ internal: { query: { ...targetQuery, datasource: { uid: correlation.target.uid } }, datasourceUid: correlation.target.uid, datasourceName: correlation.target.name, transformations: correlation.config?.transformations, }, url: '', title: correlation.label || correlation.target.name, origin: DataLinkConfigOrigin.Correlations, }); } }); }); }; export const getCorrelationsBySourceUIDs = async (sourceUIDs: string[]): Promise => { return lastValueFrom( getBackendSrv().fetch({ url: `/api/datasources/correlations`, method: 'GET', showErrorAlert: false, params: { sourceUID: sourceUIDs, }, }) ) .then(getData) .then(toEnrichedCorrelationsData); }; export const createCorrelation = async ( sourceUID: string, correlation: CreateCorrelationParams ): Promise => { return getBackendSrv().post(`/api/datasources/uid/${sourceUID}/correlations`, correlation); }; const getDSInstanceForPane = async (pane: ExploreItemState) => { if (pane.datasourceInstance?.meta.mixed) { return await getDataSourceSrv().get(pane.queries[0].datasource); } else { return pane.datasourceInstance; } }; export const generateDefaultLabel = async (sourcePane: ExploreItemState, targetPane: ExploreItemState) => { return Promise.all([getDSInstanceForPane(sourcePane), getDSInstanceForPane(targetPane)]).then((dsInstances) => { return dsInstances[0]?.name !== undefined && dsInstances[1]?.name !== undefined ? `${dsInstances[0]?.name} to ${dsInstances[1]?.name}` : ''; }); };