mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-16 04:55:55 +08:00
Fix/query builder updating (#2962)
* feat: add dynamic table based on query * fix: group by repeating * fix: change view when groupBy exist in the list * feat: add list view for log explorer * fix: query builder updating * fix: table scroll * fix: filters for explorer page (#2959) --------- Co-authored-by: Prashant Shahi <prashant@signoz.io>
This commit is contained in:
parent
522bdf04ef
commit
bd18eee662
@ -70,7 +70,7 @@ function FormAlertRules({
|
|||||||
|
|
||||||
const sq = useMemo(() => mapQueryDataFromApi(initQuery), [initQuery]);
|
const sq = useMemo(() => mapQueryDataFromApi(initQuery), [initQuery]);
|
||||||
|
|
||||||
useShareBuilderUrl({ defaultValue: sq });
|
useShareBuilderUrl(sq);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setAlertDef(initialValue);
|
setAlertDef(initialValue);
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export { LogsExplorerChart } from './LogsExplorerChart';
|
|
@ -2,41 +2,33 @@ import Graph from 'components/Graph';
|
|||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||||
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
|
|
||||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
import { getExplorerChartData } from 'lib/explorer/getExplorerChartData';
|
import { getExplorerChartData } from 'lib/explorer/getExplorerChartData';
|
||||||
import { useMemo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
|
||||||
import { CardStyled } from './LogsExplorerChart.styled';
|
import { CardStyled } from './LogsExplorerChart.styled';
|
||||||
|
|
||||||
export function LogsExplorerChart(): JSX.Element {
|
function LogsExplorerChart(): JSX.Element {
|
||||||
const { stagedQuery } = useQueryBuilder();
|
const { stagedQuery, panelType, isEnabledQuery } = useQueryBuilder();
|
||||||
|
|
||||||
const { selectedTime } = useSelector<AppState, GlobalReducer>(
|
const { selectedTime } = useSelector<AppState, GlobalReducer>(
|
||||||
(state) => state.globalTime,
|
(state) => state.globalTime,
|
||||||
);
|
);
|
||||||
|
|
||||||
const panelTypeParam = useGetPanelTypesQueryParam(PANEL_TYPES.LIST);
|
|
||||||
|
|
||||||
const { data, isFetching } = useGetQueryRange(
|
const { data, isFetching } = useGetQueryRange(
|
||||||
{
|
{
|
||||||
query: stagedQuery || initialQueriesMap.metrics,
|
query: stagedQuery || initialQueriesMap.metrics,
|
||||||
graphType: panelTypeParam,
|
graphType: panelType || PANEL_TYPES.LIST,
|
||||||
globalSelectedInterval: selectedTime,
|
globalSelectedInterval: selectedTime,
|
||||||
selectedTime: 'GLOBAL_TIME',
|
selectedTime: 'GLOBAL_TIME',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
queryKey: [
|
queryKey: [REACT_QUERY_KEY.GET_QUERY_RANGE, selectedTime, stagedQuery],
|
||||||
REACT_QUERY_KEY.GET_QUERY_RANGE,
|
enabled: isEnabledQuery,
|
||||||
selectedTime,
|
|
||||||
stagedQuery,
|
|
||||||
panelTypeParam,
|
|
||||||
],
|
|
||||||
enabled: !!stagedQuery,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -64,3 +56,5 @@ export function LogsExplorerChart(): JSX.Element {
|
|||||||
</CardStyled>
|
</CardStyled>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default memo(LogsExplorerChart);
|
@ -0,0 +1,3 @@
|
|||||||
|
import { QueryDataV3 } from 'types/api/widgets/getQuery';
|
||||||
|
|
||||||
|
export type LogsExplorerListProps = { data: QueryDataV3[]; isLoading: boolean };
|
117
frontend/src/container/LogsExplorerList/index.tsx
Normal file
117
frontend/src/container/LogsExplorerList/index.tsx
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import { Card, Typography } from 'antd';
|
||||||
|
// components
|
||||||
|
import ListLogView from 'components/Logs/ListLogView';
|
||||||
|
import RawLogView from 'components/Logs/RawLogView';
|
||||||
|
import LogsTableView from 'components/Logs/TableView';
|
||||||
|
import Spinner from 'components/Spinner';
|
||||||
|
import { LogViewMode } from 'container/LogsTable';
|
||||||
|
import { Container, Heading } from 'container/LogsTable/styles';
|
||||||
|
import { contentStyle } from 'container/Trace/Search/config';
|
||||||
|
import useFontFaceObserver from 'hooks/useFontObserver';
|
||||||
|
import { memo, useCallback, useMemo, useState } from 'react';
|
||||||
|
import { Virtuoso } from 'react-virtuoso';
|
||||||
|
// interfaces
|
||||||
|
import { ILog } from 'types/api/logs/log';
|
||||||
|
|
||||||
|
import { LogsExplorerListProps } from './LogsExplorerList.interfaces';
|
||||||
|
|
||||||
|
function LogsExplorerList({
|
||||||
|
data,
|
||||||
|
isLoading,
|
||||||
|
}: LogsExplorerListProps): JSX.Element {
|
||||||
|
const [viewMode] = useState<LogViewMode>('raw');
|
||||||
|
const [linesPerRow] = useState<number>(20);
|
||||||
|
|
||||||
|
const logs: ILog[] = useMemo(() => {
|
||||||
|
if (data.length > 0 && data[0].list) {
|
||||||
|
const logs: ILog[] = data[0].list.map((item) => ({
|
||||||
|
timestamp: +item.timestamp,
|
||||||
|
...item.data,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return logs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
useFontFaceObserver(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
family: 'Fira Code',
|
||||||
|
weight: '300',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
viewMode === 'raw',
|
||||||
|
{
|
||||||
|
timeout: 5000,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// TODO: implement here linesPerRow, mode like in useSelectedLogView
|
||||||
|
|
||||||
|
const getItemContent = useCallback(
|
||||||
|
(index: number): JSX.Element => {
|
||||||
|
const log = logs[index];
|
||||||
|
|
||||||
|
if (viewMode === 'raw') {
|
||||||
|
return (
|
||||||
|
<RawLogView
|
||||||
|
key={log.id}
|
||||||
|
data={log}
|
||||||
|
linesPerRow={linesPerRow}
|
||||||
|
// TODO: write new onClickExpanded logic
|
||||||
|
onClickExpand={(): void => {}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <ListLogView key={log.id} logData={log} />;
|
||||||
|
},
|
||||||
|
[logs, linesPerRow, viewMode],
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderContent = useMemo(() => {
|
||||||
|
if (viewMode === 'table') {
|
||||||
|
return (
|
||||||
|
<LogsTableView
|
||||||
|
logs={logs}
|
||||||
|
// TODO: write new selected logic
|
||||||
|
fields={[]}
|
||||||
|
linesPerRow={linesPerRow}
|
||||||
|
// TODO: write new onClickExpanded logic
|
||||||
|
onClickExpand={(): void => {}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card bodyStyle={contentStyle}>
|
||||||
|
<Virtuoso
|
||||||
|
useWindowScroll
|
||||||
|
totalCount={logs.length}
|
||||||
|
itemContent={getItemContent}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}, [getItemContent, linesPerRow, logs, viewMode]);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <Spinner height={20} tip="Getting Logs" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
{viewMode !== 'table' && (
|
||||||
|
<Heading>
|
||||||
|
<Typography.Text>Event</Typography.Text>
|
||||||
|
</Heading>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{logs.length === 0 && <Typography>No logs lines found</Typography>}
|
||||||
|
|
||||||
|
{renderContent}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(LogsExplorerList);
|
@ -0,0 +1,6 @@
|
|||||||
|
import { QueryDataV3 } from 'types/api/widgets/getQuery';
|
||||||
|
|
||||||
|
export type LogsExplorerTableProps = {
|
||||||
|
data: QueryDataV3[];
|
||||||
|
isLoading: boolean;
|
||||||
|
};
|
@ -1,44 +0,0 @@
|
|||||||
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
|
||||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
|
||||||
import { QueryTable } from 'container/QueryTable';
|
|
||||||
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
|
|
||||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
import { AppState } from 'store/reducers';
|
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
|
||||||
|
|
||||||
export function LogsExplorerTable(): JSX.Element {
|
|
||||||
const { stagedQuery } = useQueryBuilder();
|
|
||||||
|
|
||||||
const { selectedTime } = useSelector<AppState, GlobalReducer>(
|
|
||||||
(state) => state.globalTime,
|
|
||||||
);
|
|
||||||
|
|
||||||
const panelTypeParam = useGetPanelTypesQueryParam(PANEL_TYPES.LIST);
|
|
||||||
|
|
||||||
const { data, isFetching } = useGetQueryRange(
|
|
||||||
{
|
|
||||||
query: stagedQuery || initialQueriesMap.metrics,
|
|
||||||
graphType: panelTypeParam,
|
|
||||||
globalSelectedInterval: selectedTime,
|
|
||||||
selectedTime: 'GLOBAL_TIME',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
queryKey: [
|
|
||||||
REACT_QUERY_KEY.GET_QUERY_RANGE,
|
|
||||||
selectedTime,
|
|
||||||
stagedQuery,
|
|
||||||
panelTypeParam,
|
|
||||||
],
|
|
||||||
enabled: !!stagedQuery,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<QueryTable
|
|
||||||
query={stagedQuery || initialQueriesMap.metrics}
|
|
||||||
queryTableData={data?.payload.data.newResult.data.result || []}
|
|
||||||
loading={isFetching}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
export { LogsExplorerTable } from './LogsExplorerTable';
|
|
23
frontend/src/container/LogsExplorerTable/index.tsx
Normal file
23
frontend/src/container/LogsExplorerTable/index.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { initialQueriesMap } from 'constants/queryBuilder';
|
||||||
|
import { QueryTable } from 'container/QueryTable';
|
||||||
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
|
import { memo } from 'react';
|
||||||
|
|
||||||
|
import { LogsExplorerTableProps } from './LogsExplorerTable.interfaces';
|
||||||
|
|
||||||
|
function LogsExplorerTable({
|
||||||
|
isLoading,
|
||||||
|
data,
|
||||||
|
}: LogsExplorerTableProps): JSX.Element {
|
||||||
|
const { stagedQuery } = useQueryBuilder();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<QueryTable
|
||||||
|
query={stagedQuery || initialQueriesMap.metrics}
|
||||||
|
queryTableData={data}
|
||||||
|
loading={isLoading}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(LogsExplorerTable);
|
@ -1,87 +0,0 @@
|
|||||||
import { TabsProps } from 'antd';
|
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
|
||||||
import { PANEL_TYPES_QUERY } from 'constants/queryBuilderQueryNames';
|
|
||||||
import { LogsExplorerTable } from 'container/LogsExplorerTable';
|
|
||||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
|
||||||
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
|
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
|
||||||
import useUrlQuery from 'hooks/useUrlQuery';
|
|
||||||
import { useCallback, useEffect, useMemo } from 'react';
|
|
||||||
import { useHistory, useLocation } from 'react-router-dom';
|
|
||||||
|
|
||||||
import { TabsStyled } from './LogsExplorerViews.styled';
|
|
||||||
|
|
||||||
export function LogsExplorerViews(): JSX.Element {
|
|
||||||
const location = useLocation();
|
|
||||||
const urlQuery = useUrlQuery();
|
|
||||||
const history = useHistory();
|
|
||||||
const { currentQuery } = useQueryBuilder();
|
|
||||||
|
|
||||||
const panelTypeParams = useGetPanelTypesQueryParam(PANEL_TYPES.LIST);
|
|
||||||
|
|
||||||
const isMultipleQueries = useMemo(
|
|
||||||
() =>
|
|
||||||
currentQuery.builder.queryData.length > 1 ||
|
|
||||||
currentQuery.builder.queryFormulas.length > 0,
|
|
||||||
[currentQuery],
|
|
||||||
);
|
|
||||||
|
|
||||||
const isGroupByExist = useMemo(() => {
|
|
||||||
const groupByCount: number = currentQuery.builder.queryData.reduce<number>(
|
|
||||||
(acc, query) => acc + query.groupBy.length,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
|
|
||||||
return groupByCount > 0;
|
|
||||||
}, [currentQuery]);
|
|
||||||
|
|
||||||
const tabsItems: TabsProps['items'] = useMemo(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
label: 'List View',
|
|
||||||
key: PANEL_TYPES.LIST,
|
|
||||||
disabled: isMultipleQueries || isGroupByExist,
|
|
||||||
},
|
|
||||||
{ label: 'TimeSeries', key: PANEL_TYPES.TIME_SERIES },
|
|
||||||
{ label: 'Table', key: PANEL_TYPES.TABLE, children: <LogsExplorerTable /> },
|
|
||||||
],
|
|
||||||
[isMultipleQueries, isGroupByExist],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleChangeView = useCallback(
|
|
||||||
(panelType: string) => {
|
|
||||||
urlQuery.set(PANEL_TYPES_QUERY, JSON.stringify(panelType) as GRAPH_TYPES);
|
|
||||||
const path = `${location.pathname}?${urlQuery}`;
|
|
||||||
|
|
||||||
history.push(path);
|
|
||||||
},
|
|
||||||
[history, location, urlQuery],
|
|
||||||
);
|
|
||||||
|
|
||||||
const currentTabKey = useMemo(
|
|
||||||
() =>
|
|
||||||
Object.values(PANEL_TYPES).includes(panelTypeParams)
|
|
||||||
? panelTypeParams
|
|
||||||
: PANEL_TYPES.LIST,
|
|
||||||
[panelTypeParams],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const shouldChangeView = isMultipleQueries || isGroupByExist;
|
|
||||||
|
|
||||||
if (panelTypeParams === 'list' && shouldChangeView) {
|
|
||||||
handleChangeView(PANEL_TYPES.TIME_SERIES);
|
|
||||||
}
|
|
||||||
}, [panelTypeParams, isMultipleQueries, isGroupByExist, handleChangeView]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<TabsStyled
|
|
||||||
items={tabsItems}
|
|
||||||
defaultActiveKey={currentTabKey}
|
|
||||||
activeKey={currentTabKey}
|
|
||||||
onChange={handleChangeView}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
export { LogsExplorerViews } from './LogsExplorerViews';
|
|
124
frontend/src/container/LogsExplorerViews/index.tsx
Normal file
124
frontend/src/container/LogsExplorerViews/index.tsx
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
import { TabsProps } from 'antd';
|
||||||
|
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
|
import { PANEL_TYPES_QUERY } from 'constants/queryBuilderQueryNames';
|
||||||
|
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||||
|
import LogsExplorerList from 'container/LogsExplorerList';
|
||||||
|
import LogsExplorerTable from 'container/LogsExplorerTable';
|
||||||
|
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||||
|
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||||
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
|
import { memo, useCallback, useEffect, useMemo } from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
|
import { DataSource } from 'types/common/queryBuilder';
|
||||||
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
|
||||||
|
import { TabsStyled } from './LogsExplorerViews.styled';
|
||||||
|
|
||||||
|
function LogsExplorerViews(): JSX.Element {
|
||||||
|
const {
|
||||||
|
currentQuery,
|
||||||
|
stagedQuery,
|
||||||
|
panelType,
|
||||||
|
isEnabledQuery,
|
||||||
|
updateAllQueriesOperators,
|
||||||
|
redirectWithQueryBuilderData,
|
||||||
|
} = useQueryBuilder();
|
||||||
|
|
||||||
|
const { selectedTime } = useSelector<AppState, GlobalReducer>(
|
||||||
|
(state) => state.globalTime,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data, isFetching } = useGetQueryRange(
|
||||||
|
{
|
||||||
|
query: stagedQuery || initialQueriesMap.metrics,
|
||||||
|
graphType: panelType || PANEL_TYPES.LIST,
|
||||||
|
globalSelectedInterval: selectedTime,
|
||||||
|
selectedTime: 'GLOBAL_TIME',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
queryKey: [REACT_QUERY_KEY.GET_QUERY_RANGE, selectedTime, stagedQuery],
|
||||||
|
enabled: isEnabledQuery,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const isMultipleQueries = useMemo(
|
||||||
|
() =>
|
||||||
|
currentQuery.builder.queryData.length > 1 ||
|
||||||
|
currentQuery.builder.queryFormulas.length > 0,
|
||||||
|
[currentQuery],
|
||||||
|
);
|
||||||
|
|
||||||
|
const isGroupByExist = useMemo(() => {
|
||||||
|
const groupByCount: number = currentQuery.builder.queryData.reduce<number>(
|
||||||
|
(acc, query) => acc + query.groupBy.length,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
|
return groupByCount > 0;
|
||||||
|
}, [currentQuery]);
|
||||||
|
|
||||||
|
const currentData = useMemo(
|
||||||
|
() => data?.payload.data.newResult.data.result || [],
|
||||||
|
[data],
|
||||||
|
);
|
||||||
|
|
||||||
|
const tabsItems: TabsProps['items'] = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
label: 'List View',
|
||||||
|
key: PANEL_TYPES.LIST,
|
||||||
|
disabled: isMultipleQueries || isGroupByExist,
|
||||||
|
children: <LogsExplorerList data={currentData} isLoading={isFetching} />,
|
||||||
|
},
|
||||||
|
{ label: 'TimeSeries', key: PANEL_TYPES.TIME_SERIES },
|
||||||
|
{
|
||||||
|
label: 'Table',
|
||||||
|
key: PANEL_TYPES.TABLE,
|
||||||
|
children: <LogsExplorerTable data={currentData} isLoading={isFetching} />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[isMultipleQueries, isGroupByExist, currentData, isFetching],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleChangeView = useCallback(
|
||||||
|
(newPanelType: string) => {
|
||||||
|
if (newPanelType === panelType) return;
|
||||||
|
|
||||||
|
const query = updateAllQueriesOperators(
|
||||||
|
currentQuery,
|
||||||
|
newPanelType as GRAPH_TYPES,
|
||||||
|
DataSource.LOGS,
|
||||||
|
);
|
||||||
|
|
||||||
|
redirectWithQueryBuilderData(query, { [PANEL_TYPES_QUERY]: newPanelType });
|
||||||
|
},
|
||||||
|
[
|
||||||
|
currentQuery,
|
||||||
|
panelType,
|
||||||
|
updateAllQueriesOperators,
|
||||||
|
redirectWithQueryBuilderData,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const shouldChangeView = isMultipleQueries || isGroupByExist;
|
||||||
|
|
||||||
|
if (panelType === 'list' && shouldChangeView) {
|
||||||
|
handleChangeView(PANEL_TYPES.TIME_SERIES);
|
||||||
|
}
|
||||||
|
}, [panelType, isMultipleQueries, isGroupByExist, handleChangeView]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TabsStyled
|
||||||
|
items={tabsItems}
|
||||||
|
defaultActiveKey={panelType || PANEL_TYPES.LIST}
|
||||||
|
activeKey={panelType || PANEL_TYPES.LIST}
|
||||||
|
onChange={handleChangeView}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(LogsExplorerViews);
|
@ -58,7 +58,7 @@ function QuerySection({
|
|||||||
|
|
||||||
const { query } = selectedWidget;
|
const { query } = selectedWidget;
|
||||||
|
|
||||||
useShareBuilderUrl({ defaultValue: query });
|
useShareBuilderUrl(query);
|
||||||
|
|
||||||
const handleStageQuery = useCallback(
|
const handleStageQuery = useCallback(
|
||||||
(updatedQuery: Query): void => {
|
(updatedQuery: Query): void => {
|
||||||
|
@ -15,26 +15,36 @@ import { ActionsWrapperStyled } from './QueryBuilder.styled';
|
|||||||
|
|
||||||
export const QueryBuilder = memo(function QueryBuilder({
|
export const QueryBuilder = memo(function QueryBuilder({
|
||||||
config,
|
config,
|
||||||
panelType,
|
panelType: newPanelType,
|
||||||
actions,
|
actions,
|
||||||
}: QueryBuilderProps): JSX.Element {
|
}: QueryBuilderProps): JSX.Element {
|
||||||
const {
|
const {
|
||||||
currentQuery,
|
currentQuery,
|
||||||
setupInitialDataSource,
|
|
||||||
addNewBuilderQuery,
|
addNewBuilderQuery,
|
||||||
addNewFormula,
|
addNewFormula,
|
||||||
handleSetPanelType,
|
handleSetConfig,
|
||||||
|
panelType,
|
||||||
|
initialDataSource,
|
||||||
} = useQueryBuilder();
|
} = useQueryBuilder();
|
||||||
|
|
||||||
useEffect(() => {
|
const currentDataSource = useMemo(
|
||||||
if (config && config.queryVariant === 'static') {
|
() =>
|
||||||
setupInitialDataSource(config.initialDataSource);
|
(config && config.queryVariant === 'static' && config.initialDataSource) ||
|
||||||
}
|
null,
|
||||||
}, [config, setupInitialDataSource]);
|
[config],
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleSetPanelType(panelType);
|
if (currentDataSource !== initialDataSource || newPanelType !== panelType) {
|
||||||
}, [handleSetPanelType, panelType]);
|
handleSetConfig(newPanelType, currentDataSource);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
handleSetConfig,
|
||||||
|
panelType,
|
||||||
|
initialDataSource,
|
||||||
|
currentDataSource,
|
||||||
|
newPanelType,
|
||||||
|
]);
|
||||||
|
|
||||||
const isDisabledQueryButton = useMemo(
|
const isDisabledQueryButton = useMemo(
|
||||||
() => currentQuery.builder.queryData.length >= MAX_QUERIES,
|
() => currentQuery.builder.queryData.length >= MAX_QUERIES,
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
import { initialQueriesMap } from 'constants/queryBuilder';
|
||||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||||
import useUrlQuery from 'hooks/useUrlQuery';
|
|
||||||
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
||||||
import { UseQueryOptions, UseQueryResult } from 'react-query';
|
import { UseQueryOptions, UseQueryResult } from 'react-query';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
@ -10,6 +9,7 @@ import { SuccessResponse } from 'types/api';
|
|||||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
|
||||||
|
import { useGetCompositeQueryParam } from './useGetCompositeQueryParam';
|
||||||
import { useGetQueryRange } from './useGetQueryRange';
|
import { useGetQueryRange } from './useGetQueryRange';
|
||||||
|
|
||||||
export const useGetWidgetQueryRange = (
|
export const useGetWidgetQueryRange = (
|
||||||
@ -19,21 +19,19 @@ export const useGetWidgetQueryRange = (
|
|||||||
}: Pick<GetQueryResultsProps, 'graphType' | 'selectedTime'>,
|
}: Pick<GetQueryResultsProps, 'graphType' | 'selectedTime'>,
|
||||||
options?: UseQueryOptions<SuccessResponse<MetricRangePayloadProps>, Error>,
|
options?: UseQueryOptions<SuccessResponse<MetricRangePayloadProps>, Error>,
|
||||||
): UseQueryResult<SuccessResponse<MetricRangePayloadProps>, Error> => {
|
): UseQueryResult<SuccessResponse<MetricRangePayloadProps>, Error> => {
|
||||||
const urlQuery = useUrlQuery();
|
|
||||||
|
|
||||||
const { selectedTime: globalSelectedInterval } = useSelector<
|
const { selectedTime: globalSelectedInterval } = useSelector<
|
||||||
AppState,
|
AppState,
|
||||||
GlobalReducer
|
GlobalReducer
|
||||||
>((state) => state.globalTime);
|
>((state) => state.globalTime);
|
||||||
|
|
||||||
const compositeQuery = urlQuery.get(COMPOSITE_QUERY);
|
const compositeQuery = useGetCompositeQueryParam();
|
||||||
|
|
||||||
return useGetQueryRange(
|
return useGetQueryRange(
|
||||||
{
|
{
|
||||||
graphType,
|
graphType,
|
||||||
selectedTime,
|
selectedTime,
|
||||||
globalSelectedInterval,
|
globalSelectedInterval,
|
||||||
query: JSON.parse(compositeQuery || '{}'),
|
query: compositeQuery || initialQueriesMap.metrics,
|
||||||
variables: getDashboardVariables(),
|
variables: getDashboardVariables(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@ import {
|
|||||||
initialAutocompleteData,
|
initialAutocompleteData,
|
||||||
initialQueryBuilderFormValuesMap,
|
initialQueryBuilderFormValuesMap,
|
||||||
mapOfFilters,
|
mapOfFilters,
|
||||||
|
PANEL_TYPES,
|
||||||
} from 'constants/queryBuilder';
|
} from 'constants/queryBuilder';
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
import { getOperatorsBySourceAndPanelType } from 'lib/newQueryBuilder/getOperatorsBySourceAndPanelType';
|
import { getOperatorsBySourceAndPanelType } from 'lib/newQueryBuilder/getOperatorsBySourceAndPanelType';
|
||||||
@ -78,7 +79,7 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => {
|
|||||||
(nextSource: DataSource): void => {
|
(nextSource: DataSource): void => {
|
||||||
const newOperators = getOperatorsBySourceAndPanelType({
|
const newOperators = getOperatorsBySourceAndPanelType({
|
||||||
dataSource: nextSource,
|
dataSource: nextSource,
|
||||||
panelType,
|
panelType: panelType || PANEL_TYPES.TIME_SERIES,
|
||||||
});
|
});
|
||||||
|
|
||||||
const entries = Object.entries(
|
const entries = Object.entries(
|
||||||
@ -126,28 +127,13 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => {
|
|||||||
|
|
||||||
const initialOperators = getOperatorsBySourceAndPanelType({
|
const initialOperators = getOperatorsBySourceAndPanelType({
|
||||||
dataSource,
|
dataSource,
|
||||||
panelType,
|
panelType: panelType || PANEL_TYPES.TIME_SERIES,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (JSON.stringify(operators) === JSON.stringify(initialOperators)) return;
|
if (JSON.stringify(operators) === JSON.stringify(initialOperators)) return;
|
||||||
|
|
||||||
setOperators(initialOperators);
|
setOperators(initialOperators);
|
||||||
|
}, [dataSource, initialDataSource, panelType, operators]);
|
||||||
const isCurrentOperatorAvailableInList = initialOperators
|
|
||||||
.map((operator) => operator.value)
|
|
||||||
.includes(aggregateOperator);
|
|
||||||
|
|
||||||
if (!isCurrentOperatorAvailableInList) {
|
|
||||||
handleChangeOperator(initialOperators[0].value);
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
dataSource,
|
|
||||||
initialDataSource,
|
|
||||||
panelType,
|
|
||||||
operators,
|
|
||||||
aggregateOperator,
|
|
||||||
handleChangeOperator,
|
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const additionalFilters = getNewListOfAdditionalFilters(dataSource);
|
const additionalFilters = getNewListOfAdditionalFilters(dataSource);
|
||||||
|
@ -5,11 +5,9 @@ import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
|||||||
import { useGetCompositeQueryParam } from './useGetCompositeQueryParam';
|
import { useGetCompositeQueryParam } from './useGetCompositeQueryParam';
|
||||||
import { useQueryBuilder } from './useQueryBuilder';
|
import { useQueryBuilder } from './useQueryBuilder';
|
||||||
|
|
||||||
type UseShareBuilderUrlParams = { defaultValue: Query };
|
export type UseShareBuilderUrlParams = { defaultValue: Query };
|
||||||
|
|
||||||
export const useShareBuilderUrl = ({
|
export const useShareBuilderUrl = (defaultQuery: Query): void => {
|
||||||
defaultValue,
|
|
||||||
}: UseShareBuilderUrlParams): void => {
|
|
||||||
const { redirectWithQueryBuilderData, resetStagedQuery } = useQueryBuilder();
|
const { redirectWithQueryBuilderData, resetStagedQuery } = useQueryBuilder();
|
||||||
const urlQuery = useUrlQuery();
|
const urlQuery = useUrlQuery();
|
||||||
|
|
||||||
@ -17,9 +15,9 @@ export const useShareBuilderUrl = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!compositeQuery) {
|
if (!compositeQuery) {
|
||||||
redirectWithQueryBuilderData(defaultValue);
|
redirectWithQueryBuilderData(defaultQuery);
|
||||||
}
|
}
|
||||||
}, [defaultValue, urlQuery, redirectWithQueryBuilderData, compositeQuery]);
|
}, [defaultQuery, urlQuery, redirectWithQueryBuilderData, compositeQuery]);
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => (): void => {
|
() => (): void => {
|
||||||
|
@ -1,21 +1,32 @@
|
|||||||
import { Button, Col, Row } from 'antd';
|
import { Button, Col, Row } from 'antd';
|
||||||
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import { LogsExplorerChart } from 'container/LogsExplorerChart';
|
import LogsExplorerChart from 'container/LogsExplorerChart';
|
||||||
import { LogsExplorerViews } from 'container/LogsExplorerViews';
|
import LogsExplorerViews from 'container/LogsExplorerViews';
|
||||||
import { QueryBuilder } from 'container/QueryBuilder';
|
import { QueryBuilder } from 'container/QueryBuilder';
|
||||||
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
|
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||||
|
import { useMemo } from 'react';
|
||||||
import { DataSource } from 'types/common/queryBuilder';
|
import { DataSource } from 'types/common/queryBuilder';
|
||||||
|
|
||||||
// ** Styles
|
// ** Styles
|
||||||
import { ButtonWrapperStyled, WrapperStyled } from './styles';
|
import { ButtonWrapperStyled, WrapperStyled } from './styles';
|
||||||
|
|
||||||
function LogsExporer(): JSX.Element {
|
function LogsExporer(): JSX.Element {
|
||||||
const { handleRunQuery } = useQueryBuilder();
|
const { handleRunQuery, updateAllQueriesOperators } = useQueryBuilder();
|
||||||
const panelTypes = useGetPanelTypesQueryParam(PANEL_TYPES.LIST);
|
const panelTypes = useGetPanelTypesQueryParam(PANEL_TYPES.LIST);
|
||||||
|
|
||||||
useShareBuilderUrl({ defaultValue: initialQueriesMap.logs });
|
const defaultValue = useMemo(
|
||||||
|
() =>
|
||||||
|
updateAllQueriesOperators(
|
||||||
|
initialQueriesMap.logs,
|
||||||
|
PANEL_TYPES.LIST,
|
||||||
|
DataSource.LOGS,
|
||||||
|
),
|
||||||
|
[updateAllQueriesOperators],
|
||||||
|
);
|
||||||
|
|
||||||
|
useShareBuilderUrl(defaultValue);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WrapperStyled>
|
<WrapperStyled>
|
||||||
|
@ -37,7 +37,7 @@ function TracesExplorer(): JSX.Element {
|
|||||||
[redirectWithCurrentTab],
|
[redirectWithCurrentTab],
|
||||||
);
|
);
|
||||||
|
|
||||||
useShareBuilderUrl({ defaultValue: initialQueriesMap.traces });
|
useShareBuilderUrl(initialQueriesMap.traces);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentUrlTab) return;
|
if (currentUrlTab) return;
|
||||||
|
@ -52,11 +52,11 @@ export const QueryBuilderContext = createContext<QueryBuilderContextType>({
|
|||||||
stagedQuery: initialQueriesMap.metrics,
|
stagedQuery: initialQueriesMap.metrics,
|
||||||
initialDataSource: null,
|
initialDataSource: null,
|
||||||
panelType: PANEL_TYPES.TIME_SERIES,
|
panelType: PANEL_TYPES.TIME_SERIES,
|
||||||
|
isEnabledQuery: false,
|
||||||
handleSetQueryData: () => {},
|
handleSetQueryData: () => {},
|
||||||
handleSetFormulaData: () => {},
|
handleSetFormulaData: () => {},
|
||||||
handleSetQueryItemData: () => {},
|
handleSetQueryItemData: () => {},
|
||||||
handleSetPanelType: () => {},
|
handleSetConfig: () => {},
|
||||||
setupInitialDataSource: () => {},
|
|
||||||
removeQueryBuilderEntityByIndex: () => {},
|
removeQueryBuilderEntityByIndex: () => {},
|
||||||
removeQueryTypeItemByIndex: () => {},
|
removeQueryTypeItemByIndex: () => {},
|
||||||
addNewBuilderQuery: () => {},
|
addNewBuilderQuery: () => {},
|
||||||
@ -65,6 +65,7 @@ export const QueryBuilderContext = createContext<QueryBuilderContextType>({
|
|||||||
redirectWithQueryBuilderData: () => {},
|
redirectWithQueryBuilderData: () => {},
|
||||||
handleRunQuery: () => {},
|
handleRunQuery: () => {},
|
||||||
resetStagedQuery: () => {},
|
resetStagedQuery: () => {},
|
||||||
|
updateAllQueriesOperators: () => initialQueriesMap.metrics,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function QueryBuilderProvider({
|
export function QueryBuilderProvider({
|
||||||
@ -75,75 +76,120 @@ export function QueryBuilderProvider({
|
|||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
const compositeQueryParam = useGetCompositeQueryParam();
|
const compositeQueryParam = useGetCompositeQueryParam();
|
||||||
|
const { queryType: queryTypeParam, ...queryState } =
|
||||||
|
compositeQueryParam || initialQueriesMap.metrics;
|
||||||
|
|
||||||
const [initialDataSource, setInitialDataSource] = useState<DataSource | null>(
|
const [initialDataSource, setInitialDataSource] = useState<DataSource | null>(
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [panelType, setPanelType] = useState<GRAPH_TYPES>(
|
const [panelType, setPanelType] = useState<GRAPH_TYPES | null>(null);
|
||||||
PANEL_TYPES.TIME_SERIES,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [currentQuery, setCurrentQuery] = useState<QueryState>(
|
const [currentQuery, setCurrentQuery] = useState<QueryState>(
|
||||||
initialQueryState,
|
queryState || initialQueryState,
|
||||||
);
|
);
|
||||||
const [stagedQuery, setStagedQuery] = useState<Query | null>(null);
|
const [stagedQuery, setStagedQuery] = useState<Query | null>(null);
|
||||||
|
|
||||||
const [queryType, setQueryType] = useState<EQueryType>(
|
const [queryType, setQueryType] = useState<EQueryType>(queryTypeParam);
|
||||||
EQueryType.QUERY_BUILDER,
|
|
||||||
|
const getElementWithActualOperator = useCallback(
|
||||||
|
(
|
||||||
|
queryData: IBuilderQuery,
|
||||||
|
dataSource: DataSource,
|
||||||
|
currentPanelType: GRAPH_TYPES,
|
||||||
|
): IBuilderQuery => {
|
||||||
|
const initialOperators = getOperatorsBySourceAndPanelType({
|
||||||
|
dataSource,
|
||||||
|
panelType: currentPanelType,
|
||||||
|
});
|
||||||
|
|
||||||
|
const isCurrentOperatorAvailableInList = initialOperators
|
||||||
|
.map((operator) => operator.value)
|
||||||
|
.includes(queryData.aggregateOperator);
|
||||||
|
|
||||||
|
if (!isCurrentOperatorAvailableInList) {
|
||||||
|
return { ...queryData, aggregateOperator: initialOperators[0].value };
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryData;
|
||||||
|
},
|
||||||
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const initQueryBuilderData = useCallback(
|
const prepareQueryBuilderData = useCallback(
|
||||||
(query: Query): void => {
|
(query: Query): Query => {
|
||||||
const { queryType: newQueryType, ...queryState } = query;
|
|
||||||
|
|
||||||
const builder: QueryBuilderData = {
|
const builder: QueryBuilderData = {
|
||||||
queryData: queryState.builder.queryData.map((item) => ({
|
queryData: query.builder.queryData.map((item) => ({
|
||||||
...initialQueryBuilderFormValuesMap[
|
...initialQueryBuilderFormValuesMap[
|
||||||
initialDataSource || DataSource.METRICS
|
initialDataSource || DataSource.METRICS
|
||||||
],
|
],
|
||||||
...item,
|
...item,
|
||||||
})),
|
})),
|
||||||
queryFormulas: queryState.builder.queryFormulas.map((item) => ({
|
queryFormulas: query.builder.queryFormulas.map((item) => ({
|
||||||
...initialFormulaBuilderFormValues,
|
...initialFormulaBuilderFormValues,
|
||||||
...item,
|
...item,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
const promql: IPromQLQuery[] = queryState.promql.map((item) => ({
|
const setupedQueryData = builder.queryData.map((item) => {
|
||||||
|
const currentElement: IBuilderQuery = {
|
||||||
|
...item,
|
||||||
|
groupBy: item.groupBy.map(({ id: _, ...item }) => ({
|
||||||
|
...item,
|
||||||
|
id: createIdFromObjectFields(item, baseAutoCompleteIdKeysOrder),
|
||||||
|
})),
|
||||||
|
aggregateAttribute: {
|
||||||
|
...item.aggregateAttribute,
|
||||||
|
id: createIdFromObjectFields(
|
||||||
|
item.aggregateAttribute,
|
||||||
|
baseAutoCompleteIdKeysOrder,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return currentElement;
|
||||||
|
});
|
||||||
|
|
||||||
|
const promql: IPromQLQuery[] = query.promql.map((item) => ({
|
||||||
...initialQueryPromQLData,
|
...initialQueryPromQLData,
|
||||||
...item,
|
...item,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const clickHouse: IClickHouseQuery[] = queryState.clickhouse_sql.map(
|
const clickHouse: IClickHouseQuery[] = query.clickhouse_sql.map((item) => ({
|
||||||
(item) => ({
|
...initialClickHouseData,
|
||||||
...initialClickHouseData,
|
...item,
|
||||||
...item,
|
}));
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
const type = newQueryType || EQueryType.QUERY_BUILDER;
|
|
||||||
|
|
||||||
const newQueryState: QueryState = {
|
const newQueryState: QueryState = {
|
||||||
clickhouse_sql: clickHouse,
|
clickhouse_sql: clickHouse,
|
||||||
promql,
|
promql,
|
||||||
builder: {
|
builder: {
|
||||||
...builder,
|
...builder,
|
||||||
queryData: builder.queryData.map((q) => ({
|
queryData: setupedQueryData,
|
||||||
...q,
|
|
||||||
groupBy: q.groupBy.map(({ id: _, ...item }) => ({
|
|
||||||
...item,
|
|
||||||
id: createIdFromObjectFields(item, baseAutoCompleteIdKeysOrder),
|
|
||||||
})),
|
|
||||||
aggregateAttribute: {
|
|
||||||
...q.aggregateAttribute,
|
|
||||||
id: createIdFromObjectFields(
|
|
||||||
q.aggregateAttribute,
|
|
||||||
baseAutoCompleteIdKeysOrder,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
},
|
},
|
||||||
|
id: query.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextQuery: Query = {
|
||||||
|
...newQueryState,
|
||||||
|
queryType: query.queryType,
|
||||||
|
};
|
||||||
|
|
||||||
|
return nextQuery;
|
||||||
|
},
|
||||||
|
[initialDataSource],
|
||||||
|
);
|
||||||
|
|
||||||
|
const initQueryBuilderData = useCallback(
|
||||||
|
(query: Query): void => {
|
||||||
|
const { queryType: newQueryType, ...queryState } = prepareQueryBuilderData(
|
||||||
|
query,
|
||||||
|
);
|
||||||
|
|
||||||
|
const type = newQueryType || EQueryType.QUERY_BUILDER;
|
||||||
|
|
||||||
|
const newQueryState: QueryState = {
|
||||||
|
...queryState,
|
||||||
id: queryState.id,
|
id: queryState.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -153,7 +199,19 @@ export function QueryBuilderProvider({
|
|||||||
setCurrentQuery(newQueryState);
|
setCurrentQuery(newQueryState);
|
||||||
setQueryType(type);
|
setQueryType(type);
|
||||||
},
|
},
|
||||||
[initialDataSource],
|
[prepareQueryBuilderData],
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateAllQueriesOperators = useCallback(
|
||||||
|
(query: Query, panelType: GRAPH_TYPES, dataSource: DataSource): Query => {
|
||||||
|
const queryData = query.builder.queryData.map((item) =>
|
||||||
|
getElementWithActualOperator(item, dataSource, panelType),
|
||||||
|
);
|
||||||
|
|
||||||
|
return { ...query, builder: { ...query.builder, queryData } };
|
||||||
|
},
|
||||||
|
|
||||||
|
[getElementWithActualOperator],
|
||||||
);
|
);
|
||||||
|
|
||||||
const removeQueryBuilderEntityByIndex = useCallback(
|
const removeQueryBuilderEntityByIndex = useCallback(
|
||||||
@ -161,11 +219,14 @@ export function QueryBuilderProvider({
|
|||||||
setCurrentQuery((prevState) => {
|
setCurrentQuery((prevState) => {
|
||||||
const currentArray: (IBuilderQuery | IBuilderFormula)[] =
|
const currentArray: (IBuilderQuery | IBuilderFormula)[] =
|
||||||
prevState.builder[type];
|
prevState.builder[type];
|
||||||
|
|
||||||
|
const filteredArray = currentArray.filter((_, i) => index !== i);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...prevState,
|
...prevState,
|
||||||
builder: {
|
builder: {
|
||||||
...prevState.builder,
|
...prevState.builder,
|
||||||
[type]: currentArray.filter((_, i) => index !== i),
|
[type]: filteredArray,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -199,20 +260,11 @@ export function QueryBuilderProvider({
|
|||||||
existNames,
|
existNames,
|
||||||
sourceNames: alphabet,
|
sourceNames: alphabet,
|
||||||
}),
|
}),
|
||||||
...(initialDataSource
|
|
||||||
? {
|
|
||||||
dataSource: initialDataSource,
|
|
||||||
aggregateOperator: getOperatorsBySourceAndPanelType({
|
|
||||||
dataSource: initialDataSource,
|
|
||||||
panelType,
|
|
||||||
})[0].value,
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return newQuery;
|
return newQuery;
|
||||||
},
|
},
|
||||||
[initialDataSource, panelType],
|
[initialDataSource],
|
||||||
);
|
);
|
||||||
|
|
||||||
const createNewBuilderFormula = useCallback((formulas: IBuilderFormula[]) => {
|
const createNewBuilderFormula = useCallback((formulas: IBuilderFormula[]) => {
|
||||||
@ -297,12 +349,6 @@ export function QueryBuilderProvider({
|
|||||||
});
|
});
|
||||||
}, [createNewBuilderFormula]);
|
}, [createNewBuilderFormula]);
|
||||||
|
|
||||||
const setupInitialDataSource = useCallback(
|
|
||||||
(newInitialDataSource: DataSource | null) =>
|
|
||||||
setInitialDataSource(newInitialDataSource),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateQueryBuilderData: <T>(
|
const updateQueryBuilderData: <T>(
|
||||||
arr: T[],
|
arr: T[],
|
||||||
index: number,
|
index: number,
|
||||||
@ -377,29 +423,33 @@ export function QueryBuilderProvider({
|
|||||||
[updateQueryBuilderData],
|
[updateQueryBuilderData],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSetPanelType = useCallback((newPanelType: GRAPH_TYPES) => {
|
|
||||||
setPanelType(newPanelType);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const redirectWithQueryBuilderData = useCallback(
|
const redirectWithQueryBuilderData = useCallback(
|
||||||
(query: Partial<Query>, searchParams?: Record<string, unknown>) => {
|
(query: Partial<Query>, searchParams?: Record<string, unknown>) => {
|
||||||
|
const queryType =
|
||||||
|
!query.queryType || !Object.values(EQueryType).includes(query.queryType)
|
||||||
|
? EQueryType.QUERY_BUILDER
|
||||||
|
: query.queryType;
|
||||||
|
|
||||||
|
const builder =
|
||||||
|
!query.builder || query.builder.queryData.length === 0
|
||||||
|
? initialQueryState.builder
|
||||||
|
: query.builder;
|
||||||
|
|
||||||
|
const promql =
|
||||||
|
!query.promql || query.promql.length === 0
|
||||||
|
? initialQueryState.promql
|
||||||
|
: query.promql;
|
||||||
|
|
||||||
|
const clickhouseSql =
|
||||||
|
!query.clickhouse_sql || query.clickhouse_sql.length === 0
|
||||||
|
? initialQueryState.clickhouse_sql
|
||||||
|
: query.clickhouse_sql;
|
||||||
|
|
||||||
const currentGeneratedQuery: Query = {
|
const currentGeneratedQuery: Query = {
|
||||||
queryType:
|
queryType,
|
||||||
!query.queryType || !Object.values(EQueryType).includes(query.queryType)
|
builder,
|
||||||
? EQueryType.QUERY_BUILDER
|
promql,
|
||||||
: query.queryType,
|
clickhouse_sql: clickhouseSql,
|
||||||
builder:
|
|
||||||
!query.builder || query.builder.queryData.length === 0
|
|
||||||
? initialQueryState.builder
|
|
||||||
: query.builder,
|
|
||||||
promql:
|
|
||||||
!query.promql || query.promql.length === 0
|
|
||||||
? initialQueryState.promql
|
|
||||||
: query.promql,
|
|
||||||
clickhouse_sql:
|
|
||||||
!query.clickhouse_sql || query.clickhouse_sql.length === 0
|
|
||||||
? initialQueryState.clickhouse_sql
|
|
||||||
: query.clickhouse_sql,
|
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -418,6 +468,14 @@ export function QueryBuilderProvider({
|
|||||||
[history, location, urlQuery],
|
[history, location, urlQuery],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleSetConfig = useCallback(
|
||||||
|
(newPanelType: GRAPH_TYPES, dataSource: DataSource | null) => {
|
||||||
|
setPanelType(newPanelType);
|
||||||
|
setInitialDataSource(dataSource);
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
const handleRunQuery = useCallback(() => {
|
const handleRunQuery = useCallback(() => {
|
||||||
redirectWithQueryBuilderData({ ...currentQuery, queryType });
|
redirectWithQueryBuilderData({ ...currentQuery, queryType });
|
||||||
}, [redirectWithQueryBuilderData, currentQuery, queryType]);
|
}, [redirectWithQueryBuilderData, currentQuery, queryType]);
|
||||||
@ -458,17 +516,22 @@ export function QueryBuilderProvider({
|
|||||||
[currentQuery, queryType],
|
[currentQuery, queryType],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isEnabledQuery = useMemo(() => !!stagedQuery && !!panelType, [
|
||||||
|
stagedQuery,
|
||||||
|
panelType,
|
||||||
|
]);
|
||||||
|
|
||||||
const contextValues: QueryBuilderContextType = useMemo(
|
const contextValues: QueryBuilderContextType = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
currentQuery: query,
|
currentQuery: query,
|
||||||
stagedQuery,
|
stagedQuery,
|
||||||
initialDataSource,
|
initialDataSource,
|
||||||
panelType,
|
panelType,
|
||||||
|
isEnabledQuery,
|
||||||
handleSetQueryData,
|
handleSetQueryData,
|
||||||
handleSetFormulaData,
|
handleSetFormulaData,
|
||||||
handleSetQueryItemData,
|
handleSetQueryItemData,
|
||||||
handleSetPanelType,
|
handleSetConfig,
|
||||||
setupInitialDataSource,
|
|
||||||
removeQueryBuilderEntityByIndex,
|
removeQueryBuilderEntityByIndex,
|
||||||
removeQueryTypeItemByIndex,
|
removeQueryTypeItemByIndex,
|
||||||
addNewBuilderQuery,
|
addNewBuilderQuery,
|
||||||
@ -477,17 +540,18 @@ export function QueryBuilderProvider({
|
|||||||
redirectWithQueryBuilderData,
|
redirectWithQueryBuilderData,
|
||||||
handleRunQuery,
|
handleRunQuery,
|
||||||
resetStagedQuery,
|
resetStagedQuery,
|
||||||
|
updateAllQueriesOperators,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
query,
|
query,
|
||||||
stagedQuery,
|
stagedQuery,
|
||||||
initialDataSource,
|
initialDataSource,
|
||||||
panelType,
|
panelType,
|
||||||
|
isEnabledQuery,
|
||||||
handleSetQueryData,
|
handleSetQueryData,
|
||||||
handleSetFormulaData,
|
handleSetFormulaData,
|
||||||
handleSetQueryItemData,
|
handleSetQueryItemData,
|
||||||
handleSetPanelType,
|
handleSetConfig,
|
||||||
setupInitialDataSource,
|
|
||||||
removeQueryBuilderEntityByIndex,
|
removeQueryBuilderEntityByIndex,
|
||||||
removeQueryTypeItemByIndex,
|
removeQueryTypeItemByIndex,
|
||||||
addNewBuilderQuery,
|
addNewBuilderQuery,
|
||||||
@ -496,6 +560,7 @@ export function QueryBuilderProvider({
|
|||||||
redirectWithQueryBuilderData,
|
redirectWithQueryBuilderData,
|
||||||
handleRunQuery,
|
handleRunQuery,
|
||||||
resetStagedQuery,
|
resetStagedQuery,
|
||||||
|
updateAllQueriesOperators,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
|
import { ILog } from '../logs/log';
|
||||||
|
|
||||||
export interface PayloadProps {
|
export interface PayloadProps {
|
||||||
status: 'success' | 'error';
|
status: 'success' | 'error';
|
||||||
result: QueryData[];
|
result: QueryData[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ListItem = { timestamp: string; data: Omit<ILog, 'timestamp'> };
|
||||||
|
|
||||||
export interface QueryData {
|
export interface QueryData {
|
||||||
metric: {
|
metric: {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
@ -20,7 +24,7 @@ export interface SeriesItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface QueryDataV3 {
|
export interface QueryDataV3 {
|
||||||
list: null;
|
list: ListItem[] | null;
|
||||||
queryName: string;
|
queryName: string;
|
||||||
legend?: string;
|
legend?: string;
|
||||||
series: SeriesItem[] | null;
|
series: SeriesItem[] | null;
|
||||||
|
@ -156,7 +156,8 @@ export type QueryBuilderContextType = {
|
|||||||
currentQuery: Query;
|
currentQuery: Query;
|
||||||
stagedQuery: Query | null;
|
stagedQuery: Query | null;
|
||||||
initialDataSource: DataSource | null;
|
initialDataSource: DataSource | null;
|
||||||
panelType: GRAPH_TYPES;
|
panelType: GRAPH_TYPES | null;
|
||||||
|
isEnabledQuery: boolean;
|
||||||
handleSetQueryData: (index: number, queryData: IBuilderQuery) => void;
|
handleSetQueryData: (index: number, queryData: IBuilderQuery) => void;
|
||||||
handleSetFormulaData: (index: number, formulaData: IBuilderFormula) => void;
|
handleSetFormulaData: (index: number, formulaData: IBuilderFormula) => void;
|
||||||
handleSetQueryItemData: (
|
handleSetQueryItemData: (
|
||||||
@ -164,8 +165,10 @@ export type QueryBuilderContextType = {
|
|||||||
type: EQueryType.PROM | EQueryType.CLICKHOUSE,
|
type: EQueryType.PROM | EQueryType.CLICKHOUSE,
|
||||||
newQueryData: IPromQLQuery | IClickHouseQuery,
|
newQueryData: IPromQLQuery | IClickHouseQuery,
|
||||||
) => void;
|
) => void;
|
||||||
handleSetPanelType: (newPanelType: GRAPH_TYPES) => void;
|
handleSetConfig: (
|
||||||
setupInitialDataSource: (newInitialDataSource: DataSource | null) => void;
|
newPanelType: GRAPH_TYPES,
|
||||||
|
dataSource: DataSource | null,
|
||||||
|
) => void;
|
||||||
removeQueryBuilderEntityByIndex: (
|
removeQueryBuilderEntityByIndex: (
|
||||||
type: keyof QueryBuilderData,
|
type: keyof QueryBuilderData,
|
||||||
index: number,
|
index: number,
|
||||||
@ -183,6 +186,11 @@ export type QueryBuilderContextType = {
|
|||||||
) => void;
|
) => void;
|
||||||
handleRunQuery: () => void;
|
handleRunQuery: () => void;
|
||||||
resetStagedQuery: () => void;
|
resetStagedQuery: () => void;
|
||||||
|
updateAllQueriesOperators: (
|
||||||
|
queryData: Query,
|
||||||
|
panelType: GRAPH_TYPES,
|
||||||
|
dataSource: DataSource,
|
||||||
|
) => Query;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type QueryAdditionalFilter = {
|
export type QueryAdditionalFilter = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user