add query inspector, clean up some stuff

This commit is contained in:
Paul Marbach
2025-12-04 17:29:36 -05:00
parent badacad658
commit e5174895d6
7 changed files with 51 additions and 28 deletions
@@ -1,9 +1,9 @@
import { css } from '@emotion/css';
import { memo, useCallback, useRef } from 'react';
import { DataFrame, DataQuery, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { DataFrame, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { VizPanel } from '@grafana/scenes';
import { SceneDataQuery, VizPanel } from '@grafana/scenes';
import { Container, ScrollContainer, useStyles2 } from '@grafana/ui';
import { isExpressionQuery } from 'app/features/expressions/guards';
@@ -18,7 +18,7 @@ import { TabId, QueryTransformItem } from './types';
export interface QueryLibraryMode {
active: boolean;
mode: 'browse' | 'save';
currentQuery?: DataQuery;
currentQuery?: SceneDataQuery;
}
interface DetailViewProps {
@@ -33,10 +33,11 @@ interface DetailViewProps {
transformationData?: DataFrame[];
onGoToQueries?: () => void;
queryLibraryMode?: QueryLibraryMode;
onQueryLibrarySelect?: (query: DataQuery) => void;
onQueryLibrarySelect?: (query: SceneDataQuery) => void;
onQueryLibrarySave?: (name: string, description: string) => void;
onQueryLibraryClose?: () => void;
onOpenQueryLibrary?: (mode: 'browse' | 'save', index?: number) => void;
onOpenQueryInspector?: () => void;
isDebugMode?: boolean;
debugPosition?: number;
}
@@ -58,6 +59,7 @@ export const DetailView = memo(
onQueryLibrarySave,
onQueryLibraryClose,
onOpenQueryLibrary,
onOpenQueryInspector,
isDebugMode,
debugPosition,
}: DetailViewProps) => {
@@ -119,22 +121,27 @@ export const DetailView = memo(
);
}
if (selectedItem.type === 'query' && 'refId' in selectedItem.data) {
if (selectedItem.type === 'query') {
const query = selectedItem.data;
return (
<>
<DetailViewHeader selectedItem={selectedItem} panel={panel} onOpenQueryLibrary={onOpenQueryLibrary} />
<DetailViewHeader
selectedItem={selectedItem}
panel={panel}
onOpenQueryLibrary={onOpenQueryLibrary}
onOpenQueryInspector={onOpenQueryInspector}
/>
<ScrollContainer>
<QueryDetailView panel={panel} query={query} queryIndex={selectedItem.index} />
</ScrollContainer>
</>
);
} else if (selectedItem.type === 'expression' && 'refId' in selectedItem.data) {
} else if (selectedItem.type === 'expression') {
const data = selectedItem.data;
if (isExpressionQuery(data)) {
return (
<>
<DetailViewHeader selectedItem={selectedItem} panel={panel} />
<DetailViewHeader selectedItem={selectedItem} panel={panel} onOpenQueryInspector={onOpenQueryInspector} />
<ScrollContainer>
<ExpressionDetailView panel={panel} expression={data} expressionIndex={selectedItem.index} />
</ScrollContainer>
@@ -143,7 +150,7 @@ export const DetailView = memo(
}
} else {
const transformsTab = tabs.find((t): t is PanelDataTransformationsTab => t.tabId === TabId.Transformations);
if (transformsTab && 'id' in selectedItem.data) {
if (transformsTab) {
return (
<>
<DetailViewHeader
@@ -166,24 +173,27 @@ export const DetailView = memo(
return null;
}, [
selectedItem,
panel,
tabs,
styles.emptyState,
onRemoveTransform,
onToggleTransformVisibility,
isAddingTransform,
onAddTransformation,
onCancelAddTransform,
queryLibraryMode?.active,
queryLibraryMode?.mode,
queryLibraryMode?.currentQuery,
onQueryLibraryClose,
selectedItem,
transformationData,
onGoToQueries,
queryLibraryMode,
onQueryLibrarySelect,
onQueryLibrarySave,
onQueryLibraryClose,
onOpenQueryLibrary,
handleSelectQueryFromHeader,
handleSaveQueryFromHeader,
onQueryLibrarySelect,
onQueryLibrarySave,
styles.emptyState,
panel,
onOpenQueryLibrary,
onOpenQueryInspector,
tabs,
onRemoveTransform,
onToggleTransformVisibility,
isDebugMode,
debugPosition,
]);
@@ -45,6 +45,7 @@ interface ItemModeProps {
onRemoveTransform?: (index: number) => void;
onToggleTransformVisibility?: (index: number) => void;
onOpenQueryLibrary?: (mode: 'browse' | 'save') => void;
onOpenQueryInspector?: () => void;
isDebugMode?: boolean;
debugPosition?: number;
queryLibraryMode?: never;
@@ -59,6 +60,7 @@ interface QueryLibraryModeProps {
onRemoveTransform?: never;
onToggleTransformVisibility?: never;
onOpenQueryLibrary?: never;
onOpenQueryInspector?: never;
queryLibraryMode: 'browse' | 'save';
onSelectQuery?: () => void;
onSaveQuery?: () => void;
@@ -152,6 +154,7 @@ function ItemHeader({
onRemoveTransform,
onToggleTransformVisibility,
onOpenQueryLibrary,
onOpenQueryInspector,
isDebugMode,
debugPosition,
}: ItemModeProps) {
@@ -567,6 +570,11 @@ function ItemHeader({
icon="trash-alt"
onClick={onRemoveQuery}
/>
<Menu.Item
label={t('dashboard-scene.detail-view-header.query-inspector', 'Query inspector')}
icon="wrench"
onClick={onOpenQueryInspector}
/>
</Menu>
}
>
@@ -693,6 +701,7 @@ export const DetailViewHeader = (props: DetailViewHeaderProps) => {
onRemoveTransform={props.onRemoveTransform}
onToggleTransformVisibility={props.onToggleTransformVisibility}
onOpenQueryLibrary={props.onOpenQueryLibrary}
onOpenQueryInspector={props.onOpenQueryInspector}
isDebugMode={props.isDebugMode}
debugPosition={props.debugPosition}
/>
@@ -709,7 +718,7 @@ const getStyles = (theme: GrafanaTheme2, config: { color: string }) => {
borderLeft: `4px solid ${config.color}`,
borderBottom: `1px solid ${theme.colors.border.weak}`,
background: theme.colors.background.secondary,
minHeight: '41px',
minHeight: theme.spacing(6),
}),
headerContent: css({
display: 'flex',
@@ -316,6 +316,10 @@ function PanelDataPaneRendered({ model }: SceneComponentProps<PanelDataPane>) {
[transformations, transformsTab]
);
const handleOpenQueryInspector = useCallback(() => {
queriesTab?.onOpenInspector();
}, [queriesTab]);
// Get data for transformations drawer
const sourceData = queryRunner?.useState();
const series = sourceData?.data?.series || [];
@@ -339,6 +343,7 @@ function PanelDataPaneRendered({ model }: SceneComponentProps<PanelDataPane>) {
onQueryLibrarySave={handleQueryLibrarySave}
onQueryLibraryClose={handleQueryLibraryClose}
onOpenQueryLibrary={handleOpenQueryLibrary}
onOpenQueryInspector={handleOpenQueryInspector}
isDebugMode={isDebugMode}
debugPosition={debugPosition}
/>
@@ -837,7 +837,7 @@ async function setupScene(panelId: string) {
deactivators.push(dashboard.activate());
deactivators.push(panelEditor.activate());
const queriesTab = panelEditor.state.dataPane!.state.editorRef.resolve().state.dataPaneTabs[0];
const queriesTab = panelEditor.state.dataPane!.state.tabs[0];
deactivators.push(queriesTab.activate());
await Promise.resolve();
@@ -90,7 +90,7 @@ export function PanelDataTransformationsTabRendered({
return;
}
const queriesTab = parent.state.editorRef.resolve().state.dataPaneTabs.find((tab) => tab.tabId === TabId.Queries);
const queriesTab = parent.state.tabs.find((tab) => tab.tabId === TabId.Queries);
if (!(queriesTab instanceof PanelDataQueriesTab)) {
return;
}
@@ -780,8 +780,6 @@ export const QueryTransformList = memo(
QueryTransformList.displayName = 'QueryTransformList';
const getStyles = (theme: GrafanaTheme2, colors: ReturnType<typeof usePanelDataPaneColors>) => {
const headerHeight = 41;
const footerHeight = 32;
const barBase = {
padding: theme.spacing(0.5, 2),
background: theme.colors.background.secondary,
@@ -804,7 +802,7 @@ const getStyles = (theme: GrafanaTheme2, colors: ReturnType<typeof usePanelDataP
}),
header: css({
...barBase,
height: headerHeight,
height: theme.spacing(6),
borderBottom: `1px solid ${theme.colors.border.weak}`,
'& > div:first-child': {
@@ -929,7 +927,7 @@ const getStyles = (theme: GrafanaTheme2, colors: ReturnType<typeof usePanelDataP
}),
footer: css({
...barBase,
height: footerHeight,
height: theme.spacing(4),
borderTop: `1px solid ${theme.colors.border.weak}`,
gap: theme.spacing(1),
position: 'relative',
@@ -197,7 +197,7 @@ function getStyles(theme: GrafanaTheme2) {
}),
pageContainerWithControls: css({
gridTemplateAreas: `
"controls controls"
"sidebar controls"
"sidebar panels"`,
gridTemplateRows: 'auto 1fr',
}),
@@ -210,6 +210,7 @@ function getStyles(theme: GrafanaTheme2) {
height: '100%',
maxHeight: '100%',
overflow: 'auto',
paddingTop: theme.spacing(2),
}),
expandDataSidebar: css({
width: theme.spacing(6),