Skip to content

Commit

Permalink
extract explore URL logic to util
Browse files Browse the repository at this point in the history
  • Loading branch information
domasx2 committed Nov 11, 2024
1 parent fb17d31 commit 2c63320
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 44 deletions.
55 changes: 11 additions & 44 deletions packages/scenes/src/components/VizPanel/VizPanelExploreButton.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, { useMemo } from 'react';
import React from 'react';

import { SceneComponentProps, sceneGraph, SceneObjectBase, SceneObjectState } from '@grafana/scenes';
import { LinkButton } from '@grafana/ui';
import { DataQuery } from '@grafana/schema';
import { getDataSourceSrv } from '@grafana/runtime';
import { ScopedVars } from '@grafana/data';
import { useAsync } from 'react-use';
import { SceneComponentProps, SceneObjectState } from '../../core/types';
import { SceneObjectBase } from '../../core/SceneObjectBase';
import { sceneGraph } from '../../core/sceneGraph';
import { getExploreURL } from '../../utils/explore';

export interface ExploreButtonOptions {
// Callback to hook in tracking / analytics
Expand All @@ -32,55 +33,21 @@ function VizPanelExploreButtonComponent({ model }: SceneComponentProps<VizPanelE

const { data } = sceneGraph.getData(model).useState();

const targets = useMemo(() => data?.request?.targets ?? [], [data]);

const { from, to } = sceneGraph.getTimeRange(model).useState();

const { value: interpolatedQueries } = useAsync(async () => {
const scopedVars: ScopedVars = {
__sceneObject: { text: '__sceneObject', value: model },
};
return (
await Promise.allSettled(
targets.map(async (q) => {
const queryDs = await getDataSourceSrv().get(q.datasource);
return queryDs.interpolateVariablesInQueries?.([q], scopedVars ?? {})[0] || q;
})
)
)
.filter((promise): promise is PromiseFulfilledResult<DataQuery> => promise.status === 'fulfilled')
.map((q) => q.value)
.map((q) => options.transform?.(q) ?? q);
}, [targets, model]);

const left = useMemo(() => {
const queries: DataQuery[] = interpolatedQueries ?? [];

const datasource = queries.find((query) => !!query.datasource?.uid)?.datasource?.uid;

if (queries?.length && datasource && from && to) {
return encodeURIComponent(
JSON.stringify({
datasource,
queries,
range: {
from,
to,
},
})
);
}
return '';
}, [interpolatedQueries, from, to]);
const { value: exploreLink } = useAsync(
async () => (data ? getExploreURL(data, model, { from, to }, options.transform) : ''),
[data, model, from, to]
);

if (left) {
if (exploreLink) {
return (
<LinkButton
key="explore"
icon="compass"
size="sm"
variant="secondary"
href={`/explore?left=${left}`}
href={exploreLink}
onClick={options.onClick}
>
Explore
Expand Down
1 change: 1 addition & 0 deletions packages/scenes/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,4 @@ export const sceneUtils = {
};

export { SafeSerializableSceneObject } from './utils/SafeSerializableSceneObject';
export { getExploreURL } from './utils/explore';
60 changes: 60 additions & 0 deletions packages/scenes/src/utils/explore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { PanelData, RawTimeRange, ScopedVars } from '@grafana/data';
import { SceneObject } from '../core/types';
import { wrapInSafeSerializableSceneObject } from './wrapInSafeSerializableSceneObject';
import { getDataSourceSrv } from '@grafana/runtime';
import { DataQuery } from '@grafana/schema';

/**
* Returns URL to Grafana explore for the queries in the given panel data and time range.
*/
export async function getExploreURL(
data: PanelData,
model: SceneObject,
timeRange: RawTimeRange,
transform?: (query: DataQuery) => DataQuery
): Promise<string> {
const targets = data.request?.targets;
if (!targets) {
return '';
}

const { from, to } = timeRange;

const filters = data.request?.filters;

const scopedVars: ScopedVars = {
__sceneObject: wrapInSafeSerializableSceneObject(model),
};

const interpolatedQueries = (
await Promise.allSettled(
targets.map(async (q) => {
const queryDs = await getDataSourceSrv().get(q.datasource);
return queryDs.interpolateVariablesInQueries?.([q], scopedVars ?? {}, filters)[0] || q;
})
)
)
.filter((promise): promise is PromiseFulfilledResult<DataQuery> => promise.status === 'fulfilled')
.map((q) => q.value)
.map((q) => transform?.(q) ?? q);

const queries: DataQuery[] = interpolatedQueries ?? [];

const datasource = queries.find((query) => !!query.datasource?.uid)?.datasource?.uid;

if (queries?.length && datasource && from && to) {
const left = encodeURIComponent(
JSON.stringify({
datasource,
queries,
range: {
from,
to,
},
})
);

return `/explore?left=${left}`;
}
return '';
}

0 comments on commit 2c63320

Please sign in to comment.