mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-15 17:35:53 +08:00
Feat/logs explorer (#2905)
* feat: add query builder and graph * feat: add graph * fix: id in the another places * fix: multiple queries for explorer logs * chore: chunkName is updated --------- Co-authored-by: Chintan Sudani <46838508+techchintan@users.noreply.github.com> Co-authored-by: Palash Gupta <palashgdev@gmail.com>
This commit is contained in:
parent
82936f73a3
commit
5bdb0e84d1
@ -101,6 +101,10 @@ export const Logs = Loadable(
|
||||
() => import(/* webpackChunkName: "Logs" */ 'pages/Logs'),
|
||||
);
|
||||
|
||||
export const LogsExplorer = Loadable(
|
||||
() => import(/* webpackChunkName: "Logs Explorer" */ 'pages/LogsExplorer'),
|
||||
);
|
||||
|
||||
export const Login = Loadable(
|
||||
() => import(/* webpackChunkName: "Login" */ 'pages/Login'),
|
||||
);
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
ListAllALertsPage,
|
||||
Login,
|
||||
Logs,
|
||||
LogsExplorer,
|
||||
MySettings,
|
||||
NewDashboardPage,
|
||||
OrganizationSettings,
|
||||
@ -209,6 +210,13 @@ const routes: AppRoutes[] = [
|
||||
key: 'LOGS',
|
||||
isPrivate: true,
|
||||
},
|
||||
{
|
||||
path: ROUTES.LOGS_EXPLORER,
|
||||
exact: true,
|
||||
component: LogsExplorer,
|
||||
key: 'LOGS_EXPLORER',
|
||||
isPrivate: true,
|
||||
},
|
||||
{
|
||||
path: ROUTES.LOGIN,
|
||||
exact: true,
|
||||
|
@ -1,5 +1,6 @@
|
||||
// ** Helpers
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import { createIdFromObjectFields } from 'lib/createIdFromObjectFields';
|
||||
import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderItemName';
|
||||
import {
|
||||
BaseAutocompleteData,
|
||||
@ -18,6 +19,7 @@ import { EQueryType } from 'types/common/dashboard';
|
||||
import {
|
||||
BoolOperators,
|
||||
DataSource,
|
||||
LogsAggregatorOperator,
|
||||
MetricAggregateOperator,
|
||||
NumberOperators,
|
||||
PanelTypeKeys,
|
||||
@ -25,6 +27,7 @@ import {
|
||||
QueryBuilderData,
|
||||
ReduceOperators,
|
||||
StringOperators,
|
||||
TracesAggregatorOperator,
|
||||
} from 'types/common/queryBuilder';
|
||||
import { SelectOption } from 'types/common/select';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
@ -100,14 +103,17 @@ export const initialHavingValues: HavingForm = {
|
||||
};
|
||||
|
||||
export const initialAutocompleteData: BaseAutocompleteData = {
|
||||
id: uuid(),
|
||||
id: createIdFromObjectFields(
|
||||
{ dataType: null, key: '', isColumn: null, type: null },
|
||||
baseAutoCompleteIdKeysOrder,
|
||||
),
|
||||
dataType: null,
|
||||
key: '',
|
||||
isColumn: null,
|
||||
type: null,
|
||||
};
|
||||
|
||||
export const initialQueryBuilderFormValues: IBuilderQuery = {
|
||||
const initialQueryBuilderFormValues: IBuilderQuery = {
|
||||
dataSource: DataSource.METRICS,
|
||||
queryName: createNewBuilderItemName({ existNames: [], sourceNames: alphabet }),
|
||||
aggregateOperator: MetricAggregateOperator.NOOP,
|
||||
@ -127,6 +133,27 @@ export const initialQueryBuilderFormValues: IBuilderQuery = {
|
||||
reduceTo: 'sum',
|
||||
};
|
||||
|
||||
const initialQueryBuilderFormLogsValues: IBuilderQuery = {
|
||||
...initialQueryBuilderFormValues,
|
||||
aggregateOperator: LogsAggregatorOperator.COUNT,
|
||||
dataSource: DataSource.LOGS,
|
||||
};
|
||||
|
||||
const initialQueryBuilderFormTracesValues: IBuilderQuery = {
|
||||
...initialQueryBuilderFormValues,
|
||||
aggregateOperator: TracesAggregatorOperator.COUNT,
|
||||
dataSource: DataSource.TRACES,
|
||||
};
|
||||
|
||||
export const initialQueryBuilderFormValuesMap: Record<
|
||||
DataSource,
|
||||
IBuilderQuery
|
||||
> = {
|
||||
metrics: initialQueryBuilderFormValues,
|
||||
logs: initialQueryBuilderFormLogsValues,
|
||||
traces: initialQueryBuilderFormTracesValues,
|
||||
};
|
||||
|
||||
export const initialFormulaBuilderFormValues: IBuilderFormula = {
|
||||
queryName: createNewBuilderItemName({
|
||||
existNames: [],
|
||||
@ -161,17 +188,39 @@ export const initialSingleQueryMap: Record<
|
||||
IClickHouseQuery | IPromQLQuery
|
||||
> = { clickhouse_sql: initialClickHouseData, promql: initialQueryPromQLData };
|
||||
|
||||
export const initialQuery: QueryState = {
|
||||
export const initialQueryState: QueryState = {
|
||||
id: uuid(),
|
||||
builder: initialQueryBuilderData,
|
||||
clickhouse_sql: [initialClickHouseData],
|
||||
promql: [initialQueryPromQLData],
|
||||
};
|
||||
|
||||
export const initialQueryWithType: Query = {
|
||||
...initialQuery,
|
||||
const initialQueryWithType: Query = {
|
||||
...initialQueryState,
|
||||
queryType: EQueryType.QUERY_BUILDER,
|
||||
};
|
||||
|
||||
const initialQueryLogsWithType: Query = {
|
||||
...initialQueryWithType,
|
||||
builder: {
|
||||
...initialQueryWithType.builder,
|
||||
queryData: [initialQueryBuilderFormValuesMap.logs],
|
||||
},
|
||||
};
|
||||
const initialQueryTracesWithType: Query = {
|
||||
...initialQueryWithType,
|
||||
builder: {
|
||||
...initialQueryWithType.builder,
|
||||
queryData: [initialQueryBuilderFormValuesMap.traces],
|
||||
},
|
||||
};
|
||||
|
||||
export const initialQueriesMap: Record<DataSource, Query> = {
|
||||
metrics: initialQueryWithType,
|
||||
logs: initialQueryLogsWithType,
|
||||
traces: initialQueryTracesWithType,
|
||||
};
|
||||
|
||||
export const operatorsByTypes: Record<LocalDataType, string[]> = {
|
||||
string: Object.values(StringOperators),
|
||||
number: Object.values(NumberOperators),
|
||||
|
@ -1 +1,2 @@
|
||||
export const COMPOSITE_QUERY = 'compositeQuery';
|
||||
export const PANEL_TYPES_QUERY = 'panelTypes';
|
||||
|
@ -27,6 +27,7 @@ const ROUTES = {
|
||||
UN_AUTHORIZED: '/un-authorized',
|
||||
NOT_FOUND: '/not-found',
|
||||
LOGS: '/logs',
|
||||
LOGS_EXPLORER: '/logs-explorer',
|
||||
HOME_PAGE: '/',
|
||||
PASSWORD_RESET: '/password-reset',
|
||||
LIST_LICENSES: '/licenses',
|
||||
|
@ -36,8 +36,11 @@ const themeColors = {
|
||||
royalGrey: '#888888',
|
||||
matterhornGrey: '#555555',
|
||||
whiteCream: '#ffffffd5',
|
||||
white: '#ffffff',
|
||||
black: '#000000',
|
||||
lightBlack: '#141414',
|
||||
lightgrey: '#ddd',
|
||||
lightWhite: '#ffffffd9',
|
||||
borderLightGrey: '#d9d9d9',
|
||||
borderDarkGrey: '#424242',
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {
|
||||
initialQueryBuilderFormValues,
|
||||
initialQueryBuilderFormValuesMap,
|
||||
initialQueryPromQLData,
|
||||
PANEL_TYPES,
|
||||
} from 'constants/queryBuilder';
|
||||
@ -11,11 +11,6 @@ import {
|
||||
defaultMatchType,
|
||||
} from 'types/api/alerts/def';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import {
|
||||
DataSource,
|
||||
LogsAggregatorOperator,
|
||||
TracesAggregatorOperator,
|
||||
} from 'types/common/queryBuilder';
|
||||
|
||||
const defaultAlertDescription =
|
||||
'This alert is fired when the defined metric (current value: {{$value}}) crosses the threshold ({{$threshold}})';
|
||||
@ -32,7 +27,7 @@ export const alertDefaults: AlertDef = {
|
||||
condition: {
|
||||
compositeQuery: {
|
||||
builderQueries: {
|
||||
A: initialQueryBuilderFormValues,
|
||||
A: initialQueryBuilderFormValuesMap.metrics,
|
||||
},
|
||||
promQueries: { A: initialQueryPromQLData },
|
||||
chQueries: {
|
||||
@ -61,11 +56,7 @@ export const logAlertDefaults: AlertDef = {
|
||||
condition: {
|
||||
compositeQuery: {
|
||||
builderQueries: {
|
||||
A: {
|
||||
...initialQueryBuilderFormValues,
|
||||
aggregateOperator: LogsAggregatorOperator.COUNT,
|
||||
dataSource: DataSource.LOGS,
|
||||
},
|
||||
A: initialQueryBuilderFormValuesMap.logs,
|
||||
},
|
||||
promQueries: { A: initialQueryPromQLData },
|
||||
chQueries: {
|
||||
@ -95,11 +86,7 @@ export const traceAlertDefaults: AlertDef = {
|
||||
condition: {
|
||||
compositeQuery: {
|
||||
builderQueries: {
|
||||
A: {
|
||||
...initialQueryBuilderFormValues,
|
||||
aggregateOperator: TracesAggregatorOperator.COUNT,
|
||||
dataSource: DataSource.TRACES,
|
||||
},
|
||||
A: initialQueryBuilderFormValuesMap.traces,
|
||||
},
|
||||
promQueries: { A: initialQueryPromQLData },
|
||||
chQueries: {
|
||||
@ -129,11 +116,7 @@ export const exceptionAlertDefaults: AlertDef = {
|
||||
condition: {
|
||||
compositeQuery: {
|
||||
builderQueries: {
|
||||
A: {
|
||||
...initialQueryBuilderFormValues,
|
||||
aggregateOperator: TracesAggregatorOperator.COUNT,
|
||||
dataSource: DataSource.TRACES,
|
||||
},
|
||||
A: initialQueryBuilderFormValuesMap.traces,
|
||||
},
|
||||
promQueries: { A: initialQueryPromQLData },
|
||||
chQueries: {
|
||||
|
@ -1,16 +1,11 @@
|
||||
import { Form, Row } from 'antd';
|
||||
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
||||
import FormAlertRules from 'container/FormAlertRules';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
|
||||
import { useState } from 'react';
|
||||
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
||||
import { AlertDef } from 'types/api/alerts/def';
|
||||
|
||||
import {
|
||||
alertDefaults,
|
||||
ALERTS_VALUES_MAP,
|
||||
exceptionAlertDefaults,
|
||||
logAlertDefaults,
|
||||
traceAlertDefaults,
|
||||
@ -18,18 +13,12 @@ import {
|
||||
import SelectAlertType from './SelectAlertType';
|
||||
|
||||
function CreateRules(): JSX.Element {
|
||||
const [initValues, setInitValues] = useState<AlertDef>(alertDefaults);
|
||||
const [initValues, setInitValues] = useState<AlertDef | null>(null);
|
||||
const [alertType, setAlertType] = useState<AlertTypes>(
|
||||
AlertTypes.METRICS_BASED_ALERT,
|
||||
);
|
||||
const [formInstance] = Form.useForm();
|
||||
|
||||
const urlQuery = useUrlQuery();
|
||||
|
||||
const compositeQuery = urlQuery.get(COMPOSITE_QUERY);
|
||||
|
||||
const { redirectWithQueryBuilderData } = useQueryBuilder();
|
||||
|
||||
const onSelectType = (typ: AlertTypes): void => {
|
||||
setAlertType(typ);
|
||||
switch (typ) {
|
||||
@ -45,15 +34,9 @@ function CreateRules(): JSX.Element {
|
||||
default:
|
||||
setInitValues(alertDefaults);
|
||||
}
|
||||
|
||||
const value = ALERTS_VALUES_MAP[typ].condition.compositeQuery;
|
||||
|
||||
const compositeQuery = mapQueryDataFromApi(value);
|
||||
|
||||
redirectWithQueryBuilderData(compositeQuery);
|
||||
};
|
||||
|
||||
if (!compositeQuery) {
|
||||
if (!initValues) {
|
||||
return (
|
||||
<Row wrap={false}>
|
||||
<SelectAlertType onSelect={onSelectType} />
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||
import { StaticLineProps } from 'components/Graph';
|
||||
import Spinner from 'components/Spinner';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import GridGraphComponent from 'container/GridGraphComponent';
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems';
|
||||
@ -17,7 +17,7 @@ import { ChartContainer, FailedMessageContainer } from './styles';
|
||||
|
||||
export interface ChartPreviewProps {
|
||||
name: string;
|
||||
query: Query | undefined;
|
||||
query: Query | null;
|
||||
graphType?: GRAPH_TYPES;
|
||||
selectedTime?: timePreferenceType;
|
||||
selectedInterval?: Time;
|
||||
@ -74,15 +74,7 @@ function ChartPreview({
|
||||
|
||||
const queryResponse = useGetQueryRange(
|
||||
{
|
||||
query: query || {
|
||||
queryType: EQueryType.QUERY_BUILDER,
|
||||
promql: [],
|
||||
builder: {
|
||||
queryFormulas: [],
|
||||
queryData: [],
|
||||
},
|
||||
clickhouse_sql: [],
|
||||
},
|
||||
query: query || initialQueriesMap.metrics,
|
||||
globalSelectedInterval: selectedInterval,
|
||||
graphType,
|
||||
selectedTime,
|
||||
|
@ -48,7 +48,12 @@ function FormAlertRules({
|
||||
// init namespace for translations
|
||||
const { t } = useTranslation('alerts');
|
||||
|
||||
const { currentQuery, redirectWithQueryBuilderData } = useQueryBuilder();
|
||||
const {
|
||||
currentQuery,
|
||||
stagedQuery,
|
||||
handleRunQuery,
|
||||
redirectWithQueryBuilderData,
|
||||
} = useQueryBuilder();
|
||||
|
||||
// use query client
|
||||
const ruleCache = useQueryClient();
|
||||
@ -65,35 +70,14 @@ function FormAlertRules({
|
||||
|
||||
const sq = useMemo(() => mapQueryDataFromApi(initQuery), [initQuery]);
|
||||
|
||||
// manualStagedQuery requires manual staging of query
|
||||
// when user clicks run query button. Useful for clickhouse tab where
|
||||
// run query button is provided.
|
||||
const [manualStagedQuery, setManualStagedQuery] = useState<Query>();
|
||||
|
||||
// this use effect initiates staged query and
|
||||
// other queries based on server data.
|
||||
// useful when fetching of initial values (from api)
|
||||
// is delayed
|
||||
|
||||
const { compositeQuery } = useShareBuilderUrl({ defaultValue: sq });
|
||||
useShareBuilderUrl({ defaultValue: sq });
|
||||
|
||||
useEffect(() => {
|
||||
if (compositeQuery && !manualStagedQuery) {
|
||||
setManualStagedQuery(compositeQuery);
|
||||
}
|
||||
setAlertDef(initialValue);
|
||||
}, [
|
||||
initialValue,
|
||||
initQuery,
|
||||
redirectWithQueryBuilderData,
|
||||
currentQuery,
|
||||
manualStagedQuery,
|
||||
compositeQuery,
|
||||
]);
|
||||
}, [initialValue]);
|
||||
|
||||
const onRunQuery = (): void => {
|
||||
setManualStagedQuery(currentQuery);
|
||||
redirectWithQueryBuilderData(currentQuery);
|
||||
handleRunQuery();
|
||||
};
|
||||
|
||||
const onCancelHandler = useCallback(() => {
|
||||
@ -115,8 +99,6 @@ function FormAlertRules({
|
||||
}
|
||||
const query: Query = { ...currentQuery, queryType: val };
|
||||
|
||||
setManualStagedQuery(query);
|
||||
|
||||
redirectWithQueryBuilderData(query);
|
||||
};
|
||||
const { notifications } = useNotifications();
|
||||
@ -368,7 +350,7 @@ function FormAlertRules({
|
||||
headline={<PlotTag queryType={currentQuery.queryType} />}
|
||||
name=""
|
||||
threshold={alertDef.condition?.target}
|
||||
query={manualStagedQuery}
|
||||
query={stagedQuery}
|
||||
selectedInterval={toChartInterval(alertDef.evalWindow)}
|
||||
/>
|
||||
);
|
||||
@ -378,7 +360,7 @@ function FormAlertRules({
|
||||
headline={<PlotTag queryType={currentQuery.queryType} />}
|
||||
name="Chart Preview"
|
||||
threshold={alertDef.condition?.target}
|
||||
query={manualStagedQuery}
|
||||
query={stagedQuery}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -387,7 +369,7 @@ function FormAlertRules({
|
||||
headline={<PlotTag queryType={currentQuery.queryType} />}
|
||||
name="Chart Preview"
|
||||
threshold={alertDef.condition?.target}
|
||||
query={manualStagedQuery}
|
||||
query={stagedQuery}
|
||||
selectedInterval={toChartInterval(alertDef.evalWindow)}
|
||||
/>
|
||||
);
|
||||
|
@ -1,15 +1,10 @@
|
||||
import { NotificationInstance } from 'antd/es/notification/interface';
|
||||
import updateDashboardApi from 'api/dashboard/update';
|
||||
import {
|
||||
initialClickHouseData,
|
||||
initialQueryBuilderFormValues,
|
||||
initialQueryPromQLData,
|
||||
} from 'constants/queryBuilder';
|
||||
import { initialQueriesMap } from 'constants/queryBuilder';
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import { Layout } from 'react-grid-layout';
|
||||
import store from 'store';
|
||||
import { Dashboard, Widgets } from 'types/api/dashboard/getAll';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
|
||||
export const UpdateDashboard = async (
|
||||
{
|
||||
@ -41,15 +36,7 @@ export const UpdateDashboard = async (
|
||||
nullZeroValues: widgetData?.nullZeroValues || '',
|
||||
opacity: '',
|
||||
panelTypes: graphType,
|
||||
query: widgetData?.query || {
|
||||
queryType: EQueryType.QUERY_BUILDER,
|
||||
promql: [initialQueryPromQLData],
|
||||
clickhouse_sql: [initialClickHouseData],
|
||||
builder: {
|
||||
queryFormulas: [],
|
||||
queryData: [initialQueryBuilderFormValues],
|
||||
},
|
||||
},
|
||||
query: widgetData?.query || initialQueriesMap.metrics,
|
||||
timePreferance: widgetData?.timePreferance || 'GLOBAL_TIME',
|
||||
title: widgetData ? copyTitle : '',
|
||||
},
|
||||
|
@ -0,0 +1,11 @@
|
||||
import { Card } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const CardStyled = styled(Card)`
|
||||
position: relative;
|
||||
margin: 0.5rem 0 3.1rem 0;
|
||||
.ant-card-body {
|
||||
height: 20vh;
|
||||
min-height: 200px;
|
||||
}
|
||||
`;
|
@ -0,0 +1,66 @@
|
||||
import Graph from 'components/Graph';
|
||||
import Spinner from 'components/Spinner';
|
||||
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
|
||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { getExplorerChartData } from 'lib/explorer/getExplorerChartData';
|
||||
import { useMemo } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
|
||||
import { CardStyled } from './LogsExplorerChart.styled';
|
||||
|
||||
export function LogsExplorerChart(): 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,
|
||||
},
|
||||
);
|
||||
|
||||
const graphData = useMemo(() => {
|
||||
if (data?.payload.data && data.payload.data.result.length > 0) {
|
||||
return getExplorerChartData([data.payload.data.result[0]]);
|
||||
}
|
||||
|
||||
return getExplorerChartData([]);
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<CardStyled>
|
||||
{isFetching ? (
|
||||
<Spinner size="default" height="100%" />
|
||||
) : (
|
||||
<Graph
|
||||
name="logsExplorerChart"
|
||||
data={graphData}
|
||||
type="bar"
|
||||
containerHeight="100%"
|
||||
animate
|
||||
/>
|
||||
)}
|
||||
</CardStyled>
|
||||
);
|
||||
}
|
1
frontend/src/container/LogsExplorerChart/index.ts
Normal file
1
frontend/src/container/LogsExplorerChart/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { LogsExplorerChart } from './LogsExplorerChart';
|
@ -0,0 +1,9 @@
|
||||
import { Tabs } from 'antd';
|
||||
import { themeColors } from 'constants/theme';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const TabsStyled = styled(Tabs)`
|
||||
& .ant-tabs-nav {
|
||||
background-color: ${themeColors.lightBlack};
|
||||
}
|
||||
`;
|
@ -0,0 +1,75 @@
|
||||
import { TabsProps } from 'antd';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { PANEL_TYPES_QUERY } from 'constants/queryBuilderQueryNames';
|
||||
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 tabsItems: TabsProps['items'] = useMemo(
|
||||
() => [
|
||||
{
|
||||
label: 'List View',
|
||||
key: PANEL_TYPES.LIST,
|
||||
disabled: isMultipleQueries,
|
||||
},
|
||||
{ label: 'TimeSeries', key: PANEL_TYPES.TIME_SERIES },
|
||||
{ label: 'Table', key: PANEL_TYPES.TABLE },
|
||||
],
|
||||
[isMultipleQueries],
|
||||
);
|
||||
|
||||
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(() => {
|
||||
if (panelTypeParams === 'list' && isMultipleQueries) {
|
||||
handleChangeView(PANEL_TYPES.TIME_SERIES);
|
||||
}
|
||||
}, [panelTypeParams, isMultipleQueries, handleChangeView]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<TabsStyled
|
||||
items={tabsItems}
|
||||
defaultActiveKey={currentTabKey}
|
||||
activeKey={currentTabKey}
|
||||
onChange={handleChangeView}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
1
frontend/src/container/LogsExplorerViews/index.ts
Normal file
1
frontend/src/container/LogsExplorerViews/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { LogsExplorerViews } from './LogsExplorerViews';
|
@ -1,6 +1,6 @@
|
||||
import {
|
||||
initialFormulaBuilderFormValues,
|
||||
initialQueryBuilderFormValues,
|
||||
initialQueryBuilderFormValuesMap,
|
||||
} from 'constants/queryBuilder';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
||||
@ -18,7 +18,7 @@ export const getQueryBuilderQueries = ({
|
||||
queryFormulas: [],
|
||||
queryData: [
|
||||
{
|
||||
...initialQueryBuilderFormValues,
|
||||
...initialQueryBuilderFormValuesMap.metrics,
|
||||
aggregateOperator: MetricAggregateOperator.SUM_RATE,
|
||||
disabled: false,
|
||||
groupBy,
|
||||
@ -53,7 +53,7 @@ export const getQueryBuilderQuerieswithFormula = ({
|
||||
],
|
||||
queryData: [
|
||||
{
|
||||
...initialQueryBuilderFormValues,
|
||||
...initialQueryBuilderFormValuesMap.metrics,
|
||||
aggregateOperator: MetricAggregateOperator.SUM_RATE,
|
||||
disabled,
|
||||
groupBy,
|
||||
@ -66,7 +66,7 @@ export const getQueryBuilderQuerieswithFormula = ({
|
||||
},
|
||||
},
|
||||
{
|
||||
...initialQueryBuilderFormValues,
|
||||
...initialQueryBuilderFormValuesMap.metrics,
|
||||
aggregateOperator: MetricAggregateOperator.SUM_RATE,
|
||||
disabled,
|
||||
groupBy,
|
||||
|
@ -14,6 +14,7 @@ import { useParams } from 'react-router-dom';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
|
||||
import { Button } from './styles';
|
||||
@ -56,6 +57,7 @@ function DBCall({ getWidgetQueryBuilder }: DBCallProps): JSX.Element {
|
||||
tagFilterItems,
|
||||
}),
|
||||
clickhouse_sql: [],
|
||||
id: uuid(),
|
||||
}),
|
||||
[getWidgetQueryBuilder, servicename, tagFilterItems],
|
||||
);
|
||||
@ -69,6 +71,7 @@ function DBCall({ getWidgetQueryBuilder }: DBCallProps): JSX.Element {
|
||||
tagFilterItems,
|
||||
}),
|
||||
clickhouse_sql: [],
|
||||
id: uuid(),
|
||||
}),
|
||||
[getWidgetQueryBuilder, servicename, tagFilterItems],
|
||||
);
|
||||
|
@ -15,6 +15,7 @@ import { useMemo, useState } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
|
||||
import { legend } from './constant';
|
||||
@ -48,6 +49,7 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
|
||||
tagFilterItems,
|
||||
}),
|
||||
clickhouse_sql: [],
|
||||
id: uuid(),
|
||||
}),
|
||||
[getWidgetQueryBuilder, servicename, tagFilterItems],
|
||||
);
|
||||
@ -67,6 +69,7 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
|
||||
tagFilterItems,
|
||||
}),
|
||||
clickhouse_sql: [],
|
||||
id: uuid(),
|
||||
}),
|
||||
[getWidgetQueryBuilder, servicename, tagFilterItems],
|
||||
);
|
||||
@ -82,6 +85,7 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
|
||||
tagFilterItems,
|
||||
}),
|
||||
clickhouse_sql: [],
|
||||
id: uuid(),
|
||||
}),
|
||||
[getWidgetQueryBuilder, servicename, tagFilterItems],
|
||||
);
|
||||
@ -97,6 +101,7 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
|
||||
tagFilterItems,
|
||||
}),
|
||||
clickhouse_sql: [],
|
||||
id: uuid(),
|
||||
}),
|
||||
[getWidgetQueryBuilder, servicename, tagFilterItems],
|
||||
);
|
||||
|
@ -21,6 +21,7 @@ import { AppState } from 'store/reducers';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import MetricReducer from 'types/reducer/metrics';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import {
|
||||
errorPercentage,
|
||||
@ -91,6 +92,7 @@ function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element {
|
||||
topLevelOperations,
|
||||
}),
|
||||
clickhouse_sql: [],
|
||||
id: uuid(),
|
||||
}),
|
||||
[getWidgetQueryBuilder, servicename, topLevelOperations, tagFilterItems],
|
||||
);
|
||||
@ -106,6 +108,7 @@ function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element {
|
||||
topLevelOperations,
|
||||
}),
|
||||
clickhouse_sql: [],
|
||||
id: uuid(),
|
||||
}),
|
||||
[servicename, topLevelOperations, tagFilterItems, getWidgetQueryBuilder],
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
import { initialQueryWithType } from 'constants/queryBuilder';
|
||||
import { initialQueriesMap } from 'constants/queryBuilder';
|
||||
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
@ -47,7 +47,7 @@ function DashboardGraphSlider({ toggleAddWidget }: Props): JSX.Element {
|
||||
history.push(
|
||||
`${history.location.pathname}/new?graphType=${name}&widgetId=${
|
||||
emptyLayout.i
|
||||
}&${COMPOSITE_QUERY}=${JSON.stringify(initialQueryWithType)}`,
|
||||
}&${COMPOSITE_QUERY}=${JSON.stringify(initialQueriesMap.metrics)}`,
|
||||
);
|
||||
} catch (error) {
|
||||
notifications.error({
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ITEMS } from 'container/NewDashboard/ComponentsSlider/menuItems';
|
||||
import { ReactNode } from 'react';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
export type QueryBuilderConfig =
|
||||
@ -11,4 +12,5 @@ export type QueryBuilderConfig =
|
||||
export type QueryBuilderProps = {
|
||||
config?: QueryBuilderConfig;
|
||||
panelType: ITEMS;
|
||||
actions?: ReactNode;
|
||||
};
|
||||
|
@ -0,0 +1,6 @@
|
||||
import { Col } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const ActionsWrapperStyled = styled(Col)`
|
||||
padding-right: 1rem;
|
||||
`;
|
@ -11,15 +11,16 @@ import { Formula, Query } from './components';
|
||||
// ** Types
|
||||
import { QueryBuilderProps } from './QueryBuilder.interfaces';
|
||||
// ** Styles
|
||||
import { ActionsWrapperStyled } from './QueryBuilder.styled';
|
||||
|
||||
export const QueryBuilder = memo(function QueryBuilder({
|
||||
config,
|
||||
panelType,
|
||||
actions,
|
||||
}: QueryBuilderProps): JSX.Element {
|
||||
const {
|
||||
currentQuery,
|
||||
setupInitialDataSource,
|
||||
resetQueryBuilderInfo,
|
||||
addNewBuilderQuery,
|
||||
addNewFormula,
|
||||
handleSetPanelType,
|
||||
@ -35,13 +36,6 @@ export const QueryBuilder = memo(function QueryBuilder({
|
||||
handleSetPanelType(panelType);
|
||||
}, [handleSetPanelType, panelType]);
|
||||
|
||||
useEffect(
|
||||
() => (): void => {
|
||||
resetQueryBuilderInfo();
|
||||
},
|
||||
[resetQueryBuilderInfo],
|
||||
);
|
||||
|
||||
const isDisabledQueryButton = useMemo(
|
||||
() => currentQuery.builder.queryData.length >= MAX_QUERIES,
|
||||
[currentQuery],
|
||||
@ -81,28 +75,31 @@ export const QueryBuilder = memo(function QueryBuilder({
|
||||
</Row>
|
||||
</Col>
|
||||
|
||||
<Row gutter={[20, 0]}>
|
||||
<Col>
|
||||
<Button
|
||||
disabled={isDisabledQueryButton}
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={addNewBuilderQuery}
|
||||
>
|
||||
Query
|
||||
</Button>
|
||||
</Col>
|
||||
<Col>
|
||||
<Button
|
||||
disabled={isDisabledFormulaButton}
|
||||
onClick={addNewFormula}
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
>
|
||||
Formula
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<ActionsWrapperStyled span={24}>
|
||||
<Row gutter={[20, 0]}>
|
||||
<Col>
|
||||
<Button
|
||||
disabled={isDisabledQueryButton}
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={addNewBuilderQuery}
|
||||
>
|
||||
Query
|
||||
</Button>
|
||||
</Col>
|
||||
<Col>
|
||||
<Button
|
||||
disabled={isDisabledFormulaButton}
|
||||
onClick={addNewFormula}
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
>
|
||||
Formula
|
||||
</Button>
|
||||
</Col>
|
||||
{actions}
|
||||
</Row>
|
||||
</ActionsWrapperStyled>
|
||||
</Row>
|
||||
);
|
||||
});
|
||||
|
@ -3,19 +3,17 @@ import userEvent from '@testing-library/user-event';
|
||||
// Constants
|
||||
import {
|
||||
HAVING_OPERATORS,
|
||||
initialQueryBuilderFormValues,
|
||||
initialQueryBuilderFormValuesMap,
|
||||
} from 'constants/queryBuilder';
|
||||
import { transformFromStringToHaving } from 'lib/query/transformQueryBuilderData';
|
||||
// ** Types
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
// ** Components
|
||||
import { HavingFilter } from '../HavingFilter';
|
||||
|
||||
const valueWithAttributeAndOperator: IBuilderQuery = {
|
||||
...initialQueryBuilderFormValues,
|
||||
dataSource: DataSource.LOGS,
|
||||
...initialQueryBuilderFormValuesMap.logs,
|
||||
aggregateOperator: 'SUM',
|
||||
aggregateAttribute: {
|
||||
isColumn: false,
|
||||
@ -29,7 +27,10 @@ describe('Having filter behaviour', () => {
|
||||
test('Having filter render is rendered', () => {
|
||||
const mockFn = jest.fn();
|
||||
const { unmount } = render(
|
||||
<HavingFilter query={initialQueryBuilderFormValues} onChange={mockFn} />,
|
||||
<HavingFilter
|
||||
query={initialQueryBuilderFormValuesMap.metrics}
|
||||
onChange={mockFn}
|
||||
/>,
|
||||
);
|
||||
|
||||
const selectId = 'havingSelect';
|
||||
@ -44,7 +45,10 @@ describe('Having filter behaviour', () => {
|
||||
test('Having render is disabled initially', () => {
|
||||
const mockFn = jest.fn();
|
||||
const { unmount } = render(
|
||||
<HavingFilter query={initialQueryBuilderFormValues} onChange={mockFn} />,
|
||||
<HavingFilter
|
||||
query={initialQueryBuilderFormValuesMap.metrics}
|
||||
onChange={mockFn}
|
||||
/>,
|
||||
);
|
||||
|
||||
const input = screen.getByRole('combobox');
|
||||
|
@ -53,16 +53,20 @@ const menus: SidebarMenu[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
key: ROUTES.LOGS,
|
||||
key: 'logs',
|
||||
label: 'Logs',
|
||||
icon: <AlignLeftOutlined />,
|
||||
// label: createLabelWithTags('Logs', ['Beta']),
|
||||
// children: [
|
||||
// {
|
||||
// key: ROUTES.LOGS,
|
||||
// label: 'Search',
|
||||
// },
|
||||
// ],
|
||||
children: [
|
||||
{
|
||||
key: ROUTES.LOGS,
|
||||
label: 'Search',
|
||||
},
|
||||
// TODO: uncomment when will be ready explorer
|
||||
// {
|
||||
// key: ROUTES.LOGS_EXPLORER,
|
||||
// label: 'Views',
|
||||
// },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: ROUTES.ALL_DASHBOARD,
|
||||
|
@ -19,6 +19,7 @@ const breadcrumbNameMap = {
|
||||
[ROUTES.LIST_ALL_ALERT]: 'Alerts',
|
||||
[ROUTES.ALL_DASHBOARD]: 'Dashboard',
|
||||
[ROUTES.LOGS]: 'Logs',
|
||||
[ROUTES.LOGS_EXPLORER]: 'Logs Explorer',
|
||||
};
|
||||
|
||||
function ShowBreadcrumbs(props: RouteComponentProps): JSX.Element {
|
||||
|
14
frontend/src/hooks/queryBuilder/useGetCompositeQueryParam.ts
Normal file
14
frontend/src/hooks/queryBuilder/useGetCompositeQueryParam.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { useMemo } from 'react';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
export const useGetCompositeQueryParam = (): Query | null => {
|
||||
const urlQuery = useUrlQuery();
|
||||
|
||||
return useMemo(() => {
|
||||
const compositeQuery = urlQuery.get(COMPOSITE_QUERY);
|
||||
|
||||
return compositeQuery ? JSON.parse(compositeQuery) : null;
|
||||
}, [urlQuery]);
|
||||
};
|
@ -0,0 +1,16 @@
|
||||
import { PANEL_TYPES_QUERY } from 'constants/queryBuilderQueryNames';
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useGetPanelTypesQueryParam = <T extends GRAPH_TYPES | undefined>(
|
||||
defaultPanelType?: T,
|
||||
): T extends undefined ? GRAPH_TYPES | null : GRAPH_TYPES => {
|
||||
const urlQuery = useUrlQuery();
|
||||
|
||||
return useMemo(() => {
|
||||
const panelTypeQuery = urlQuery.get(PANEL_TYPES_QUERY);
|
||||
|
||||
return panelTypeQuery ? JSON.parse(panelTypeQuery) : defaultPanelType;
|
||||
}, [urlQuery, defaultPanelType]);
|
||||
};
|
@ -1,7 +1,6 @@
|
||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||
import { useMemo } from 'react';
|
||||
import { useQuery, UseQueryOptions, UseQueryResult } from 'react-query';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import {
|
||||
GetMetricQueryRange,
|
||||
GetQueryResultsProps,
|
||||
@ -9,18 +8,18 @@ import {
|
||||
import { SuccessResponse } from 'types/api';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
|
||||
export const useGetQueryRange = (
|
||||
type UseGetQueryRange = (
|
||||
requestData: GetQueryResultsProps,
|
||||
options?: UseQueryOptions<SuccessResponse<MetricRangePayloadProps>, Error>,
|
||||
): UseQueryResult<SuccessResponse<MetricRangePayloadProps>, Error> => {
|
||||
const { key } = useLocation();
|
||||
) => UseQueryResult<SuccessResponse<MetricRangePayloadProps>, Error>;
|
||||
|
||||
export const useGetQueryRange: UseGetQueryRange = (requestData, options) => {
|
||||
const queryKey = useMemo(() => {
|
||||
if (options?.queryKey) {
|
||||
return [...options.queryKey, key];
|
||||
return [...options.queryKey];
|
||||
}
|
||||
return [REACT_QUERY_KEY.GET_QUERY_RANGE, key, requestData];
|
||||
}, [key, options?.queryKey, requestData]);
|
||||
return [REACT_QUERY_KEY.GET_QUERY_RANGE, requestData];
|
||||
}, [options?.queryKey, requestData]);
|
||||
|
||||
return useQuery<SuccessResponse<MetricRangePayloadProps>, Error>({
|
||||
queryFn: async () => GetMetricQueryRange(requestData),
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {
|
||||
initialAutocompleteData,
|
||||
initialQueryBuilderFormValues,
|
||||
initialQueryBuilderFormValuesMap,
|
||||
mapOfFilters,
|
||||
} from 'constants/queryBuilder';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
@ -21,6 +21,7 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => {
|
||||
handleSetQueryData,
|
||||
removeQueryBuilderEntityByIndex,
|
||||
panelType,
|
||||
initialDataSource,
|
||||
} = useQueryBuilder();
|
||||
const [operators, setOperators] = useState<SelectOption<string, string>[]>([]);
|
||||
const [listOfAdditionalFilters, setListOfAdditionalFilters] = useState<
|
||||
@ -80,9 +81,9 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => {
|
||||
panelType,
|
||||
});
|
||||
|
||||
const entries = Object.entries(initialQueryBuilderFormValues).filter(
|
||||
([key]) => key !== 'queryName' && key !== 'expression',
|
||||
);
|
||||
const entries = Object.entries(
|
||||
initialQueryBuilderFormValuesMap.metrics,
|
||||
).filter(([key]) => key !== 'queryName' && key !== 'expression');
|
||||
|
||||
const initCopyResult = Object.fromEntries(entries);
|
||||
|
||||
@ -121,12 +122,24 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (initialDataSource && dataSource !== initialDataSource) return;
|
||||
|
||||
const initialOperators = getOperatorsBySourceAndPanelType({
|
||||
dataSource,
|
||||
panelType,
|
||||
});
|
||||
|
||||
if (JSON.stringify(operators) === JSON.stringify(initialOperators)) return;
|
||||
|
||||
setOperators(initialOperators);
|
||||
}, [dataSource, panelType]);
|
||||
handleChangeOperator(initialOperators[0].value);
|
||||
}, [
|
||||
dataSource,
|
||||
initialDataSource,
|
||||
panelType,
|
||||
operators,
|
||||
handleChangeOperator,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const additionalFilters = getNewListOfAdditionalFilters(dataSource);
|
||||
|
@ -1,27 +1,19 @@
|
||||
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
import { useGetCompositeQueryParam } from './useGetCompositeQueryParam';
|
||||
import { useQueryBuilder } from './useQueryBuilder';
|
||||
|
||||
type UseShareBuilderUrlParams = { defaultValue: Query };
|
||||
type UseShareBuilderUrlReturnType = { compositeQuery: Query | null };
|
||||
|
||||
export const useShareBuilderUrl = ({
|
||||
defaultValue,
|
||||
}: UseShareBuilderUrlParams): UseShareBuilderUrlReturnType => {
|
||||
const { redirectWithQueryBuilderData } = useQueryBuilder();
|
||||
}: UseShareBuilderUrlParams): void => {
|
||||
const { redirectWithQueryBuilderData, resetStagedQuery } = useQueryBuilder();
|
||||
const urlQuery = useUrlQuery();
|
||||
|
||||
const compositeQuery: Query | null = useMemo(() => {
|
||||
const query = urlQuery.get(COMPOSITE_QUERY);
|
||||
if (query) {
|
||||
return JSON.parse(query);
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [urlQuery]);
|
||||
const compositeQuery = useGetCompositeQueryParam();
|
||||
|
||||
useEffect(() => {
|
||||
if (!compositeQuery) {
|
||||
@ -29,5 +21,10 @@ export const useShareBuilderUrl = ({
|
||||
}
|
||||
}, [defaultValue, urlQuery, redirectWithQueryBuilderData, compositeQuery]);
|
||||
|
||||
return { compositeQuery };
|
||||
useEffect(
|
||||
() => (): void => {
|
||||
resetStagedQuery();
|
||||
},
|
||||
[resetStagedQuery],
|
||||
);
|
||||
};
|
||||
|
46
frontend/src/lib/explorer/getExplorerChartData.ts
Normal file
46
frontend/src/lib/explorer/getExplorerChartData.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { ChartData } from 'chart.js';
|
||||
import getLabelName from 'lib/getLabelName';
|
||||
import { QueryData } from 'types/api/widgets/getQuery';
|
||||
|
||||
import { colors } from '../getRandomColor';
|
||||
|
||||
export const getExplorerChartData = (
|
||||
queryData: QueryData[],
|
||||
): ChartData<'bar'> => {
|
||||
const uniqueTimeLabels = new Set<number>();
|
||||
|
||||
const sortedData = [...queryData].sort((a, b) => {
|
||||
if (a.queryName < b.queryName) return -1;
|
||||
if (a.queryName > b.queryName) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
const modifiedData: { label: string }[] = sortedData.map((result) => {
|
||||
const { metric, queryName, legend } = result;
|
||||
result.values.forEach((value) => {
|
||||
uniqueTimeLabels.add(value[0] * 1000);
|
||||
});
|
||||
|
||||
return {
|
||||
label: getLabelName(metric, queryName || '', legend || ''),
|
||||
};
|
||||
});
|
||||
|
||||
const labels = Array.from(uniqueTimeLabels)
|
||||
.sort((a, b) => a - b)
|
||||
.map((value) => new Date(value));
|
||||
|
||||
const allLabels = modifiedData.map((e) => e.label);
|
||||
|
||||
const data: ChartData<'bar'> = {
|
||||
labels,
|
||||
datasets: queryData.map((result, index) => ({
|
||||
label: allLabels[index],
|
||||
data: result.values.map((item) => parseFloat(item[1])),
|
||||
backgroundColor: colors[index % colors.length] || 'red',
|
||||
borderColor: colors[index % colors.length] || 'red',
|
||||
})),
|
||||
};
|
||||
|
||||
return data;
|
||||
};
|
@ -15,6 +15,11 @@ export const getOperatorsBySourceAndPanelType = ({
|
||||
}: GetQueryOperatorsParams): SelectOption<string, string>[] => {
|
||||
let operatorsByDataSource = mapOfOperators[dataSource];
|
||||
|
||||
if (panelType === PANEL_TYPES.LIST) {
|
||||
operatorsByDataSource = operatorsByDataSource.filter(
|
||||
(operator) => operator.value === StringOperators.NOOP,
|
||||
);
|
||||
}
|
||||
if (dataSource !== DataSource.METRICS && panelType !== PANEL_TYPES.LIST) {
|
||||
operatorsByDataSource = operatorsByDataSource.filter(
|
||||
(operator) => operator.value !== StringOperators.NOOP,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { initialQuery } from 'constants/queryBuilder';
|
||||
import { initialQueryState } from 'constants/queryBuilder';
|
||||
import { ICompositeMetricQuery } from 'types/api/alerts/compositeQuery';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { transformQueryBuilderDataModel } from '../transformQueryBuilderDataModel';
|
||||
|
||||
@ -9,14 +10,14 @@ export const mapQueryDataFromApi = (
|
||||
): Query => {
|
||||
const builder = compositeQuery.builderQueries
|
||||
? transformQueryBuilderDataModel(compositeQuery.builderQueries)
|
||||
: initialQuery.builder;
|
||||
: initialQueryState.builder;
|
||||
|
||||
const promql = compositeQuery.promQueries
|
||||
? Object.keys(compositeQuery.promQueries).map((key) => ({
|
||||
...compositeQuery.promQueries[key],
|
||||
name: key,
|
||||
}))
|
||||
: initialQuery.promql;
|
||||
: initialQueryState.promql;
|
||||
|
||||
const clickhouseSql = compositeQuery.chQueries
|
||||
? Object.keys(compositeQuery.chQueries).map((key) => ({
|
||||
@ -24,12 +25,13 @@ export const mapQueryDataFromApi = (
|
||||
name: key,
|
||||
query: compositeQuery.chQueries[key].query,
|
||||
}))
|
||||
: initialQuery.clickhouse_sql;
|
||||
: initialQueryState.clickhouse_sql;
|
||||
|
||||
return {
|
||||
builder,
|
||||
promql,
|
||||
clickhouse_sql: clickhouseSql,
|
||||
queryType: compositeQuery.queryType,
|
||||
id: uuid(),
|
||||
};
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {
|
||||
initialFormulaBuilderFormValues,
|
||||
initialQueryBuilderFormValues,
|
||||
initialQueryBuilderFormValuesMap,
|
||||
} from 'constants/queryBuilder';
|
||||
import { FORMULA_REGEXP } from 'constants/regExp';
|
||||
import {
|
||||
@ -22,7 +22,7 @@ export const transformQueryBuilderDataModel = (
|
||||
queryFormulas.push({ ...initialFormulaBuilderFormValues, ...formula });
|
||||
} else {
|
||||
const query = value as IBuilderQuery;
|
||||
queryData.push({ ...initialQueryBuilderFormValues, ...query });
|
||||
queryData.push({ ...initialQueryBuilderFormValuesMap.metrics, ...query });
|
||||
}
|
||||
});
|
||||
|
||||
|
45
frontend/src/pages/LogsExplorer/index.tsx
Normal file
45
frontend/src/pages/LogsExplorer/index.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
import { Button, Col, Row } from 'antd';
|
||||
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { LogsExplorerChart } from 'container/LogsExplorerChart';
|
||||
import { LogsExplorerViews } from 'container/LogsExplorerViews';
|
||||
import { QueryBuilder } from 'container/QueryBuilder';
|
||||
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
// ** Styles
|
||||
import { ButtonWrapperStyled, WrapperStyled } from './styles';
|
||||
|
||||
function LogsExporer(): JSX.Element {
|
||||
const { handleRunQuery } = useQueryBuilder();
|
||||
const panelTypes = useGetPanelTypesQueryParam(PANEL_TYPES.LIST);
|
||||
|
||||
useShareBuilderUrl({ defaultValue: initialQueriesMap.logs });
|
||||
|
||||
return (
|
||||
<WrapperStyled>
|
||||
<Row gutter={[0, 28]}>
|
||||
<Col xs={24}>
|
||||
<QueryBuilder
|
||||
panelType={panelTypes}
|
||||
config={{ initialDataSource: DataSource.LOGS, queryVariant: 'static' }}
|
||||
actions={
|
||||
<ButtonWrapperStyled>
|
||||
<Button type="primary" onClick={handleRunQuery}>
|
||||
Run Query
|
||||
</Button>
|
||||
</ButtonWrapperStyled>
|
||||
}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24}>
|
||||
<LogsExplorerChart />
|
||||
<LogsExplorerViews />
|
||||
</Col>
|
||||
</Row>
|
||||
</WrapperStyled>
|
||||
);
|
||||
}
|
||||
|
||||
export default LogsExporer;
|
11
frontend/src/pages/LogsExplorer/styles.ts
Normal file
11
frontend/src/pages/LogsExplorer/styles.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Col } from 'antd';
|
||||
import { themeColors } from 'constants/theme';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const WrapperStyled = styled.div`
|
||||
color: ${themeColors.lightWhite};
|
||||
`;
|
||||
|
||||
export const ButtonWrapperStyled = styled(Col)`
|
||||
margin-left: auto;
|
||||
`;
|
@ -4,10 +4,10 @@ import {
|
||||
formulasNames,
|
||||
initialClickHouseData,
|
||||
initialFormulaBuilderFormValues,
|
||||
initialQuery,
|
||||
initialQueryBuilderFormValues,
|
||||
initialQueriesMap,
|
||||
initialQueryBuilderFormValuesMap,
|
||||
initialQueryPromQLData,
|
||||
initialQueryWithType,
|
||||
initialQueryState,
|
||||
initialSingleQueryMap,
|
||||
MAX_FORMULAS,
|
||||
MAX_QUERIES,
|
||||
@ -15,6 +15,7 @@ import {
|
||||
} from 'constants/queryBuilder';
|
||||
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { createIdFromObjectFields } from 'lib/createIdFromObjectFields';
|
||||
import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderItemName';
|
||||
@ -44,19 +45,17 @@ import {
|
||||
QueryBuilderContextType,
|
||||
QueryBuilderData,
|
||||
} from 'types/common/queryBuilder';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
export const QueryBuilderContext = createContext<QueryBuilderContextType>({
|
||||
currentQuery: initialQueryWithType,
|
||||
currentQuery: initialQueriesMap.metrics,
|
||||
stagedQuery: initialQueriesMap.metrics,
|
||||
initialDataSource: null,
|
||||
panelType: PANEL_TYPES.TIME_SERIES,
|
||||
resetQueryBuilderData: () => {},
|
||||
resetQueryBuilderInfo: () => {},
|
||||
handleSetQueryData: () => {},
|
||||
handleSetFormulaData: () => {},
|
||||
handleSetQueryItemData: () => {},
|
||||
handleSetPanelType: () => {},
|
||||
handleSetQueryType: () => {},
|
||||
initQueryBuilderData: () => {},
|
||||
setupInitialDataSource: () => {},
|
||||
removeQueryBuilderEntityByIndex: () => {},
|
||||
removeQueryTypeItemByIndex: () => {},
|
||||
@ -64,6 +63,8 @@ export const QueryBuilderContext = createContext<QueryBuilderContextType>({
|
||||
addNewFormula: () => {},
|
||||
addNewQueryItem: () => {},
|
||||
redirectWithQueryBuilderData: () => {},
|
||||
handleRunQuery: () => {},
|
||||
resetStagedQuery: () => {},
|
||||
});
|
||||
|
||||
export function QueryBuilderProvider({
|
||||
@ -73,6 +74,8 @@ export function QueryBuilderProvider({
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
|
||||
const compositeQueryParam = useGetCompositeQueryParam();
|
||||
|
||||
const [initialDataSource, setInitialDataSource] = useState<DataSource | null>(
|
||||
null,
|
||||
);
|
||||
@ -81,81 +84,77 @@ export function QueryBuilderProvider({
|
||||
PANEL_TYPES.TIME_SERIES,
|
||||
);
|
||||
|
||||
const [currentQuery, setCurrentQuery] = useState<QueryState>(initialQuery);
|
||||
const [currentQuery, setCurrentQuery] = useState<QueryState>(
|
||||
initialQueryState,
|
||||
);
|
||||
const [stagedQuery, setStagedQuery] = useState<Query | null>(null);
|
||||
|
||||
const [queryType, setQueryType] = useState<EQueryType>(
|
||||
EQueryType.QUERY_BUILDER,
|
||||
);
|
||||
|
||||
const handleSetQueryType = useCallback((newQueryType: EQueryType) => {
|
||||
setQueryType(newQueryType);
|
||||
}, []);
|
||||
const initQueryBuilderData = useCallback(
|
||||
(query: Query): void => {
|
||||
const { queryType: newQueryType, ...queryState } = query;
|
||||
|
||||
const resetQueryBuilderInfo = useCallback((): void => {
|
||||
setInitialDataSource(null);
|
||||
setPanelType(PANEL_TYPES.TIME_SERIES);
|
||||
}, []);
|
||||
|
||||
const resetQueryBuilderData = useCallback(() => {
|
||||
setCurrentQuery(initialQuery);
|
||||
}, []);
|
||||
|
||||
const initQueryBuilderData = useCallback((query: Partial<Query>): void => {
|
||||
const { queryType, ...queryState } = query;
|
||||
|
||||
const builder: QueryBuilderData = {
|
||||
queryData: queryState.builder
|
||||
? queryState.builder.queryData.map((item) => ({
|
||||
...initialQueryBuilderFormValues,
|
||||
...item,
|
||||
}))
|
||||
: initialQuery.builder.queryData,
|
||||
queryFormulas: queryState.builder
|
||||
? queryState.builder.queryFormulas.map((item) => ({
|
||||
...initialFormulaBuilderFormValues,
|
||||
...item,
|
||||
}))
|
||||
: initialQuery.builder.queryFormulas,
|
||||
};
|
||||
|
||||
const promql: IPromQLQuery[] = queryState.promql
|
||||
? queryState.promql.map((item) => ({
|
||||
...initialQueryPromQLData,
|
||||
const builder: QueryBuilderData = {
|
||||
queryData: queryState.builder.queryData.map((item) => ({
|
||||
...initialQueryBuilderFormValuesMap[
|
||||
initialDataSource || DataSource.METRICS
|
||||
],
|
||||
...item,
|
||||
}))
|
||||
: initialQuery.promql;
|
||||
})),
|
||||
queryFormulas: queryState.builder.queryFormulas.map((item) => ({
|
||||
...initialFormulaBuilderFormValues,
|
||||
...item,
|
||||
})),
|
||||
};
|
||||
|
||||
const clickHouse: IClickHouseQuery[] = queryState.clickhouse_sql
|
||||
? queryState.clickhouse_sql.map((item) => ({
|
||||
const promql: IPromQLQuery[] = queryState.promql.map((item) => ({
|
||||
...initialQueryPromQLData,
|
||||
...item,
|
||||
}));
|
||||
|
||||
const clickHouse: IClickHouseQuery[] = queryState.clickhouse_sql.map(
|
||||
(item) => ({
|
||||
...initialClickHouseData,
|
||||
...item,
|
||||
}))
|
||||
: initialQuery.clickhouse_sql;
|
||||
}),
|
||||
);
|
||||
|
||||
setCurrentQuery({
|
||||
clickhouse_sql: clickHouse,
|
||||
promql,
|
||||
builder: {
|
||||
...builder,
|
||||
queryData: builder.queryData.map((q) => ({
|
||||
...q,
|
||||
groupBy: q.groupBy.map(({ id: _, ...item }) => ({
|
||||
...item,
|
||||
id: createIdFromObjectFields(item, baseAutoCompleteIdKeysOrder),
|
||||
const type = newQueryType || EQueryType.QUERY_BUILDER;
|
||||
|
||||
const newQueryState: QueryState = {
|
||||
clickhouse_sql: clickHouse,
|
||||
promql,
|
||||
builder: {
|
||||
...builder,
|
||||
queryData: builder.queryData.map((q) => ({
|
||||
...q,
|
||||
groupBy: q.groupBy.map(({ id: _, ...item }) => ({
|
||||
...item,
|
||||
id: createIdFromObjectFields(item, baseAutoCompleteIdKeysOrder),
|
||||
})),
|
||||
aggregateAttribute: {
|
||||
...q.aggregateAttribute,
|
||||
id: createIdFromObjectFields(
|
||||
q.aggregateAttribute,
|
||||
baseAutoCompleteIdKeysOrder,
|
||||
),
|
||||
},
|
||||
})),
|
||||
aggregateAttribute: {
|
||||
...q.aggregateAttribute,
|
||||
id: createIdFromObjectFields(
|
||||
q.aggregateAttribute,
|
||||
baseAutoCompleteIdKeysOrder,
|
||||
),
|
||||
},
|
||||
})),
|
||||
},
|
||||
});
|
||||
},
|
||||
id: queryState.id,
|
||||
};
|
||||
|
||||
setQueryType(queryType || EQueryType.QUERY_BUILDER);
|
||||
}, []);
|
||||
const nextQuery: Query = { ...newQueryState, queryType: type };
|
||||
|
||||
setStagedQuery(nextQuery);
|
||||
setCurrentQuery(newQueryState);
|
||||
setQueryType(type);
|
||||
},
|
||||
[initialDataSource],
|
||||
);
|
||||
|
||||
const removeQueryBuilderEntityByIndex = useCallback(
|
||||
(type: keyof QueryBuilderData, index: number) => {
|
||||
@ -190,9 +189,11 @@ export function QueryBuilderProvider({
|
||||
const createNewBuilderQuery = useCallback(
|
||||
(queries: IBuilderQuery[]): IBuilderQuery => {
|
||||
const existNames = queries.map((item) => item.queryName);
|
||||
const initialBuilderQuery =
|
||||
initialQueryBuilderFormValuesMap[initialDataSource || DataSource.METRICS];
|
||||
|
||||
const newQuery: IBuilderQuery = {
|
||||
...initialQueryBuilderFormValues,
|
||||
...initialBuilderQuery,
|
||||
queryName: createNewBuilderItemName({ existNames, sourceNames: alphabet }),
|
||||
expression: createNewBuilderItemName({
|
||||
existNames,
|
||||
@ -381,7 +382,7 @@ export function QueryBuilderProvider({
|
||||
}, []);
|
||||
|
||||
const redirectWithQueryBuilderData = useCallback(
|
||||
(query: Partial<Query>) => {
|
||||
(query: Partial<Query>, searchParams?: Record<string, unknown>) => {
|
||||
const currentGeneratedQuery: Query = {
|
||||
queryType:
|
||||
!query.queryType || !Object.values(EQueryType).includes(query.queryType)
|
||||
@ -389,63 +390,84 @@ export function QueryBuilderProvider({
|
||||
: query.queryType,
|
||||
builder:
|
||||
!query.builder || query.builder.queryData.length === 0
|
||||
? initialQuery.builder
|
||||
? initialQueryState.builder
|
||||
: query.builder,
|
||||
promql:
|
||||
!query.promql || query.promql.length === 0
|
||||
? initialQuery.promql
|
||||
? initialQueryState.promql
|
||||
: query.promql,
|
||||
clickhouse_sql:
|
||||
!query.clickhouse_sql || query.clickhouse_sql.length === 0
|
||||
? initialQuery.clickhouse_sql
|
||||
? initialQueryState.clickhouse_sql
|
||||
: query.clickhouse_sql,
|
||||
id: uuid(),
|
||||
};
|
||||
|
||||
urlQuery.set(COMPOSITE_QUERY, JSON.stringify(currentGeneratedQuery));
|
||||
|
||||
const generatedUrl = `${location.pathname}?${urlQuery.toString()}`;
|
||||
if (searchParams) {
|
||||
Object.keys(searchParams).forEach((param) =>
|
||||
urlQuery.set(param, JSON.stringify(searchParams[param])),
|
||||
);
|
||||
}
|
||||
|
||||
const generatedUrl = `${location.pathname}?${urlQuery}`;
|
||||
|
||||
history.push(generatedUrl);
|
||||
},
|
||||
[history, location, urlQuery],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const compositeQuery = urlQuery.get(COMPOSITE_QUERY);
|
||||
if (!compositeQuery) return;
|
||||
const handleRunQuery = useCallback(() => {
|
||||
redirectWithQueryBuilderData({ ...currentQuery, queryType });
|
||||
}, [redirectWithQueryBuilderData, currentQuery, queryType]);
|
||||
|
||||
const newQuery: Query = JSON.parse(compositeQuery);
|
||||
const resetStagedQuery = useCallback(() => {
|
||||
setStagedQuery(null);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!compositeQueryParam) return;
|
||||
|
||||
if (stagedQuery && stagedQuery.id === compositeQueryParam.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { isValid, validData } = replaceIncorrectObjectFields(
|
||||
newQuery,
|
||||
initialQueryWithType,
|
||||
compositeQueryParam,
|
||||
initialQueriesMap.metrics,
|
||||
);
|
||||
|
||||
if (!isValid) {
|
||||
redirectWithQueryBuilderData(validData);
|
||||
} else {
|
||||
initQueryBuilderData(newQuery);
|
||||
initQueryBuilderData(compositeQueryParam);
|
||||
}
|
||||
}, [initQueryBuilderData, redirectWithQueryBuilderData, urlQuery]);
|
||||
|
||||
const query: Query = useMemo(() => ({ ...currentQuery, queryType }), [
|
||||
currentQuery,
|
||||
queryType,
|
||||
}, [
|
||||
initQueryBuilderData,
|
||||
redirectWithQueryBuilderData,
|
||||
compositeQueryParam,
|
||||
stagedQuery,
|
||||
]);
|
||||
|
||||
const query: Query = useMemo(
|
||||
() => ({
|
||||
...currentQuery,
|
||||
queryType,
|
||||
}),
|
||||
[currentQuery, queryType],
|
||||
);
|
||||
|
||||
const contextValues: QueryBuilderContextType = useMemo(
|
||||
() => ({
|
||||
currentQuery: query,
|
||||
stagedQuery,
|
||||
initialDataSource,
|
||||
panelType,
|
||||
resetQueryBuilderData,
|
||||
resetQueryBuilderInfo,
|
||||
handleSetQueryData,
|
||||
handleSetFormulaData,
|
||||
handleSetQueryItemData,
|
||||
handleSetPanelType,
|
||||
handleSetQueryType,
|
||||
initQueryBuilderData,
|
||||
setupInitialDataSource,
|
||||
removeQueryBuilderEntityByIndex,
|
||||
removeQueryTypeItemByIndex,
|
||||
@ -453,19 +475,18 @@ export function QueryBuilderProvider({
|
||||
addNewFormula,
|
||||
addNewQueryItem,
|
||||
redirectWithQueryBuilderData,
|
||||
handleRunQuery,
|
||||
resetStagedQuery,
|
||||
}),
|
||||
[
|
||||
query,
|
||||
stagedQuery,
|
||||
initialDataSource,
|
||||
panelType,
|
||||
resetQueryBuilderData,
|
||||
resetQueryBuilderInfo,
|
||||
handleSetQueryData,
|
||||
handleSetFormulaData,
|
||||
handleSetQueryItemData,
|
||||
handleSetPanelType,
|
||||
handleSetQueryType,
|
||||
initQueryBuilderData,
|
||||
setupInitialDataSource,
|
||||
removeQueryBuilderEntityByIndex,
|
||||
removeQueryTypeItemByIndex,
|
||||
@ -473,6 +494,8 @@ export function QueryBuilderProvider({
|
||||
addNewFormula,
|
||||
addNewQueryItem,
|
||||
redirectWithQueryBuilderData,
|
||||
handleRunQuery,
|
||||
resetStagedQuery,
|
||||
],
|
||||
);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import getDashboard from 'api/dashboard/get';
|
||||
import { initialQueryWithType, PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import { Dispatch } from 'redux';
|
||||
import AppActions from 'types/actions';
|
||||
@ -39,7 +39,7 @@ export const GetDashboard = ({
|
||||
panelTypes: graphType || PANEL_TYPES.TIME_SERIES,
|
||||
timePreferance: 'GLOBAL_TIME',
|
||||
title: '',
|
||||
query: initialQueryWithType,
|
||||
query: initialQueriesMap.metrics,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import getStep from 'lib/getStep';
|
||||
import { mapQueryDataToApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataToApi';
|
||||
import { isEmpty } from 'lodash-es';
|
||||
import store from 'store';
|
||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||
import { SuccessResponse } from 'types/api';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
|
@ -79,6 +79,7 @@ export interface Query {
|
||||
promql: IPromQLQuery[];
|
||||
builder: QueryBuilderData;
|
||||
clickhouse_sql: IClickHouseQuery[];
|
||||
id: string;
|
||||
}
|
||||
|
||||
export type QueryState = Omit<Query, 'queryType'>;
|
||||
|
@ -154,10 +154,9 @@ export type QueryBuilderData = {
|
||||
|
||||
export type QueryBuilderContextType = {
|
||||
currentQuery: Query;
|
||||
stagedQuery: Query | null;
|
||||
initialDataSource: DataSource | null;
|
||||
panelType: GRAPH_TYPES;
|
||||
resetQueryBuilderData: () => void;
|
||||
resetQueryBuilderInfo: () => void;
|
||||
handleSetQueryData: (index: number, queryData: IBuilderQuery) => void;
|
||||
handleSetFormulaData: (index: number, formulaData: IBuilderFormula) => void;
|
||||
handleSetQueryItemData: (
|
||||
@ -166,8 +165,6 @@ export type QueryBuilderContextType = {
|
||||
newQueryData: IPromQLQuery | IClickHouseQuery,
|
||||
) => void;
|
||||
handleSetPanelType: (newPanelType: GRAPH_TYPES) => void;
|
||||
handleSetQueryType: (newQueryType: EQueryType) => void;
|
||||
initQueryBuilderData: (query: Partial<Query>) => void;
|
||||
setupInitialDataSource: (newInitialDataSource: DataSource | null) => void;
|
||||
removeQueryBuilderEntityByIndex: (
|
||||
type: keyof QueryBuilderData,
|
||||
@ -180,7 +177,12 @@ export type QueryBuilderContextType = {
|
||||
addNewBuilderQuery: () => void;
|
||||
addNewFormula: () => void;
|
||||
addNewQueryItem: (type: EQueryType.PROM | EQueryType.CLICKHOUSE) => void;
|
||||
redirectWithQueryBuilderData: (query: Query) => void;
|
||||
redirectWithQueryBuilderData: (
|
||||
query: Query,
|
||||
searchParams?: Record<string, unknown>,
|
||||
) => void;
|
||||
handleRunQuery: () => void;
|
||||
resetStagedQuery: () => void;
|
||||
};
|
||||
|
||||
export type QueryAdditionalFilter = {
|
||||
|
@ -69,6 +69,7 @@ export const routePermission: Record<keyof typeof ROUTES, ROLES[]> = {
|
||||
USAGE_EXPLORER: ['ADMIN', 'EDITOR', 'VIEWER'],
|
||||
VERSION: ['ADMIN', 'EDITOR', 'VIEWER'],
|
||||
LOGS: ['ADMIN', 'EDITOR', 'VIEWER'],
|
||||
LOGS_EXPLORER: ['ADMIN', 'EDITOR', 'VIEWER'],
|
||||
LIST_LICENSES: ['ADMIN'],
|
||||
TRACE_EXPLORER: ['ADMIN', 'EDITOR', 'VIEWER'],
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user