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