feat: support of changing panel type in dashboards (#4759)

* feat: support of changing panel type in dashboards

* feat: add handle query change function

* feat: last bit of minor change

* feat: apply current query updates to superset query

* feat: pr cleanup

* feat: handle list type change

* fix: build issues

* fix: changes required due to refactor

* fix: handle offset and page size for list queries

* feat: handle functions propagation

* feat: handle the spaceAggregation value to retain

* fix: handle list panel type changes

* feat: handle removing the graph list from the side selection in case of metrics

* feat: handle list type qb changes

* feat: handle page breaking

* feat: pick dataSource from newQUeryItem

* feat: handle page reload
This commit is contained in:
Vikrant Gupta 2024-04-09 13:36:19 +05:30 committed by GitHub
parent e9bb05cc5d
commit 6815a96d29
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 494 additions and 21 deletions

View File

@ -30,7 +30,7 @@ const Items: ItemsProps[] = [
},
];
interface ItemsProps {
export interface ItemsProps {
name: PANEL_TYPES;
icon: JSX.Element;
display: string;

View File

@ -64,6 +64,7 @@ function WidgetGraphContainer({
selectedWidget={selectedWidget}
queryResponse={queryResponse}
setRequestData={setRequestData}
selectedGraph={selectedGraph}
/>
);
}

View File

@ -1,4 +1,5 @@
import { QueryParams } from 'constants/query';
import { PANEL_TYPES } from 'constants/queryBuilder';
import PanelWrapper from 'container/PanelWrapper/PanelWrapper';
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config';
import useUrlQuery from 'hooks/useUrlQuery';
@ -25,6 +26,7 @@ function WidgetGraph({
selectedWidget,
queryResponse,
setRequestData,
selectedGraph,
}: WidgetGraphProps): JSX.Element {
const graphRef = useRef<HTMLDivElement>(null);
const dispatch = useDispatch();
@ -89,6 +91,7 @@ function WidgetGraph({
queryResponse={queryResponse}
setRequestData={setRequestData}
onDragSelect={onDragSelect}
selectedGraph={selectedGraph}
/>
</div>
);
@ -101,6 +104,7 @@ interface WidgetGraphProps {
Error
>;
setRequestData: Dispatch<SetStateAction<GetQueryResultsProps>>;
selectedGraph: PANEL_TYPES;
}
export default WidgetGraph;

View File

@ -35,10 +35,10 @@ function LeftContainer({
>((state) => state.globalTime);
const [requestData, setRequestData] = useState<GetQueryResultsProps>(() => {
if (selectedWidget && selectedWidget.panelTypes !== PANEL_TYPES.LIST) {
if (selectedWidget && selectedGraph !== PANEL_TYPES.LIST) {
return {
selectedTime: selectedWidget?.timePreferance,
graphType: getGraphType(selectedWidget.panelTypes),
graphType: getGraphType(selectedGraph || selectedWidget.panelTypes),
query: stagedQuery || initialQueriesMap.metrics,
globalSelectedInterval,
variables: getDashboardVariables(selectedDashboard?.data.variables),
@ -65,6 +65,7 @@ function LeftContainer({
if (stagedQuery) {
setRequestData((prev) => ({
...prev,
graphType: getGraphType(selectedGraph || selectedWidget.panelTypes),
query: stagedQuery,
}));
}

View File

@ -12,10 +12,20 @@ import {
import InputComponent from 'components/Input';
import TimePreference from 'components/TimePreferenceDropDown';
import { PANEL_TYPES } from 'constants/queryBuilder';
import GraphTypes from 'container/NewDashboard/ComponentsSlider/menuItems';
import GraphTypes, {
ItemsProps,
} from 'container/NewDashboard/ComponentsSlider/menuItems';
import useCreateAlerts from 'hooks/queryBuilder/useCreateAlerts';
import { Dispatch, SetStateAction, useCallback } from 'react';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import {
Dispatch,
SetStateAction,
useCallback,
useEffect,
useState,
} from 'react';
import { Widgets } from 'types/api/dashboard/getAll';
import { DataSource } from 'types/common/queryBuilder';
import {
panelTypeVsCreateAlert,
@ -75,6 +85,24 @@ function RightContainer({
const allowPanelTimePreference =
panelTypeVsPanelTimePreferences[selectedGraph];
const { currentQuery } = useQueryBuilder();
const [graphTypes, setGraphTypes] = useState<ItemsProps[]>(GraphTypes);
useEffect(() => {
const queryContainsMetricsDataSource = currentQuery.builder.queryData.some(
(query) => query.dataSource === DataSource.METRICS,
);
if (queryContainsMetricsDataSource) {
setGraphTypes((prev) =>
prev.filter((graph) => graph.name !== PANEL_TYPES.LIST),
);
} else {
setGraphTypes(GraphTypes);
}
}, [currentQuery]);
const softMinHandler = useCallback(
(value: number | null) => {
setSoftMin(value);
@ -95,10 +123,9 @@ function RightContainer({
<Select
onChange={setGraphHandler}
value={selectedGraph}
disabled
style={{ width: '100%', marginBottom: 24 }}
>
{GraphTypes.map((item) => (
{graphTypes.map((item) => (
<Option key={item.name} value={item.name}>
{item.display}
</Option>

View File

@ -3,6 +3,7 @@ import { LockFilled, WarningOutlined } from '@ant-design/icons';
import { Button, Modal, Space, Tooltip, Typography } from 'antd';
import { SOMETHING_WENT_WRONG } from 'constants/api';
import { FeatureKeys } from 'constants/features';
import { QueryParams } from 'constants/query';
import { PANEL_TYPES } from 'constants/queryBuilder';
import ROUTES from 'constants/routes';
import { DashboardShortcuts } from 'constants/shortcuts/DashboardShortcuts';
@ -23,7 +24,7 @@ import {
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { generatePath, useLocation, useParams } from 'react-router-dom';
import { generatePath, useParams } from 'react-router-dom';
import { AppState } from 'store/reducers';
import { Dashboard, Widgets } from 'types/api/dashboard/getAll';
import { IField } from 'types/api/logs/fields';
@ -44,7 +45,7 @@ import {
RightContainerWrapper,
} from './styles';
import { NewWidgetProps } from './types';
import { getIsQueryModified } from './utils';
import { getIsQueryModified, handleQueryChange } from './utils';
function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
const {
@ -57,7 +58,12 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
const { registerShortcut, deregisterShortcut } = useKeyboardHotkeys();
const { currentQuery, stagedQuery } = useQueryBuilder();
const {
currentQuery,
stagedQuery,
redirectWithQueryBuilderData,
supersetQuery,
} = useQueryBuilder();
const isQueryModified = useMemo(
() => getIsQueryModified(currentQuery, stagedQuery),
@ -70,8 +76,6 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
const { widgets = [] } = selectedDashboard?.data || {};
const { search } = useLocation();
const query = useUrlQuery();
const { dashboardId } = useParams<DashboardWidgetPageParams>();
@ -297,9 +301,14 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
}, [dashboardId]);
const setGraphHandler = (type: PANEL_TYPES): void => {
const params = new URLSearchParams(search);
params.set('graphType', type);
const updatedQuery = handleQueryChange(type as any, supersetQuery);
setGraphType(type);
redirectWithQueryBuilderData(
updatedQuery,
{ [QueryParams.graphType]: type },
undefined,
false,
);
};
const onSaveDashboard = useCallback((): void => {

View File

@ -1,6 +1,11 @@
import { omitIdFromQuery } from 'components/ExplorerCard/utils';
import { isEqual } from 'lodash-es';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import {
initialQueryBuilderFormValuesMap,
PANEL_TYPES,
} from 'constants/queryBuilder';
import { isEqual, set, unset } from 'lodash-es';
import { IBuilderQuery, Query } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder';
export const getIsQueryModified = (
currentQuery: Query,
@ -13,3 +18,242 @@ export const getIsQueryModified = (
const omitIdFromCurrentQuery = omitIdFromQuery(currentQuery);
return !isEqual(omitIdFromStageQuery, omitIdFromCurrentQuery);
};
export type PartialPanelTypes = {
[PANEL_TYPES.BAR]: 'bar';
[PANEL_TYPES.LIST]: 'list';
[PANEL_TYPES.TABLE]: 'table';
[PANEL_TYPES.TIME_SERIES]: 'graph';
[PANEL_TYPES.VALUE]: 'value';
};
export const panelTypeDataSourceFormValuesMap: Record<
keyof PartialPanelTypes,
Record<DataSource, any>
> = {
[PANEL_TYPES.BAR]: {
[DataSource.LOGS]: {
builder: {
queryData: [
'filters',
'aggregateOperator',
'aggregateAttribute',
'groupBy',
'limit',
'having',
'orderBy',
'functions',
],
},
},
[DataSource.METRICS]: {
builder: {
queryData: [
'filters',
'aggregateOperator',
'aggregateAttribute',
'groupBy',
'limit',
'having',
'orderBy',
'functions',
'spaceAggregation',
],
},
},
[DataSource.TRACES]: {
builder: {
queryData: [
'filters',
'aggregateOperator',
'aggregateAttribute',
'groupBy',
'limit',
'having',
'orderBy',
],
},
},
},
[PANEL_TYPES.TIME_SERIES]: {
[DataSource.LOGS]: {
builder: {
queryData: [
'filters',
'aggregateOperator',
'aggregateAttribute',
'groupBy',
'limit',
'having',
'orderBy',
'functions',
],
},
},
[DataSource.METRICS]: {
builder: {
queryData: [
'filters',
'aggregateOperator',
'aggregateAttribute',
'groupBy',
'limit',
'having',
'orderBy',
'functions',
'spaceAggregation',
],
},
},
[DataSource.TRACES]: {
builder: {
queryData: [
'filters',
'aggregateOperator',
'aggregateAttribute',
'groupBy',
'limit',
'having',
'orderBy',
],
},
},
},
[PANEL_TYPES.TABLE]: {
[DataSource.LOGS]: {
builder: {
queryData: [
'filters',
'aggregateOperator',
'aggregateAttribute',
'groupBy',
'limit',
'having',
'orderBy',
'functions',
],
},
},
[DataSource.METRICS]: {
builder: {
queryData: [
'filters',
'aggregateOperator',
'aggregateAttribute',
'groupBy',
'limit',
'having',
'orderBy',
'functions',
'spaceAggregation',
],
},
},
[DataSource.TRACES]: {
builder: {
queryData: [
'filters',
'aggregateOperator',
'aggregateAttribute',
'groupBy',
'limit',
'having',
'orderBy',
],
},
},
},
[PANEL_TYPES.LIST]: {
[DataSource.LOGS]: {
builder: {
queryData: ['filters', 'limit', 'orderBy'],
},
},
[DataSource.METRICS]: {
builder: {
queryData: [],
},
},
[DataSource.TRACES]: {
builder: {
queryData: ['filters', 'limit', 'orderBy'],
},
},
},
[PANEL_TYPES.VALUE]: {
[DataSource.LOGS]: {
builder: {
queryData: [
'filters',
'aggregateOperator',
'aggregateAttribute',
'reduceTo',
'having',
'functions',
],
},
},
[DataSource.METRICS]: {
builder: {
queryData: [
'filters',
'aggregateOperator',
'aggregateAttribute',
'having',
'reduceTo',
'functions',
'spaceAggregation',
],
},
},
[DataSource.TRACES]: {
builder: {
queryData: [
'filters',
'aggregateOperator',
'aggregateAttribute',
'groupBy',
'limit',
'having',
'orderBy',
],
},
},
},
};
export function handleQueryChange(
newPanelType: keyof PartialPanelTypes,
supersetQuery: Query,
): Query {
return {
...supersetQuery,
builder: {
...supersetQuery.builder,
queryData: supersetQuery.builder.queryData.map((query, index) => {
const { dataSource } = query;
const tempQuery = { ...initialQueryBuilderFormValuesMap[dataSource] };
const fieldsToSelect =
panelTypeDataSourceFormValuesMap[newPanelType][dataSource].builder
.queryData;
fieldsToSelect.forEach((field: keyof IBuilderQuery) => {
set(tempQuery, field, supersetQuery.builder.queryData[index][field]);
});
if (newPanelType === PANEL_TYPES.LIST) {
set(tempQuery, 'aggregateOperator', 'noop');
set(tempQuery, 'offset', 0);
set(tempQuery, 'pageSize', 10);
} else if (tempQuery.aggregateOperator === 'noop') {
set(tempQuery, 'aggregateOperator', 'count');
unset(tempQuery, 'offset');
unset(tempQuery, 'pageSize');
}
return tempQuery;
}),
},
};
}

View File

@ -13,9 +13,10 @@ function PanelWrapper({
onToggleModelHandler,
onClickHandler,
onDragSelect,
selectedGraph,
}: PanelWrapperProps): JSX.Element {
const Component = PanelTypeVsPanelWrapper[
widget.panelTypes
selectedGraph || widget.panelTypes
] as FC<PanelWrapperProps>;
if (!Component) {
@ -33,6 +34,7 @@ function PanelWrapper({
onToggleModelHandler={onToggleModelHandler}
onClickHandler={onClickHandler}
onDragSelect={onDragSelect}
selectedGraph={selectedGraph}
/>
);
}

View File

@ -25,6 +25,7 @@ function UplotPanelWrapper({
onToggleModelHandler,
onClickHandler,
onDragSelect,
selectedGraph,
}: PanelWrapperProps): JSX.Element {
const { toScrollWidgetId, setToScrollWidgetId } = useDashboard();
const isDarkMode = useIsDarkMode();
@ -96,7 +97,7 @@ function UplotPanelWrapper({
softMin: widget.softMin === undefined ? null : widget.softMin,
graphsVisibilityStates: graphVisibility,
setGraphsVisibilityStates: setGraphVisibility,
panelType: widget.panelTypes,
panelType: selectedGraph || widget.panelTypes,
currentQuery,
}),
[
@ -115,6 +116,7 @@ function UplotPanelWrapper({
maxTimeScale,
graphVisibility,
setGraphVisibility,
selectedGraph,
currentQuery,
],
);

View File

@ -1,3 +1,4 @@
import { PANEL_TYPES } from 'constants/queryBuilder';
import { WidgetGraphComponentProps } from 'container/GridCardLayout/GridCard/types';
import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin';
import { Dispatch, SetStateAction } from 'react';
@ -19,4 +20,5 @@ export type PanelWrapperProps = {
setGraphVisibility?: Dispatch<SetStateAction<boolean[]>>;
onClickHandler?: OnClickPluginOpts['onClick'];
onDragSelect: (start: number, end: number) => void;
selectedGraph?: PANEL_TYPES;
};

View File

@ -16,6 +16,10 @@ import {
PANEL_TYPES,
} from 'constants/queryBuilder';
import ROUTES from 'constants/routes';
import {
panelTypeDataSourceFormValuesMap,
PartialPanelTypes,
} from 'container/NewWidget/utils';
import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam';
import { updateStepInterval } from 'hooks/queryBuilder/useStepInterval';
import useUrlQuery from 'hooks/useUrlQuery';
@ -23,7 +27,7 @@ import { createIdFromObjectFields } from 'lib/createIdFromObjectFields';
import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderItemName';
import { getOperatorsBySourceAndPanelType } from 'lib/newQueryBuilder/getOperatorsBySourceAndPanelType';
import { replaceIncorrectObjectFields } from 'lib/replaceIncorrectObjectFields';
import { merge } from 'lodash-es';
import { get, merge, set } from 'lodash-es';
import {
createContext,
PropsWithChildren,
@ -57,6 +61,8 @@ import { v4 as uuid } from 'uuid';
export const QueryBuilderContext = createContext<QueryBuilderContextType>({
currentQuery: initialQueriesMap.metrics,
supersetQuery: initialQueriesMap.metrics,
setSupersetQuery: () => {},
stagedQuery: initialQueriesMap.metrics,
initialDataSource: null,
panelType: PANEL_TYPES.TIME_SERIES,
@ -110,6 +116,7 @@ export function QueryBuilderProvider({
);
const [currentQuery, setCurrentQuery] = useState<QueryState>(queryState);
const [supersetQuery, setSupersetQuery] = useState<QueryState>(queryState);
const [stagedQuery, setStagedQuery] = useState<Query | null>(null);
const [queryType, setQueryType] = useState<EQueryType>(queryTypeParam);
@ -263,6 +270,21 @@ export function QueryBuilderProvider({
const filteredArray = currentArray.filter((_, i) => index !== i);
return {
...prevState,
builder: {
...prevState.builder,
[type]: filteredArray,
},
};
});
// eslint-disable-next-line sonarjs/no-identical-functions
setSupersetQuery((prevState) => {
const currentArray: (IBuilderQuery | IBuilderFormula)[] =
prevState.builder[type];
const filteredArray = currentArray.filter((_, i) => index !== i);
return {
...prevState,
builder: {
@ -284,6 +306,14 @@ export function QueryBuilderProvider({
[type]: targetArray.filter((_, i) => index !== i),
};
});
// eslint-disable-next-line sonarjs/no-identical-functions
setSupersetQuery((prevState) => {
const targetArray: (IPromQLQuery | IClickHouseQuery)[] = prevState[type];
return {
...prevState,
[type]: targetArray.filter((_, i) => index !== i),
};
});
},
[],
);
@ -366,6 +396,17 @@ export function QueryBuilderProvider({
const newQuery = createNewQueryTypeItem(prevState[type], type);
return {
...prevState,
[type]: [...prevState[type], newQuery],
};
});
// eslint-disable-next-line sonarjs/no-identical-functions
setSupersetQuery((prevState) => {
if (prevState[type].length >= MAX_QUERIES) return prevState;
const newQuery = createNewQueryTypeItem(prevState[type], type);
return {
...prevState,
[type]: [...prevState[type], newQuery],
@ -381,6 +422,20 @@ export function QueryBuilderProvider({
const newQuery = createNewBuilderQuery(prevState.builder.queryData);
return {
...prevState,
builder: {
...prevState.builder,
queryData: [...prevState.builder.queryData, newQuery],
},
};
});
// eslint-disable-next-line sonarjs/no-identical-functions
setSupersetQuery((prevState) => {
if (prevState.builder.queryData.length >= MAX_QUERIES) return prevState;
const newQuery = createNewBuilderQuery(prevState.builder.queryData);
return {
...prevState,
builder: {
@ -401,6 +456,23 @@ export function QueryBuilderProvider({
query,
);
return {
...prevState,
builder: {
...prevState.builder,
queryData: [...prevState.builder.queryData, clonedQuery],
},
};
});
// eslint-disable-next-line sonarjs/no-identical-functions
setSupersetQuery((prevState) => {
if (prevState.builder.queryData.length >= MAX_QUERIES) return prevState;
const clonedQuery = cloneNewBuilderQuery(
prevState.builder.queryData,
query,
);
return {
...prevState,
builder: {
@ -419,6 +491,20 @@ export function QueryBuilderProvider({
const newFormula = createNewBuilderFormula(prevState.builder.queryFormulas);
return {
...prevState,
builder: {
...prevState.builder,
queryFormulas: [...prevState.builder.queryFormulas, newFormula],
},
};
});
// eslint-disable-next-line sonarjs/no-identical-functions
setSupersetQuery((prevState) => {
if (prevState.builder.queryFormulas.length >= MAX_FORMULAS) return prevState;
const newFormula = createNewBuilderFormula(prevState.builder.queryFormulas);
return {
...prevState,
builder: {
@ -439,6 +525,31 @@ export function QueryBuilderProvider({
[],
);
const updateSuperSetQueryBuilderData = useCallback(
(arr: IBuilderQuery[], index: number, newQueryItem: IBuilderQuery) =>
arr.map((item, idx) => {
if (index === idx) {
if (!panelType) {
return newQueryItem;
}
const queryItem = item as IBuilderQuery;
const propsRequired =
panelTypeDataSourceFormValuesMap[panelType as keyof PartialPanelTypes][
queryItem.dataSource
].builder.queryData;
propsRequired.push('dataSource');
propsRequired.forEach((p: any) => {
set(queryItem, p, get(newQueryItem, p));
});
return queryItem;
}
return item;
}),
[panelType],
);
const handleSetQueryItemData = useCallback(
(
index: number,
@ -452,6 +563,19 @@ export function QueryBuilderProvider({
newQueryData,
);
return {
...prevState,
[type]: updatedQueryBuilderData,
};
});
// eslint-disable-next-line sonarjs/no-identical-functions
setSupersetQuery((prevState) => {
const updatedQueryBuilderData = updateQueryBuilderData(
prevState[type],
index,
newQueryData,
);
return {
...prevState,
[type]: updatedQueryBuilderData,
@ -470,6 +594,22 @@ export function QueryBuilderProvider({
newQueryData,
);
return {
...prevState,
builder: {
...prevState.builder,
queryData: updatedQueryBuilderData,
},
};
});
// eslint-disable-next-line sonarjs/no-identical-functions
setSupersetQuery((prevState) => {
const updatedQueryBuilderData = updateSuperSetQueryBuilderData(
prevState.builder.queryData,
index,
newQueryData,
);
return {
...prevState,
builder: {
@ -479,7 +619,7 @@ export function QueryBuilderProvider({
};
});
},
[updateQueryBuilderData],
[updateQueryBuilderData, updateSuperSetQueryBuilderData],
);
const handleSetFormulaData = useCallback(
(index: number, formulaData: IBuilderFormula): void => {
@ -490,6 +630,22 @@ export function QueryBuilderProvider({
formulaData,
);
return {
...prevState,
builder: {
...prevState.builder,
queryFormulas: updatedFormulasBuilderData,
},
};
});
// eslint-disable-next-line sonarjs/no-identical-functions
setSupersetQuery((prevState) => {
const updatedFormulasBuilderData = updateQueryBuilderData(
prevState.builder.queryFormulas,
index,
formulaData,
);
return {
...prevState,
builder: {
@ -518,6 +674,7 @@ export function QueryBuilderProvider({
query: Partial<Query>,
searchParams?: Record<string, unknown>,
redirectingUrl?: typeof ROUTES[keyof typeof ROUTES],
shallStringify?: boolean,
) => {
const queryType =
!query.queryType || !Object.values(EQueryType).includes(query.queryType)
@ -569,7 +726,12 @@ export function QueryBuilderProvider({
if (searchParams) {
Object.keys(searchParams).forEach((param) =>
urlQuery.set(param, JSON.stringify(searchParams[param])),
urlQuery.set(
param,
shallStringify
? JSON.stringify(searchParams[param])
: (searchParams[param] as string),
),
);
}
@ -657,6 +819,10 @@ export function QueryBuilderProvider({
...prevState,
unit,
}));
setSupersetQuery((prevState) => ({
...prevState,
unit,
}));
},
[setCurrentQuery],
);
@ -669,6 +835,14 @@ export function QueryBuilderProvider({
[currentQuery, queryType],
);
const superQuery: Query = useMemo(
() => ({
...supersetQuery,
queryType,
}),
[supersetQuery, queryType],
);
const isEnabledQuery = useMemo(() => !!stagedQuery && !!panelType, [
stagedQuery,
panelType,
@ -677,6 +851,8 @@ export function QueryBuilderProvider({
const contextValues: QueryBuilderContextType = useMemo(
() => ({
currentQuery: query,
supersetQuery: superQuery,
setSupersetQuery,
stagedQuery,
initialDataSource,
panelType,
@ -702,6 +878,7 @@ export function QueryBuilderProvider({
}),
[
query,
superQuery,
stagedQuery,
initialDataSource,
panelType,

View File

@ -1,6 +1,7 @@
import { PANEL_TYPES } from 'constants/queryBuilder';
import ROUTES from 'constants/routes';
import { Format } from 'container/NewWidget/RightContainer/types';
import { Dispatch, SetStateAction } from 'react';
import {
IBuilderFormula,
IBuilderQuery,
@ -187,6 +188,8 @@ export type QueryBuilderData = {
export type QueryBuilderContextType = {
currentQuery: Query;
stagedQuery: Query | null;
supersetQuery: Query;
setSupersetQuery: Dispatch<SetStateAction<QueryState>>;
initialDataSource: DataSource | null;
panelType: PANEL_TYPES | null;
isEnabledQuery: boolean;
@ -217,6 +220,7 @@ export type QueryBuilderContextType = {
query: Query,
searchParams?: Record<string, unknown>,
redirectToUrl?: typeof ROUTES[keyof typeof ROUTES],
shallStringify?: boolean,
) => void;
handleRunQuery: () => void;
resetQuery: (newCurrentQuery?: QueryState) => void;