mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-13 06:29:04 +08:00
feat: resource attribute is added in the exception (#2491)
* feat: resource attribute is added in the exception * fix: build is fixed * chore: methods is updated to post * fix: build is fixed * fix: listErrors, countErrors API request body * chore: type of the function is updated * chore: convertRawQueriesToTraceSelectedTags is updated * fix: resource attribute is updated * chore: selected tags is updated * feat: key is updated --------- Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
This commit is contained in:
parent
12e56932ee
commit
99ed314fc9
@ -4,6 +4,7 @@ import Spinner from 'components/Spinner';
|
|||||||
import AppLayout from 'container/AppLayout';
|
import AppLayout from 'container/AppLayout';
|
||||||
import { useThemeConfig } from 'hooks/useDarkMode';
|
import { useThemeConfig } from 'hooks/useDarkMode';
|
||||||
import { NotificationProvider } from 'hooks/useNotifications';
|
import { NotificationProvider } from 'hooks/useNotifications';
|
||||||
|
import { ResourceProvider } from 'hooks/useResourceAttribute';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
import { QueryBuilderProvider } from 'providers/QueryBuilder';
|
import { QueryBuilderProvider } from 'providers/QueryBuilder';
|
||||||
import React, { Suspense } from 'react';
|
import React, { Suspense } from 'react';
|
||||||
@ -17,30 +18,32 @@ function App(): JSX.Element {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfigProvider theme={themeConfig}>
|
<ConfigProvider theme={themeConfig}>
|
||||||
<NotificationProvider>
|
<Router history={history}>
|
||||||
<Router history={history}>
|
<NotificationProvider>
|
||||||
<PrivateRoute>
|
<PrivateRoute>
|
||||||
<QueryBuilderProvider>
|
<ResourceProvider>
|
||||||
<AppLayout>
|
<QueryBuilderProvider>
|
||||||
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
|
<AppLayout>
|
||||||
<Switch>
|
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
|
||||||
{routes.map(({ path, component, exact }) => (
|
<Switch>
|
||||||
<Route
|
{routes.map(({ path, component, exact }) => (
|
||||||
key={`${path}`}
|
<Route
|
||||||
exact={exact}
|
key={`${path}`}
|
||||||
path={path}
|
exact={exact}
|
||||||
component={component}
|
path={path}
|
||||||
/>
|
component={component}
|
||||||
))}
|
/>
|
||||||
|
))}
|
||||||
|
|
||||||
<Route path="*" component={NotFound} />
|
<Route path="*" component={NotFound} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</AppLayout>
|
</AppLayout>
|
||||||
</QueryBuilderProvider>
|
</QueryBuilderProvider>
|
||||||
|
</ResourceProvider>
|
||||||
</PrivateRoute>
|
</PrivateRoute>
|
||||||
</Router>
|
</NotificationProvider>
|
||||||
</NotificationProvider>
|
</Router>
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import axios from 'api';
|
import axios from 'api';
|
||||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import createQueryParams from 'lib/createQueryParams';
|
|
||||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||||
import { PayloadProps, Props } from 'types/api/errors/getAll';
|
import { PayloadProps, Props } from 'types/api/errors/getAll';
|
||||||
|
|
||||||
@ -9,11 +8,17 @@ const getAll = async (
|
|||||||
props: Props,
|
props: Props,
|
||||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await axios.post(`/listErrors`, {
|
||||||
`/listErrors?${createQueryParams({
|
start: `${props.start}`,
|
||||||
...props,
|
end: `${props.end}`,
|
||||||
})}`,
|
order: props.order,
|
||||||
);
|
orderParam: props.orderParam,
|
||||||
|
limit: props.limit,
|
||||||
|
offset: props.offset,
|
||||||
|
exceptionType: props.exceptionType,
|
||||||
|
serviceName: props.serviceName,
|
||||||
|
tags: props.tags,
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import axios from 'api';
|
import axios from 'api';
|
||||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import createQueryParams from 'lib/createQueryParams';
|
|
||||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||||
import { PayloadProps, Props } from 'types/api/errors/getErrorCounts';
|
import { PayloadProps, Props } from 'types/api/errors/getErrorCounts';
|
||||||
|
|
||||||
@ -9,11 +8,13 @@ const getErrorCounts = async (
|
|||||||
props: Props,
|
props: Props,
|
||||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await axios.post(`/countErrors`, {
|
||||||
`/countErrors?${createQueryParams({
|
start: `${props.start}`,
|
||||||
...props,
|
end: `${props.end}`,
|
||||||
})}`,
|
exceptionType: props.exceptionType,
|
||||||
);
|
serviceName: props.serviceName,
|
||||||
|
tags: props.tags,
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
|
@ -10,7 +10,7 @@ const getSpans = async (
|
|||||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||||
try {
|
try {
|
||||||
const updatedSelectedTags = props.selectedTags.map((e) => ({
|
const updatedSelectedTags = props.selectedTags.map((e) => ({
|
||||||
Key: e.Key,
|
Key: `${e.Key}.(string)`,
|
||||||
Operator: e.Operator,
|
Operator: e.Operator,
|
||||||
StringValues: e.StringValues,
|
StringValues: e.StringValues,
|
||||||
NumberValues: e.NumberValues,
|
NumberValues: e.NumberValues,
|
||||||
|
@ -28,7 +28,7 @@ const getSpanAggregate = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
const updatedSelectedTags = props.selectedTags.map((e) => ({
|
const updatedSelectedTags = props.selectedTags.map((e) => ({
|
||||||
Key: e.Key,
|
Key: `${e.Key}.(string)`,
|
||||||
Operator: e.Operator,
|
Operator: e.Operator,
|
||||||
StringValues: e.StringValues,
|
StringValues: e.StringValues,
|
||||||
NumberValues: e.NumberValues,
|
NumberValues: e.NumberValues,
|
||||||
|
@ -18,6 +18,8 @@ import { ResizeTable } from 'components/ResizeTable';
|
|||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
|
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||||
|
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
||||||
import useUrlQuery from 'hooks/useUrlQuery';
|
import useUrlQuery from 'hooks/useUrlQuery';
|
||||||
import createQueryParams from 'lib/createQueryParams';
|
import createQueryParams from 'lib/createQueryParams';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
@ -93,9 +95,11 @@ function AllErrors(): JSX.Element {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { queries } = useResourceAttribute();
|
||||||
|
|
||||||
const [{ isLoading, data }, errorCountResponse] = useQueries([
|
const [{ isLoading, data }, errorCountResponse] = useQueries([
|
||||||
{
|
{
|
||||||
queryKey: ['getAllErrors', updatedPath, maxTime, minTime],
|
queryKey: ['getAllErrors', updatedPath, maxTime, minTime, queries],
|
||||||
queryFn: (): Promise<SuccessResponse<PayloadProps> | ErrorResponse> =>
|
queryFn: (): Promise<SuccessResponse<PayloadProps> | ErrorResponse> =>
|
||||||
getAll({
|
getAll({
|
||||||
end: maxTime,
|
end: maxTime,
|
||||||
@ -106,6 +110,7 @@ function AllErrors(): JSX.Element {
|
|||||||
orderParam: getUpdatedParams,
|
orderParam: getUpdatedParams,
|
||||||
exceptionType: getUpdatedExceptionType,
|
exceptionType: getUpdatedExceptionType,
|
||||||
serviceName: getUpdatedServiceName,
|
serviceName: getUpdatedServiceName,
|
||||||
|
tags: convertRawQueriesToTraceSelectedTags(queries),
|
||||||
}),
|
}),
|
||||||
enabled: !loading,
|
enabled: !loading,
|
||||||
},
|
},
|
||||||
@ -116,6 +121,7 @@ function AllErrors(): JSX.Element {
|
|||||||
minTime,
|
minTime,
|
||||||
getUpdatedExceptionType,
|
getUpdatedExceptionType,
|
||||||
getUpdatedServiceName,
|
getUpdatedServiceName,
|
||||||
|
queries,
|
||||||
],
|
],
|
||||||
queryFn: (): Promise<ErrorResponse | SuccessResponse<number>> =>
|
queryFn: (): Promise<ErrorResponse | SuccessResponse<number>> =>
|
||||||
getErrorCounts({
|
getErrorCounts({
|
||||||
@ -123,6 +129,7 @@ function AllErrors(): JSX.Element {
|
|||||||
start: minTime,
|
start: minTime,
|
||||||
exceptionType: getUpdatedExceptionType,
|
exceptionType: getUpdatedExceptionType,
|
||||||
serviceName: getUpdatedServiceName,
|
serviceName: getUpdatedServiceName,
|
||||||
|
tags: convertRawQueriesToTraceSelectedTags(queries),
|
||||||
}),
|
}),
|
||||||
enabled: !loading,
|
enabled: !loading,
|
||||||
},
|
},
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
import { convertMetricKeyToTrace } from 'lib/resourceAttributes';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { QueryChipContainer, QueryChipItem } from './styles';
|
|
||||||
import { IResourceAttributeQuery } from './types';
|
|
||||||
|
|
||||||
interface IQueryChipProps {
|
|
||||||
queryData: IResourceAttributeQuery;
|
|
||||||
onClose: (id: string) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function QueryChip({
|
|
||||||
queryData,
|
|
||||||
onClose,
|
|
||||||
disabled,
|
|
||||||
}: IQueryChipProps): JSX.Element {
|
|
||||||
return (
|
|
||||||
<QueryChipContainer>
|
|
||||||
<QueryChipItem>{convertMetricKeyToTrace(queryData.tagKey)}</QueryChipItem>
|
|
||||||
<QueryChipItem>{queryData.operator}</QueryChipItem>
|
|
||||||
<QueryChipItem
|
|
||||||
closable={!disabled}
|
|
||||||
onClose={(): void => {
|
|
||||||
if (!disabled) onClose(queryData.id);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{queryData.tagValue.join(', ')}
|
|
||||||
</QueryChipItem>
|
|
||||||
</QueryChipContainer>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
import { createMachine } from 'xstate';
|
|
||||||
|
|
||||||
export const ResourceAttributesFilterMachine =
|
|
||||||
/** @xstate-layout N4IgpgJg5mDOIC5QBECGsAWAjA9qgThAAQDKYBAxhkQIIB2xAYgJYA2ALmPgHQAqqUANJgAngGIAcgFEAGr0SgADjljN2zHHQUgAHogAcAFgAM3AOz6ATAEYAzJdsA2Y4cOWAnABoQIxAFpDR2tuQ319AFYTcKdbFycAX3jvNExcAmIySmp6JjZOHn4hUTFNACFWAFd8bWVVdU1tPQQzY1MXY2tDdzNHM3dHd0NvXwR7biMTa313S0i+63DE5PRsPEJScnwqWgYiFg4uPgFhcQAlKRIpeSQQWrUNLRumx3Czbg8TR0sbS31jfUcw38fW47gBHmm4XCVms3SWIBSq3SGyyO1yBx4AHlFFxUOwcPhJLJrkoVPcGk9ENYFuF3i5YR0wtEHECEAEgiEmV8zH1DLYzHZ4Yi0utMltsrt9vluNjcfjCWVKtUbnd6o9QE1rMYBtxbGFvsZ3NrZj1WdYOfotUZLX0XEFHEKViKMpttjk9nlDrL8HiCWJzpcSbcyWrGoh3NCQj0zK53P1ph1WeFLLqnJZ2s5vmZLA6kginWsXaj3VLDoUAGqoSpgEp0cpVGohh5hhDWDy0sz8zruakzamWVm-Qyg362V5-AZOayO1KFlHitEejFHKCV6v+i5XRt1ZuU1s52zjNOOaZfdOWIY+RDZ0Hc6ZmKEXqyLPPCudit2Sz08ACSEFYNbSHI27kuquiIOEjiONwjJgrM3RWJYZisgEIJgnYPTmuEdi2OaiR5nQOAQHA2hvsiH4Sui0qFCcIGhnuLSmP0YJuJ2xjJsmKELG8XZTK0tjdHG06vgW5GupRS7St6vrKqSO4UhqVL8TBWp8o4eqdl0A5Xmy3G6gK56-B4uERDOSKiuJi6lgUAhrhUYB0buimtrEKZBDYrxaS0OZca8+ltheybOI4hivGZzrzp+VGHH+AGOQp4EIHy+ghNYnawtG4TsbYvk8QKfHGAJfQ9uF76WSW37xWBTSGJ0qXpd0vRZdEKGPqC2YeO2-zfO4+HxEAA */
|
|
||||||
createMachine({
|
|
||||||
tsTypes: {} as import('./ResourceAttributesFilter.Machine.typegen').Typegen0,
|
|
||||||
initial: 'Idle',
|
|
||||||
states: {
|
|
||||||
TagKey: {
|
|
||||||
on: {
|
|
||||||
NEXT: {
|
|
||||||
actions: 'onSelectOperator',
|
|
||||||
target: 'Operator',
|
|
||||||
},
|
|
||||||
onBlur: {
|
|
||||||
actions: 'onBlurPurge',
|
|
||||||
target: 'Idle',
|
|
||||||
},
|
|
||||||
RESET: {
|
|
||||||
target: 'Idle',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Operator: {
|
|
||||||
on: {
|
|
||||||
NEXT: {
|
|
||||||
actions: 'onSelectTagValue',
|
|
||||||
target: 'TagValue',
|
|
||||||
},
|
|
||||||
onBlur: {
|
|
||||||
actions: 'onBlurPurge',
|
|
||||||
target: 'Idle',
|
|
||||||
},
|
|
||||||
RESET: {
|
|
||||||
target: 'Idle',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TagValue: {
|
|
||||||
on: {
|
|
||||||
onBlur: {
|
|
||||||
actions: ['onValidateQuery', 'onBlurPurge'],
|
|
||||||
target: 'Idle',
|
|
||||||
},
|
|
||||||
RESET: {
|
|
||||||
target: 'Idle',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Idle: {
|
|
||||||
on: {
|
|
||||||
NEXT: {
|
|
||||||
actions: 'onSelectTagKey',
|
|
||||||
description: 'Select Category',
|
|
||||||
target: 'TagKey',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
id: 'Dashboard Search And Filter',
|
|
||||||
});
|
|
@ -1,32 +0,0 @@
|
|||||||
// This file was automatically generated. Edits will be overwritten
|
|
||||||
|
|
||||||
export interface Typegen0 {
|
|
||||||
'@@xstate/typegen': true;
|
|
||||||
eventsCausingActions: {
|
|
||||||
onSelectOperator: 'NEXT';
|
|
||||||
onBlurPurge: 'onBlur';
|
|
||||||
onSelectTagValue: 'NEXT';
|
|
||||||
onValidateQuery: 'onBlur';
|
|
||||||
onSelectTagKey: 'NEXT';
|
|
||||||
};
|
|
||||||
internalEvents: {
|
|
||||||
'xstate.init': { type: 'xstate.init' };
|
|
||||||
};
|
|
||||||
invokeSrcNameMap: {};
|
|
||||||
missingImplementations: {
|
|
||||||
actions:
|
|
||||||
| 'onSelectOperator'
|
|
||||||
| 'onBlurPurge'
|
|
||||||
| 'onSelectTagValue'
|
|
||||||
| 'onValidateQuery'
|
|
||||||
| 'onSelectTagKey';
|
|
||||||
services: never;
|
|
||||||
guards: never;
|
|
||||||
delays: never;
|
|
||||||
};
|
|
||||||
eventsCausingServices: {};
|
|
||||||
eventsCausingGuards: {};
|
|
||||||
eventsCausingDelays: {};
|
|
||||||
matchesStates: 'TagKey' | 'Operator' | 'TagValue' | 'Idle';
|
|
||||||
tags: never;
|
|
||||||
}
|
|
@ -1,219 +0,0 @@
|
|||||||
import { CloseCircleFilled } from '@ant-design/icons';
|
|
||||||
import { useMachine } from '@xstate/react';
|
|
||||||
import { Button, Select, Spin } from 'antd';
|
|
||||||
import ROUTES from 'constants/routes';
|
|
||||||
import history from 'lib/history';
|
|
||||||
import { convertMetricKeyToTrace } from 'lib/resourceAttributes';
|
|
||||||
import { map } from 'lodash-es';
|
|
||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
|
||||||
import { ResetInitialData } from 'store/actions/metrics/resetInitialData';
|
|
||||||
import { SetResourceAttributeQueries } from 'store/actions/metrics/setResourceAttributeQueries';
|
|
||||||
import { AppState } from 'store/reducers';
|
|
||||||
import MetricReducer from 'types/reducer/metrics';
|
|
||||||
import { v4 as uuid } from 'uuid';
|
|
||||||
|
|
||||||
import QueryChip from './QueryChip';
|
|
||||||
import { ResourceAttributesFilterMachine } from './ResourceAttributesFilter.Machine';
|
|
||||||
import { QueryChipItem, SearchContainer } from './styles';
|
|
||||||
import { IOption, IResourceAttributeQuery } from './types';
|
|
||||||
import { createQuery, GetTagKeys, GetTagValues, OperatorSchema } from './utils';
|
|
||||||
|
|
||||||
function ResourceAttributesFilter(): JSX.Element | null {
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
const [disabled, setDisabled] = useState(
|
|
||||||
!(history.location.pathname === ROUTES.APPLICATION),
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const unListen = history.listen(({ pathname }) => {
|
|
||||||
setDisabled(!(pathname === ROUTES.APPLICATION));
|
|
||||||
});
|
|
||||||
return (): void => {
|
|
||||||
if (!history.location.pathname.startsWith(`${ROUTES.APPLICATION}/`)) {
|
|
||||||
dispatch(ResetInitialData());
|
|
||||||
}
|
|
||||||
unListen();
|
|
||||||
};
|
|
||||||
}, [dispatch]);
|
|
||||||
|
|
||||||
const { resourceAttributeQueries } = useSelector<AppState, MetricReducer>(
|
|
||||||
(state) => state.metrics,
|
|
||||||
);
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
const [selectedValues, setSelectedValues] = useState<string[]>([]);
|
|
||||||
const [staging, setStaging] = useState<string[]>([]);
|
|
||||||
const [queries, setQueries] = useState<IResourceAttributeQuery[]>([]);
|
|
||||||
const [optionsData, setOptionsData] = useState<{
|
|
||||||
mode: undefined | 'tags' | 'multiple';
|
|
||||||
options: IOption[];
|
|
||||||
}>({
|
|
||||||
mode: undefined,
|
|
||||||
options: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const dispatchQueries = (updatedQueries: IResourceAttributeQuery[]): void => {
|
|
||||||
dispatch(SetResourceAttributeQueries(updatedQueries));
|
|
||||||
};
|
|
||||||
const handleLoading = (isLoading: boolean): void => {
|
|
||||||
setLoading(isLoading);
|
|
||||||
if (isLoading) {
|
|
||||||
setOptionsData({ mode: undefined, options: [] });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const [state, send] = useMachine(ResourceAttributesFilterMachine, {
|
|
||||||
actions: {
|
|
||||||
onSelectTagKey: () => {
|
|
||||||
handleLoading(true);
|
|
||||||
GetTagKeys()
|
|
||||||
.then((tagKeys) => setOptionsData({ options: tagKeys, mode: undefined }))
|
|
||||||
.finally(() => {
|
|
||||||
handleLoading(false);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onSelectOperator: () => {
|
|
||||||
setOptionsData({ options: OperatorSchema, mode: undefined });
|
|
||||||
},
|
|
||||||
onSelectTagValue: () => {
|
|
||||||
handleLoading(true);
|
|
||||||
|
|
||||||
GetTagValues(staging[0])
|
|
||||||
.then((tagValuesOptions) =>
|
|
||||||
setOptionsData({ options: tagValuesOptions, mode: 'multiple' }),
|
|
||||||
)
|
|
||||||
.finally(() => {
|
|
||||||
handleLoading(false);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onBlurPurge: () => {
|
|
||||||
setSelectedValues([]);
|
|
||||||
setStaging([]);
|
|
||||||
},
|
|
||||||
onValidateQuery: (): void => {
|
|
||||||
if (staging.length < 2 || selectedValues.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const generatedQuery = createQuery([...staging, selectedValues]);
|
|
||||||
if (generatedQuery) {
|
|
||||||
dispatchQueries([...queries, generatedQuery]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setQueries(resourceAttributeQueries);
|
|
||||||
}, [resourceAttributeQueries]);
|
|
||||||
|
|
||||||
const handleFocus = (): void => {
|
|
||||||
if (state.value === 'Idle') {
|
|
||||||
send('NEXT');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleBlur = (): void => {
|
|
||||||
send('onBlur');
|
|
||||||
};
|
|
||||||
const handleChange = (value: never): void => {
|
|
||||||
if (!optionsData.mode) {
|
|
||||||
setStaging((prevStaging) => [...prevStaging, value]);
|
|
||||||
setSelectedValues([]);
|
|
||||||
send('NEXT');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setSelectedValues([...value]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClose = (id: string): void => {
|
|
||||||
dispatchQueries(queries.filter((queryData) => queryData.id !== id));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClearAll = (): void => {
|
|
||||||
send('RESET');
|
|
||||||
dispatchQueries([]);
|
|
||||||
setStaging([]);
|
|
||||||
setSelectedValues([]);
|
|
||||||
};
|
|
||||||
const disabledAndEmpty = !!(
|
|
||||||
!queries.length &&
|
|
||||||
!staging.length &&
|
|
||||||
!selectedValues.length &&
|
|
||||||
disabled
|
|
||||||
);
|
|
||||||
const disabledOrEmpty = !!(
|
|
||||||
queries.length ||
|
|
||||||
staging.length ||
|
|
||||||
selectedValues.length ||
|
|
||||||
disabled
|
|
||||||
);
|
|
||||||
|
|
||||||
if (disabledAndEmpty) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SearchContainer disabled={disabled}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
maxWidth: disabled ? '100%' : '70%',
|
|
||||||
display: 'flex',
|
|
||||||
overflowX: 'auto',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{map(
|
|
||||||
queries,
|
|
||||||
(query): JSX.Element => (
|
|
||||||
<QueryChip
|
|
||||||
disabled={disabled}
|
|
||||||
key={query.id}
|
|
||||||
queryData={query}
|
|
||||||
onClose={handleClose}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
{map(staging, (item, idx) => (
|
|
||||||
<QueryChipItem key={uuid()}>
|
|
||||||
{idx === 0 ? convertMetricKeyToTrace(item) : item}
|
|
||||||
</QueryChipItem>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
{!disabled && (
|
|
||||||
<Select
|
|
||||||
placeholder={
|
|
||||||
disabledOrEmpty ? '' : 'Search and Filter based on resource attributes.'
|
|
||||||
}
|
|
||||||
disabled={disabled}
|
|
||||||
onChange={handleChange}
|
|
||||||
bordered={false}
|
|
||||||
value={selectedValues as never}
|
|
||||||
style={{ flex: 1 }}
|
|
||||||
options={optionsData.options}
|
|
||||||
mode={optionsData?.mode}
|
|
||||||
showArrow={false}
|
|
||||||
onFocus={handleFocus}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
notFoundContent={
|
|
||||||
loading ? (
|
|
||||||
<span>
|
|
||||||
<Spin size="small" /> Loading...{' '}
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
<span>
|
|
||||||
No resource attributes available to filter. Please refer docs to send
|
|
||||||
attributes.
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{(queries.length || staging.length || selectedValues.length) && !disabled ? (
|
|
||||||
<Button onClick={handleClearAll} icon={<CloseCircleFilled />} type="text" />
|
|
||||||
) : null}
|
|
||||||
</SearchContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ResourceAttributesFilter;
|
|
@ -1,11 +0,0 @@
|
|||||||
export interface IOption {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IResourceAttributeQuery {
|
|
||||||
id: string;
|
|
||||||
tagKey: string;
|
|
||||||
operator: string;
|
|
||||||
tagValue: string[];
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
import {
|
|
||||||
getResourceAttributesTagKeys,
|
|
||||||
getResourceAttributesTagValues,
|
|
||||||
} from 'api/metrics/getResourceAttributes';
|
|
||||||
import { OperatorConversions } from 'constants/resourceAttributes';
|
|
||||||
import { convertMetricKeyToTrace } from 'lib/resourceAttributes';
|
|
||||||
import { v4 as uuid } from 'uuid';
|
|
||||||
|
|
||||||
import { IOption, IResourceAttributeQuery } from './types';
|
|
||||||
|
|
||||||
export const OperatorSchema: IOption[] = OperatorConversions.map(
|
|
||||||
(operator) => ({
|
|
||||||
label: operator.label,
|
|
||||||
value: operator.label,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const GetTagKeys = async (): Promise<IOption[]> => {
|
|
||||||
// if (TagKeysCache) {
|
|
||||||
// return new Promise((resolve) => {
|
|
||||||
// resolve(TagKeysCache);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
const { payload } = await getResourceAttributesTagKeys({
|
|
||||||
metricName: 'signoz_calls_total',
|
|
||||||
match: 'resource_',
|
|
||||||
});
|
|
||||||
if (!payload || !payload?.data) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return payload.data.map((tagKey: string) => ({
|
|
||||||
label: convertMetricKeyToTrace(tagKey),
|
|
||||||
value: tagKey,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const GetTagValues = async (tagKey: string): Promise<IOption[]> => {
|
|
||||||
const { payload } = await getResourceAttributesTagValues({
|
|
||||||
tagKey,
|
|
||||||
metricName: 'signoz_calls_total',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!payload || !payload?.data) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return payload.data.map((tagValue: string) => ({
|
|
||||||
label: tagValue,
|
|
||||||
value: tagValue,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createQuery = (
|
|
||||||
selectedItems: Array<string | string[]> = [],
|
|
||||||
): IResourceAttributeQuery | null => {
|
|
||||||
if (selectedItems.length === 3) {
|
|
||||||
return {
|
|
||||||
id: uuid().slice(0, 8),
|
|
||||||
tagKey: selectedItems[0] as string,
|
|
||||||
operator: selectedItems[1] as string,
|
|
||||||
tagValue: selectedItems[2] as string[],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
@ -4,16 +4,14 @@ import {
|
|||||||
databaseCallsAvgDuration,
|
databaseCallsAvgDuration,
|
||||||
databaseCallsRPS,
|
databaseCallsRPS,
|
||||||
} from 'container/MetricsApplication/MetricsPageQueries/DBCallQueries';
|
} from 'container/MetricsApplication/MetricsPageQueries/DBCallQueries';
|
||||||
|
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||||
import {
|
import {
|
||||||
convertRawQueriesToTraceSelectedTags,
|
convertRawQueriesToTraceSelectedTags,
|
||||||
resourceAttributesToTagFilterItems,
|
resourceAttributesToTagFilterItems,
|
||||||
} from 'lib/resourceAttributes';
|
} from 'hooks/useResourceAttribute/utils';
|
||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { AppState } from 'store/reducers';
|
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
import MetricReducer from 'types/reducer/metrics';
|
|
||||||
|
|
||||||
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
|
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
|
||||||
import { Button } from './styles';
|
import { Button } from './styles';
|
||||||
@ -26,22 +24,19 @@ import {
|
|||||||
function DBCall({ getWidgetQueryBuilder }: DBCallProps): JSX.Element {
|
function DBCall({ getWidgetQueryBuilder }: DBCallProps): JSX.Element {
|
||||||
const { servicename } = useParams<{ servicename?: string }>();
|
const { servicename } = useParams<{ servicename?: string }>();
|
||||||
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
||||||
const { resourceAttributeQueries } = useSelector<AppState, MetricReducer>(
|
const { queries } = useResourceAttribute();
|
||||||
(state) => state.metrics,
|
|
||||||
);
|
|
||||||
const tagFilterItems = useMemo(
|
const tagFilterItems = useMemo(
|
||||||
() => resourceAttributesToTagFilterItems(resourceAttributeQueries) || [],
|
() => resourceAttributesToTagFilterItems(queries) || [],
|
||||||
[resourceAttributeQueries],
|
[queries],
|
||||||
);
|
);
|
||||||
const selectedTraceTags: string = useMemo(
|
const selectedTraceTags: string = useMemo(
|
||||||
() =>
|
() =>
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
convertRawQueriesToTraceSelectedTags(resourceAttributeQueries).concat(
|
convertRawQueriesToTraceSelectedTags(queries).concat(...dbSystemTags) || [],
|
||||||
...dbSystemTags,
|
|
||||||
) || [],
|
|
||||||
),
|
),
|
||||||
[resourceAttributeQueries],
|
[queries],
|
||||||
);
|
);
|
||||||
|
|
||||||
const legend = '{{db_system}}';
|
const legend = '{{db_system}}';
|
||||||
|
|
||||||
const databaseCallsRPSWidget = useMemo(
|
const databaseCallsRPSWidget = useMemo(
|
||||||
|
@ -6,16 +6,14 @@ import {
|
|||||||
externalCallErrorPercent,
|
externalCallErrorPercent,
|
||||||
externalCallRpsByAddress,
|
externalCallRpsByAddress,
|
||||||
} from 'container/MetricsApplication/MetricsPageQueries/ExternalQueries';
|
} from 'container/MetricsApplication/MetricsPageQueries/ExternalQueries';
|
||||||
|
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||||
import {
|
import {
|
||||||
convertRawQueriesToTraceSelectedTags,
|
convertRawQueriesToTraceSelectedTags,
|
||||||
resourceAttributesToTagFilterItems,
|
resourceAttributesToTagFilterItems,
|
||||||
} from 'lib/resourceAttributes';
|
} from 'hooks/useResourceAttribute/utils';
|
||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { AppState } from 'store/reducers';
|
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
import MetricReducer from 'types/reducer/metrics';
|
|
||||||
|
|
||||||
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
|
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
|
||||||
import { legend } from './constant';
|
import { legend } from './constant';
|
||||||
@ -26,13 +24,11 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
|
|||||||
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
||||||
|
|
||||||
const { servicename } = useParams<{ servicename?: string }>();
|
const { servicename } = useParams<{ servicename?: string }>();
|
||||||
const { resourceAttributeQueries } = useSelector<AppState, MetricReducer>(
|
const { queries } = useResourceAttribute();
|
||||||
(state) => state.metrics,
|
|
||||||
);
|
|
||||||
|
|
||||||
const tagFilterItems = useMemo(
|
const tagFilterItems = useMemo(
|
||||||
() => resourceAttributesToTagFilterItems(resourceAttributeQueries) || [],
|
() => resourceAttributesToTagFilterItems(queries) || [],
|
||||||
[resourceAttributeQueries],
|
[queries],
|
||||||
);
|
);
|
||||||
|
|
||||||
const externalCallErrorWidget = useMemo(
|
const externalCallErrorWidget = useMemo(
|
||||||
@ -51,11 +47,8 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const selectedTraceTags = useMemo(
|
const selectedTraceTags = useMemo(
|
||||||
() =>
|
() => JSON.stringify(convertRawQueriesToTraceSelectedTags(queries) || []),
|
||||||
JSON.stringify(
|
[queries],
|
||||||
convertRawQueriesToTraceSelectedTags(resourceAttributeQueries) || [],
|
|
||||||
),
|
|
||||||
[resourceAttributeQueries],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const externalCallDurationWidget = useMemo(
|
const externalCallDurationWidget = useMemo(
|
||||||
|
@ -3,13 +3,14 @@ import Graph from 'components/Graph';
|
|||||||
import { METRICS_PAGE_QUERY_PARAM } from 'constants/query';
|
import { METRICS_PAGE_QUERY_PARAM } from 'constants/query';
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
import FullView from 'container/GridGraphLayout/Graph/FullView/index.metricsBuilder';
|
import FullView from 'container/GridGraphLayout/Graph/FullView/index.metricsBuilder';
|
||||||
import convertToNanoSecondsToSecond from 'lib/convertToNanoSecondsToSecond';
|
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||||
import { colors } from 'lib/getRandomColor';
|
|
||||||
import history from 'lib/history';
|
|
||||||
import {
|
import {
|
||||||
convertRawQueriesToTraceSelectedTags,
|
convertRawQueriesToTraceSelectedTags,
|
||||||
resourceAttributesToTagFilterItems,
|
resourceAttributesToTagFilterItems,
|
||||||
} from 'lib/resourceAttributes';
|
} from 'hooks/useResourceAttribute/utils';
|
||||||
|
import convertToNanoSecondsToSecond from 'lib/convertToNanoSecondsToSecond';
|
||||||
|
import { colors } from 'lib/getRandomColor';
|
||||||
|
import history from 'lib/history';
|
||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
@ -54,20 +55,20 @@ function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element {
|
|||||||
[handleSetTimeStamp],
|
[handleSetTimeStamp],
|
||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const { topOperations, serviceOverview, topLevelOperations } = useSelector<
|
||||||
topOperations,
|
AppState,
|
||||||
serviceOverview,
|
MetricReducer
|
||||||
resourceAttributeQueries,
|
>((state) => state.metrics);
|
||||||
topLevelOperations,
|
|
||||||
} = useSelector<AppState, MetricReducer>((state) => state.metrics);
|
const { queries } = useResourceAttribute();
|
||||||
|
|
||||||
const selectedTraceTags: string = JSON.stringify(
|
const selectedTraceTags: string = JSON.stringify(
|
||||||
convertRawQueriesToTraceSelectedTags(resourceAttributeQueries) || [],
|
convertRawQueriesToTraceSelectedTags(queries) || [],
|
||||||
);
|
);
|
||||||
|
|
||||||
const tagFilterItems = useMemo(
|
const tagFilterItems = useMemo(
|
||||||
() => resourceAttributesToTagFilterItems(resourceAttributeQueries) || [],
|
() => resourceAttributesToTagFilterItems(queries) || [],
|
||||||
[resourceAttributeQueries],
|
[queries],
|
||||||
);
|
);
|
||||||
|
|
||||||
const operationPerSecWidget = useMemo(
|
const operationPerSecWidget = useMemo(
|
||||||
|
@ -3,25 +3,23 @@ import { ColumnsType } from 'antd/lib/table';
|
|||||||
import { ResizeTable } from 'components/ResizeTable';
|
import { ResizeTable } from 'components/ResizeTable';
|
||||||
import { METRICS_PAGE_QUERY_PARAM } from 'constants/query';
|
import { METRICS_PAGE_QUERY_PARAM } from 'constants/query';
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
|
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||||
|
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
import { convertRawQueriesToTraceSelectedTags } from 'lib/resourceAttributes';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
import MetricReducer from 'types/reducer/metrics';
|
|
||||||
|
|
||||||
function TopOperationsTable(props: TopOperationsTableProps): JSX.Element {
|
function TopOperationsTable(props: TopOperationsTableProps): JSX.Element {
|
||||||
const { minTime, maxTime } = useSelector<AppState, GlobalReducer>(
|
const { minTime, maxTime } = useSelector<AppState, GlobalReducer>(
|
||||||
(state) => state.globalTime,
|
(state) => state.globalTime,
|
||||||
);
|
);
|
||||||
const { resourceAttributeQueries } = useSelector<AppState, MetricReducer>(
|
const { queries } = useResourceAttribute();
|
||||||
(state) => state.metrics,
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectedTraceTags: string = JSON.stringify(
|
const selectedTraceTags: string = JSON.stringify(
|
||||||
convertRawQueriesToTraceSelectedTags(resourceAttributeQueries) || [],
|
convertRawQueriesToTraceSelectedTags(queries) || [],
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data } = props;
|
const { data } = props;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import RouteTab from 'components/RouteTab';
|
import RouteTab from 'components/RouteTab';
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
|
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import { generatePath, useParams } from 'react-router-dom';
|
import { generatePath, useParams } from 'react-router-dom';
|
||||||
import { useLocation } from 'react-use';
|
import { useLocation } from 'react-use';
|
||||||
|
|
||||||
import { getWidgetQueryBuilder } from './MetricsApplication.factory';
|
import { getWidgetQueryBuilder } from './MetricsApplication.factory';
|
||||||
import ResourceAttributesFilter from './ResourceAttributesFilter';
|
|
||||||
import DBCall from './Tabs/DBCall';
|
import DBCall from './Tabs/DBCall';
|
||||||
import External from './Tabs/External';
|
import External from './Tabs/External';
|
||||||
import Overview from './Tabs/Overview';
|
import Overview from './Tabs/Overview';
|
||||||
|
@ -2,31 +2,31 @@
|
|||||||
|
|
||||||
export interface Typegen0 {
|
export interface Typegen0 {
|
||||||
'@@xstate/typegen': true;
|
'@@xstate/typegen': true;
|
||||||
eventsCausingActions: {
|
|
||||||
onSelectOperator: 'NEXT';
|
|
||||||
onBlurPurge: 'onBlur';
|
|
||||||
onSelectTagValue: 'NEXT';
|
|
||||||
onValidateQuery: 'onBlur';
|
|
||||||
onSelectTagKey: 'NEXT';
|
|
||||||
};
|
|
||||||
internalEvents: {
|
internalEvents: {
|
||||||
'xstate.init': { type: 'xstate.init' };
|
'xstate.init': { type: 'xstate.init' };
|
||||||
};
|
};
|
||||||
invokeSrcNameMap: {};
|
invokeSrcNameMap: {};
|
||||||
missingImplementations: {
|
missingImplementations: {
|
||||||
actions:
|
actions:
|
||||||
| 'onSelectOperator'
|
|
||||||
| 'onBlurPurge'
|
| 'onBlurPurge'
|
||||||
|
| 'onSelectOperator'
|
||||||
|
| 'onSelectTagKey'
|
||||||
| 'onSelectTagValue'
|
| 'onSelectTagValue'
|
||||||
| 'onValidateQuery'
|
| 'onValidateQuery';
|
||||||
| 'onSelectTagKey';
|
|
||||||
services: never;
|
|
||||||
guards: never;
|
|
||||||
delays: never;
|
delays: never;
|
||||||
|
guards: never;
|
||||||
|
services: never;
|
||||||
|
};
|
||||||
|
eventsCausingActions: {
|
||||||
|
onBlurPurge: 'onBlur';
|
||||||
|
onSelectOperator: 'NEXT';
|
||||||
|
onSelectTagKey: 'NEXT';
|
||||||
|
onSelectTagValue: 'NEXT';
|
||||||
|
onValidateQuery: 'onBlur';
|
||||||
};
|
};
|
||||||
eventsCausingServices: {};
|
|
||||||
eventsCausingGuards: {};
|
|
||||||
eventsCausingDelays: {};
|
eventsCausingDelays: {};
|
||||||
matchesStates: 'TagKey' | 'Operator' | 'TagValue' | 'Idle';
|
eventsCausingGuards: {};
|
||||||
|
eventsCausingServices: {};
|
||||||
|
matchesStates: 'Idle' | 'Operator' | 'TagKey' | 'TagValue';
|
||||||
tags: never;
|
tags: never;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
import { CloseCircleFilled } from '@ant-design/icons';
|
||||||
|
import { Button, Select, Spin } from 'antd';
|
||||||
|
import useResourceAttribute, {
|
||||||
|
isResourceEmpty,
|
||||||
|
} from 'hooks/useResourceAttribute';
|
||||||
|
import { convertMetricKeyToTrace } from 'hooks/useResourceAttribute/utils';
|
||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
|
import QueryChip from './components/QueryChip';
|
||||||
|
import { QueryChipItem, SearchContainer } from './styles';
|
||||||
|
|
||||||
|
function ResourceAttributesFilter(): JSX.Element | null {
|
||||||
|
const {
|
||||||
|
queries,
|
||||||
|
staging,
|
||||||
|
handleClose,
|
||||||
|
handleBlur,
|
||||||
|
handleClearAll,
|
||||||
|
handleFocus,
|
||||||
|
handleChange,
|
||||||
|
selectedQuery,
|
||||||
|
optionsData,
|
||||||
|
loading,
|
||||||
|
} = useResourceAttribute();
|
||||||
|
|
||||||
|
const isEmpty = useMemo(
|
||||||
|
() => isResourceEmpty(queries, staging, selectedQuery),
|
||||||
|
[queries, selectedQuery, staging],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SearchContainer>
|
||||||
|
<div>
|
||||||
|
{queries.map((query) => (
|
||||||
|
<QueryChip key={query.id} queryData={query} onClose={handleClose} />
|
||||||
|
))}
|
||||||
|
{staging.map((query, idx) => (
|
||||||
|
<QueryChipItem key={uuid()}>
|
||||||
|
{idx === 0 ? convertMetricKeyToTrace(query) : query}
|
||||||
|
</QueryChipItem>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<Select
|
||||||
|
placeholder={!isEmpty && 'Search and Filter based on resource attributes.'}
|
||||||
|
onChange={handleChange}
|
||||||
|
bordered={false}
|
||||||
|
value={selectedQuery as never}
|
||||||
|
style={{ flex: 1 }}
|
||||||
|
options={optionsData.options}
|
||||||
|
mode={optionsData?.mode}
|
||||||
|
showArrow={false}
|
||||||
|
onClick={handleFocus}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
onClear={handleClearAll}
|
||||||
|
notFoundContent={
|
||||||
|
loading ? (
|
||||||
|
<span>
|
||||||
|
<Spin size="small" /> Loading...{' '}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span>
|
||||||
|
No resource attributes available to filter. Please refer docs to send
|
||||||
|
attributes.
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{queries.length || staging.length || selectedQuery.length ? (
|
||||||
|
<Button onClick={handleClearAll} icon={<CloseCircleFilled />} type="text" />
|
||||||
|
) : null}
|
||||||
|
</SearchContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ResourceAttributesFilter;
|
@ -0,0 +1,23 @@
|
|||||||
|
import { convertMetricKeyToTrace } from 'hooks/useResourceAttribute/utils';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { QueryChipContainer, QueryChipItem } from '../../styles';
|
||||||
|
import { IQueryChipProps } from './types';
|
||||||
|
|
||||||
|
function QueryChip({ queryData, onClose }: IQueryChipProps): JSX.Element {
|
||||||
|
const onCloseHandler = (): void => {
|
||||||
|
onClose(queryData.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<QueryChipContainer>
|
||||||
|
<QueryChipItem>{convertMetricKeyToTrace(queryData.tagKey)}</QueryChipItem>
|
||||||
|
<QueryChipItem>{queryData.operator}</QueryChipItem>
|
||||||
|
<QueryChipItem closable onClose={onCloseHandler}>
|
||||||
|
{queryData.tagValue.join(', ')}
|
||||||
|
</QueryChipItem>
|
||||||
|
</QueryChipContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default QueryChip;
|
@ -0,0 +1,3 @@
|
|||||||
|
import QueryChip from './QueryChip';
|
||||||
|
|
||||||
|
export default QueryChip;
|
@ -0,0 +1,6 @@
|
|||||||
|
import { IResourceAttribute } from 'hooks/useResourceAttribute/types';
|
||||||
|
|
||||||
|
export interface IQueryChipProps {
|
||||||
|
queryData: IResourceAttribute;
|
||||||
|
onClose: (id: string) => void;
|
||||||
|
}
|
3
frontend/src/container/ResourceAttributesFilter/index.ts
Normal file
3
frontend/src/container/ResourceAttributesFilter/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import ResourceAttributesFilter from './ResourceAttributesFilter';
|
||||||
|
|
||||||
|
export default ResourceAttributesFilter;
|
@ -2,9 +2,7 @@ import { grey } from '@ant-design/colors';
|
|||||||
import { Tag } from 'antd';
|
import { Tag } from 'antd';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const SearchContainer = styled.div<{
|
export const SearchContainer = styled.div`
|
||||||
disabled: boolean;
|
|
||||||
}>`
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -12,8 +10,8 @@ export const SearchContainer = styled.div<{
|
|||||||
padding: 0.2rem;
|
padding: 0.2rem;
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
border: 1px solid #ccc5;
|
border: 1px solid #ccc5;
|
||||||
${({ disabled }): string => (disabled ? `cursor: not-allowed;` : '')}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const QueryChipContainer = styled.span`
|
export const QueryChipContainer = styled.span`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
@ -29,6 +29,7 @@ function SideNav(): JSX.Element {
|
|||||||
const [collapsed, setCollapsed] = useState<boolean>(
|
const [collapsed, setCollapsed] = useState<boolean>(
|
||||||
getLocalStorageKey(IS_SIDEBAR_COLLAPSED) === 'true',
|
getLocalStorageKey(IS_SIDEBAR_COLLAPSED) === 'true',
|
||||||
);
|
);
|
||||||
|
const { search } = useLocation();
|
||||||
const { currentVersion, latestVersion, isCurrentVersionError } = useSelector<
|
const { currentVersion, latestVersion, isCurrentVersionError } = useSelector<
|
||||||
AppState,
|
AppState,
|
||||||
AppReducer
|
AppReducer
|
||||||
@ -47,11 +48,15 @@ function SideNav(): JSX.Element {
|
|||||||
|
|
||||||
const onClickHandler = useCallback(
|
const onClickHandler = useCallback(
|
||||||
(to: string) => {
|
(to: string) => {
|
||||||
|
const queryParams = new URLSearchParams(search);
|
||||||
|
|
||||||
|
const url = queryParams.toString();
|
||||||
|
|
||||||
if (pathname !== to) {
|
if (pathname !== to) {
|
||||||
history.push(to);
|
history.push(`${to}?${url}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[pathname],
|
[pathname, search],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onClickSlackHandler = (): void => {
|
const onClickSlackHandler = (): void => {
|
||||||
|
181
frontend/src/hooks/useResourceAttribute/ResourceProvider.tsx
Normal file
181
frontend/src/hooks/useResourceAttribute/ResourceProvider.tsx
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
import { useMachine } from '@xstate/react';
|
||||||
|
import { encode } from 'js-base64';
|
||||||
|
import history from 'lib/history';
|
||||||
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { ResourceContext } from './context';
|
||||||
|
import { ResourceAttributesFilterMachine } from './machine';
|
||||||
|
import {
|
||||||
|
IResourceAttribute,
|
||||||
|
IResourceAttributeProps,
|
||||||
|
OptionsData,
|
||||||
|
} from './types';
|
||||||
|
import {
|
||||||
|
createQuery,
|
||||||
|
getResourceAttributeQueriesFromURL,
|
||||||
|
GetTagKeys,
|
||||||
|
GetTagValues,
|
||||||
|
OperatorSchema,
|
||||||
|
resourceAttributesQueryToPromQL,
|
||||||
|
} from './utils';
|
||||||
|
|
||||||
|
function ResourceProvider({ children }: Props): JSX.Element {
|
||||||
|
const { pathname } = useLocation();
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [selectedQuery, setSelectedQueries] = useState<string[]>([]);
|
||||||
|
const [staging, setStaging] = useState<string[]>([]);
|
||||||
|
const [queries, setQueries] = useState<IResourceAttribute[]>(
|
||||||
|
getResourceAttributeQueriesFromURL(),
|
||||||
|
);
|
||||||
|
|
||||||
|
const [promQLQuery, setpromQLQuery] = useState<string>(
|
||||||
|
resourceAttributesQueryToPromQL(queries),
|
||||||
|
);
|
||||||
|
|
||||||
|
const [optionsData, setOptionsData] = useState<OptionsData>({
|
||||||
|
mode: undefined,
|
||||||
|
options: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleLoading = (isLoading: boolean): void => {
|
||||||
|
setLoading(isLoading);
|
||||||
|
if (isLoading) {
|
||||||
|
setOptionsData({ mode: undefined, options: [] });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const dispatchQueries = useCallback(
|
||||||
|
(queries: IResourceAttribute[]): void => {
|
||||||
|
history.replace({
|
||||||
|
pathname,
|
||||||
|
search:
|
||||||
|
queries && queries.length
|
||||||
|
? `?resourceAttribute=${encode(JSON.stringify(queries))}`
|
||||||
|
: '',
|
||||||
|
});
|
||||||
|
setQueries(queries);
|
||||||
|
setpromQLQuery(resourceAttributesQueryToPromQL(queries));
|
||||||
|
},
|
||||||
|
[pathname],
|
||||||
|
);
|
||||||
|
|
||||||
|
const [state, send] = useMachine(ResourceAttributesFilterMachine, {
|
||||||
|
actions: {
|
||||||
|
onSelectTagKey: () => {
|
||||||
|
handleLoading(true);
|
||||||
|
GetTagKeys()
|
||||||
|
.then((tagKeys) => setOptionsData({ options: tagKeys, mode: undefined }))
|
||||||
|
.finally(() => {
|
||||||
|
handleLoading(false);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onSelectOperator: () => {
|
||||||
|
setOptionsData({ options: OperatorSchema, mode: undefined });
|
||||||
|
},
|
||||||
|
onSelectTagValue: () => {
|
||||||
|
handleLoading(true);
|
||||||
|
|
||||||
|
GetTagValues(staging[0])
|
||||||
|
.then((tagValuesOptions) =>
|
||||||
|
setOptionsData({ options: tagValuesOptions, mode: 'multiple' }),
|
||||||
|
)
|
||||||
|
.finally(() => {
|
||||||
|
handleLoading(false);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onBlurPurge: () => {
|
||||||
|
setSelectedQueries([]);
|
||||||
|
setStaging([]);
|
||||||
|
},
|
||||||
|
onValidateQuery: (): void => {
|
||||||
|
if (staging.length < 2 || selectedQuery.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const generatedQuery = createQuery([...staging, selectedQuery]);
|
||||||
|
if (generatedQuery) {
|
||||||
|
dispatchQueries([...queries, generatedQuery]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleFocus = useCallback((): void => {
|
||||||
|
if (state.value === 'Idle') {
|
||||||
|
send('NEXT');
|
||||||
|
}
|
||||||
|
}, [send, state.value]);
|
||||||
|
|
||||||
|
const handleBlur = useCallback((): void => {
|
||||||
|
send('onBlur');
|
||||||
|
}, [send]);
|
||||||
|
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(value: string): void => {
|
||||||
|
if (!optionsData.mode) {
|
||||||
|
setStaging((prevStaging) => [...prevStaging, value]);
|
||||||
|
setSelectedQueries([]);
|
||||||
|
send('NEXT');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelectedQueries([...value]);
|
||||||
|
},
|
||||||
|
[optionsData.mode, send],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleClose = useCallback(
|
||||||
|
(id: string): void => {
|
||||||
|
dispatchQueries(queries.filter((queryData) => queryData.id !== id));
|
||||||
|
},
|
||||||
|
[dispatchQueries, queries],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleClearAll = useCallback(() => {
|
||||||
|
send('RESET');
|
||||||
|
dispatchQueries([]);
|
||||||
|
setStaging([]);
|
||||||
|
setQueries([]);
|
||||||
|
setOptionsData({ mode: undefined, options: [] });
|
||||||
|
}, [dispatchQueries, send]);
|
||||||
|
|
||||||
|
const value: IResourceAttributeProps = useMemo(
|
||||||
|
() => ({
|
||||||
|
queries,
|
||||||
|
staging,
|
||||||
|
promQLQuery,
|
||||||
|
handleClearAll,
|
||||||
|
handleClose,
|
||||||
|
handleBlur,
|
||||||
|
handleFocus,
|
||||||
|
loading,
|
||||||
|
handleChange,
|
||||||
|
selectedQuery,
|
||||||
|
optionsData,
|
||||||
|
}),
|
||||||
|
[
|
||||||
|
handleBlur,
|
||||||
|
handleChange,
|
||||||
|
handleClearAll,
|
||||||
|
handleClose,
|
||||||
|
handleFocus,
|
||||||
|
loading,
|
||||||
|
promQLQuery,
|
||||||
|
queries,
|
||||||
|
staging,
|
||||||
|
selectedQuery,
|
||||||
|
optionsData,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ResourceContext.Provider value={value}>{children}</ResourceContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ResourceProvider;
|
7
frontend/src/hooks/useResourceAttribute/context.ts
Normal file
7
frontend/src/hooks/useResourceAttribute/context.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { createContext } from 'react';
|
||||||
|
|
||||||
|
import { IResourceAttributeProps } from './types';
|
||||||
|
|
||||||
|
export const ResourceContext = createContext<IResourceAttributeProps>(
|
||||||
|
{} as IResourceAttributeProps,
|
||||||
|
);
|
7
frontend/src/hooks/useResourceAttribute/index.ts
Normal file
7
frontend/src/hooks/useResourceAttribute/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import ResourceProvider from './ResourceProvider';
|
||||||
|
import useResourceAttribute from './useResourceAttribute';
|
||||||
|
import { convertMetricKeyToTrace, isResourceEmpty } from './utils';
|
||||||
|
|
||||||
|
export default useResourceAttribute;
|
||||||
|
|
||||||
|
export { convertMetricKeyToTrace, isResourceEmpty, ResourceProvider };
|
61
frontend/src/hooks/useResourceAttribute/machine.ts
Normal file
61
frontend/src/hooks/useResourceAttribute/machine.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { createMachine } from 'xstate';
|
||||||
|
|
||||||
|
export const ResourceAttributesFilterMachine =
|
||||||
|
/** @xstate-layout N4IgpgJg5mDOIC5QBECGsAWAjA9qgThAAQDKYBAxhkQIIB2xAYgJYA2ALmPgHQAqqUANJgAngGIAcgFEAGrwDaABgC6iUAAccsZu2Y46akAA9EATkUB2bgEYAbBYsBWWwA5HAFkW3F7gDQgRRABaU3duFwsXAGZbWwAmF3co01jTAF80-zRMXAJiMkpqeiY2Th5+IVExfQAhVgBXfCVVJBBNbV19QxMEcys7B2c3T28-AOC4xUduKItrSbiEuNMo6zcMrPRsPEJScnwqWgYiFg4uPgFhcQAlKRIpBRVDdp09A1aevpt7J1cPLx8-kCCCCcUcURmcwWSxWa0cGxA2W2eT2hSOJTOPAA8uouKh2Dh8JJZI8WhotK8uh9EPM4tYZl4IrZHNY1rZrEDgqFwpEoi43HEnMt3NYEUjcrsCgcisdTmVuDi8QSibUGk0nq0Xp13qAerT6VFGRZmayXOzOSDJtNZrT3I44t5bHaLGKthL8vtDsUTqVzor8PjCWJbvdSc8KdrujTFgajSa2RzxpbwZDbfbHc7XTkdh60d65ecKgA1VANMDVOh1RrNcMdN6GYFBayOKw2xZ2h1eZ3+PX2+mxFzWEWmFymBxRLPIyWemUY+XF0v1cshh41zUR+vUhDNuncAdD6wjscWKIW0FTVPt9NdluT92o6Xon2Y7gASQgrHL0jka-JdapuqIPEcTcIoihxHyTh2Pa-JntyETRO4ngig6yTuBkmQgHQOAQHAhjijmD5erKvr4LWlI6sYiDJIo3Aiieh7Gk4UynkmQRRJ44TARYijJC4AJRBOmEESiUrEXOhaXKI5GRluPG0SkI7uIKhr2vaZ7Nq2cxrGByQWKYpiisJbqEWJs7PvK-qBmR67-pReq6aB1g+DEkEcaYcQaS2l7gTCqzrMZ2aiTOT4FuUAglmWMmboB258hCESmNeLgQR4jheVp8y+SlsIBZsQXTnmJEvu+n7RQBVEIEkLh0dYDFjvYjgsRlqY6bxY4GUZGRAA */
|
||||||
|
createMachine({
|
||||||
|
tsTypes: {} as import('./machine.typegen').Typegen0,
|
||||||
|
initial: 'Idle',
|
||||||
|
states: {
|
||||||
|
TagKey: {
|
||||||
|
on: {
|
||||||
|
NEXT: {
|
||||||
|
actions: 'onSelectOperator',
|
||||||
|
target: 'Operator',
|
||||||
|
},
|
||||||
|
onBlur: {
|
||||||
|
actions: 'onBlurPurge',
|
||||||
|
target: 'Idle',
|
||||||
|
},
|
||||||
|
RESET: {
|
||||||
|
target: 'Idle',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Operator: {
|
||||||
|
on: {
|
||||||
|
NEXT: {
|
||||||
|
actions: 'onSelectTagValue',
|
||||||
|
target: 'TagValue',
|
||||||
|
},
|
||||||
|
onBlur: {
|
||||||
|
actions: 'onBlurPurge',
|
||||||
|
target: 'Idle',
|
||||||
|
},
|
||||||
|
RESET: {
|
||||||
|
target: 'Idle',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TagValue: {
|
||||||
|
on: {
|
||||||
|
onBlur: {
|
||||||
|
actions: ['onValidateQuery', 'onBlurPurge'],
|
||||||
|
target: 'Idle',
|
||||||
|
},
|
||||||
|
RESET: {
|
||||||
|
target: 'Idle',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Idle: {
|
||||||
|
on: {
|
||||||
|
NEXT: {
|
||||||
|
actions: 'onSelectTagKey',
|
||||||
|
description: 'Select Category',
|
||||||
|
target: 'TagKey',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id: 'ResourceAttributesFilterMachine',
|
||||||
|
});
|
37
frontend/src/hooks/useResourceAttribute/machine.typegen.ts
Normal file
37
frontend/src/hooks/useResourceAttribute/machine.typegen.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
// This file was automatically generated. Edits will be overwritten
|
||||||
|
|
||||||
|
export interface Typegen0 {
|
||||||
|
'@@xstate/typegen': true;
|
||||||
|
internalEvents: {
|
||||||
|
"xstate.init": { type: "xstate.init" };
|
||||||
|
};
|
||||||
|
invokeSrcNameMap: {
|
||||||
|
|
||||||
|
};
|
||||||
|
missingImplementations: {
|
||||||
|
actions: "onBlurPurge" | "onSelectOperator" | "onSelectTagKey" | "onSelectTagValue" | "onValidateQuery";
|
||||||
|
delays: never;
|
||||||
|
guards: never;
|
||||||
|
services: never;
|
||||||
|
};
|
||||||
|
eventsCausingActions: {
|
||||||
|
"onBlurPurge": "onBlur";
|
||||||
|
"onSelectOperator": "NEXT";
|
||||||
|
"onSelectTagKey": "NEXT";
|
||||||
|
"onSelectTagValue": "NEXT";
|
||||||
|
"onValidateQuery": "onBlur";
|
||||||
|
};
|
||||||
|
eventsCausingDelays: {
|
||||||
|
|
||||||
|
};
|
||||||
|
eventsCausingGuards: {
|
||||||
|
|
||||||
|
};
|
||||||
|
eventsCausingServices: {
|
||||||
|
|
||||||
|
};
|
||||||
|
matchesStates: "Idle" | "Operator" | "TagKey" | "TagValue";
|
||||||
|
tags: never;
|
||||||
|
}
|
||||||
|
|
32
frontend/src/hooks/useResourceAttribute/types.ts
Normal file
32
frontend/src/hooks/useResourceAttribute/types.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
export interface IResourceAttribute {
|
||||||
|
id: string;
|
||||||
|
tagKey: string;
|
||||||
|
operator: string;
|
||||||
|
tagValue: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IOption {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Modes = 'tags' | 'multiple';
|
||||||
|
|
||||||
|
export interface OptionsData {
|
||||||
|
mode?: Modes;
|
||||||
|
options: IOption[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IResourceAttributeProps {
|
||||||
|
queries: IResourceAttribute[];
|
||||||
|
staging: string[];
|
||||||
|
promQLQuery: string;
|
||||||
|
handleClearAll: VoidFunction;
|
||||||
|
handleClose: (id: string) => void;
|
||||||
|
handleBlur: VoidFunction;
|
||||||
|
handleFocus: VoidFunction;
|
||||||
|
loading: boolean;
|
||||||
|
handleChange: (value: string) => void;
|
||||||
|
selectedQuery: string[];
|
||||||
|
optionsData: OptionsData;
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
|
||||||
|
import { ResourceContext } from './context';
|
||||||
|
import { IResourceAttributeProps } from './types';
|
||||||
|
|
||||||
|
const useResourceAttribute = (): IResourceAttributeProps =>
|
||||||
|
useContext(ResourceContext);
|
||||||
|
|
||||||
|
export default useResourceAttribute;
|
161
frontend/src/hooks/useResourceAttribute/utils.ts
Normal file
161
frontend/src/hooks/useResourceAttribute/utils.ts
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
import {
|
||||||
|
getResourceAttributesTagKeys,
|
||||||
|
getResourceAttributesTagValues,
|
||||||
|
} from 'api/metrics/getResourceAttributes';
|
||||||
|
import { OperatorConversions } from 'constants/resourceAttributes';
|
||||||
|
import {
|
||||||
|
IOption,
|
||||||
|
IResourceAttribute,
|
||||||
|
IResourceAttributeProps,
|
||||||
|
} from 'hooks/useResourceAttribute/types';
|
||||||
|
import { decode } from 'js-base64';
|
||||||
|
import history from 'lib/history';
|
||||||
|
import { IQueryBuilderTagFilterItems } from 'types/api/dashboard/getAll';
|
||||||
|
import { OperatorValues, Tags } from 'types/reducer/trace';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resource_x_y -> x.y
|
||||||
|
*/
|
||||||
|
export const convertMetricKeyToTrace = (key: string): string => {
|
||||||
|
const splittedKey = key.split('_');
|
||||||
|
|
||||||
|
if (splittedKey.length <= 1) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return splittedKey.splice(1).join('.');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* x.y -> resource_x_y
|
||||||
|
*/
|
||||||
|
export const convertTraceKeyToMetric = (key: string): string => {
|
||||||
|
const splittedKey = key.split('.');
|
||||||
|
return `resource_${splittedKey.join('_')}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const convertOperatorLabelToMetricOperator = (label: string): string =>
|
||||||
|
OperatorConversions.find((operator) => operator.label === label)
|
||||||
|
?.metricValue || '';
|
||||||
|
|
||||||
|
export const convertOperatorLabelToTraceOperator = (
|
||||||
|
label: string,
|
||||||
|
): OperatorValues =>
|
||||||
|
OperatorConversions.find((operator) => operator.label === label)
|
||||||
|
?.traceValue as OperatorValues;
|
||||||
|
|
||||||
|
export const convertRawQueriesToTraceSelectedTags = (
|
||||||
|
queries: IResourceAttribute[],
|
||||||
|
tagType = 'ResourceAttribute',
|
||||||
|
): Tags[] =>
|
||||||
|
queries.map((query) => ({
|
||||||
|
Key: convertMetricKeyToTrace(query.tagKey),
|
||||||
|
Operator: convertOperatorLabelToTraceOperator(query.operator),
|
||||||
|
StringValues: query.tagValue,
|
||||||
|
NumberValues: [],
|
||||||
|
BoolValues: [],
|
||||||
|
TagType: tagType,
|
||||||
|
}));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts Resource Attribute Queries to PromQL query string
|
||||||
|
*/
|
||||||
|
export const resourceAttributesQueryToPromQL = (
|
||||||
|
queries: IResourceAttribute[],
|
||||||
|
): string => {
|
||||||
|
let parsedQueryString = '';
|
||||||
|
|
||||||
|
if (Array.isArray(queries))
|
||||||
|
queries.forEach((query) => {
|
||||||
|
parsedQueryString += `, ${
|
||||||
|
query.tagKey
|
||||||
|
}${convertOperatorLabelToMetricOperator(
|
||||||
|
query.operator,
|
||||||
|
)}"${query.tagValue.join('|')}"`;
|
||||||
|
});
|
||||||
|
|
||||||
|
return parsedQueryString;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Convert resource attributes to tagFilter items for queryBuilder */
|
||||||
|
export const resourceAttributesToTagFilterItems = (
|
||||||
|
queries: IResourceAttribute[],
|
||||||
|
): IQueryBuilderTagFilterItems[] =>
|
||||||
|
queries.map((res) => ({
|
||||||
|
id: `${res.id}`,
|
||||||
|
key: `${res.tagKey}`,
|
||||||
|
op: `${res.operator}`,
|
||||||
|
value: `${res.tagValue}`.split(','),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const OperatorSchema: IOption[] = OperatorConversions.map(
|
||||||
|
(operator) => ({
|
||||||
|
label: operator.label,
|
||||||
|
value: operator.label,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const GetTagKeys = async (): Promise<IOption[]> => {
|
||||||
|
const { payload } = await getResourceAttributesTagKeys({
|
||||||
|
metricName: 'signoz_calls_total',
|
||||||
|
match: 'resource_',
|
||||||
|
});
|
||||||
|
if (!payload || !payload?.data) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return payload.data.map((tagKey: string) => ({
|
||||||
|
label: convertMetricKeyToTrace(tagKey),
|
||||||
|
value: tagKey,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GetTagValues = async (tagKey: string): Promise<IOption[]> => {
|
||||||
|
const { payload } = await getResourceAttributesTagValues({
|
||||||
|
tagKey,
|
||||||
|
metricName: 'signoz_calls_total',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!payload || !payload?.data) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return payload.data.map((tagValue: string) => ({
|
||||||
|
label: tagValue,
|
||||||
|
value: tagValue,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createQuery = (
|
||||||
|
selectedItems: Array<string | string[]> = [],
|
||||||
|
): IResourceAttribute | null => {
|
||||||
|
if (selectedItems.length === 3) {
|
||||||
|
return {
|
||||||
|
id: uuid().slice(0, 8),
|
||||||
|
tagKey: selectedItems[0] as string,
|
||||||
|
operator: selectedItems[1] as string,
|
||||||
|
tagValue: selectedItems[2] as string[],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getResourceAttributeQueriesFromURL(): IResourceAttribute[] {
|
||||||
|
const resourceAttributeQuery = new URLSearchParams(
|
||||||
|
history.location.search,
|
||||||
|
).get('resourceAttribute');
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (resourceAttributeQuery) {
|
||||||
|
return JSON.parse(decode(resourceAttributeQuery)) as IResourceAttribute[];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isResourceEmpty = (
|
||||||
|
queries: IResourceAttributeProps['queries'],
|
||||||
|
staging: IResourceAttributeProps['staging'],
|
||||||
|
selectedQuery: IResourceAttributeProps['selectedQuery'],
|
||||||
|
): boolean => !!(queries.length || staging.length || selectedQuery.length);
|
@ -1,76 +0,0 @@
|
|||||||
import { OperatorConversions } from 'constants/resourceAttributes';
|
|
||||||
import { IResourceAttributeQuery } from 'container/MetricsApplication/ResourceAttributesFilter/types';
|
|
||||||
import { IQueryBuilderTagFilterItems } from 'types/api/dashboard/getAll';
|
|
||||||
import { OperatorValues, Tags } from 'types/reducer/trace';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* resource_x_y -> x.y
|
|
||||||
*/
|
|
||||||
export const convertMetricKeyToTrace = (key: string): string => {
|
|
||||||
const splittedKey = key.split('_');
|
|
||||||
|
|
||||||
if (splittedKey.length <= 1) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return splittedKey.splice(1).join('.');
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* x.y -> resource_x_y
|
|
||||||
*/
|
|
||||||
export const convertTraceKeyToMetric = (key: string): string => {
|
|
||||||
const splittedKey = key.split('.');
|
|
||||||
return `resource_${splittedKey.join('_')}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const convertOperatorLabelToMetricOperator = (label: string): string =>
|
|
||||||
OperatorConversions.find((operator) => operator.label === label)
|
|
||||||
?.metricValue || '';
|
|
||||||
|
|
||||||
export const convertOperatorLabelToTraceOperator = (
|
|
||||||
label: string,
|
|
||||||
): OperatorValues =>
|
|
||||||
OperatorConversions.find((operator) => operator.label === label)
|
|
||||||
?.traceValue as OperatorValues;
|
|
||||||
|
|
||||||
export const convertRawQueriesToTraceSelectedTags = (
|
|
||||||
queries: IResourceAttributeQuery[],
|
|
||||||
): Tags[] =>
|
|
||||||
queries.map((query) => ({
|
|
||||||
Key: convertMetricKeyToTrace(query.tagKey),
|
|
||||||
Operator: convertOperatorLabelToTraceOperator(query.operator),
|
|
||||||
StringValues: query.tagValue,
|
|
||||||
NumberValues: [],
|
|
||||||
BoolValues: [],
|
|
||||||
}));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts Resource Attribute Queries to PromQL query string
|
|
||||||
*/
|
|
||||||
export const resourceAttributesQueryToPromQL = (
|
|
||||||
queries: IResourceAttributeQuery[],
|
|
||||||
): string => {
|
|
||||||
let parsedQueryString = '';
|
|
||||||
|
|
||||||
if (Array.isArray(queries))
|
|
||||||
queries.forEach((query) => {
|
|
||||||
parsedQueryString += `, ${
|
|
||||||
query.tagKey
|
|
||||||
}${convertOperatorLabelToMetricOperator(
|
|
||||||
query.operator,
|
|
||||||
)}"${query.tagValue.join('|')}"`;
|
|
||||||
});
|
|
||||||
|
|
||||||
return parsedQueryString;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Convert resource attributes to tagFilter items for queryBuilder */
|
|
||||||
export const resourceAttributesToTagFilterItems = (
|
|
||||||
queries: IResourceAttributeQuery[],
|
|
||||||
): IQueryBuilderTagFilterItems[] =>
|
|
||||||
queries.map((res) => ({
|
|
||||||
id: `${res.id}`,
|
|
||||||
key: `${res.tagKey}`,
|
|
||||||
op: `${res.operator}`,
|
|
||||||
value: `${res.tagValue}`.split(','),
|
|
||||||
}));
|
|
@ -1,6 +1,7 @@
|
|||||||
import RouteTab from 'components/RouteTab';
|
import RouteTab from 'components/RouteTab';
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
import AllErrorsContainer from 'container/AllError';
|
import AllErrorsContainer from 'container/AllError';
|
||||||
|
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
@ -8,18 +9,21 @@ function AllErrors(): JSX.Element {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RouteTab
|
<>
|
||||||
{...{
|
<ResourceAttributesFilter />
|
||||||
routes: [
|
<RouteTab
|
||||||
{
|
{...{
|
||||||
Component: AllErrorsContainer,
|
routes: [
|
||||||
name: t('routes.all_errors'),
|
{
|
||||||
route: ROUTES.ALL_ERROR,
|
Component: AllErrorsContainer,
|
||||||
},
|
name: t('routes.all_errors'),
|
||||||
],
|
route: ROUTES.ALL_ERROR,
|
||||||
activeKey: t('routes.all_errors'),
|
},
|
||||||
}}
|
],
|
||||||
/>
|
activeKey: t('routes.all_errors'),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { Typography } from 'antd';
|
import { Typography } from 'antd';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import MetricsApplicationContainer from 'container/MetricsApplication';
|
import MetricsApplicationContainer from 'container/MetricsApplication';
|
||||||
import { convertRawQueriesToTraceSelectedTags } from 'lib/resourceAttributes';
|
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||||
|
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
||||||
import React, { useEffect, useMemo } from 'react';
|
import React, { useEffect, useMemo } from 'react';
|
||||||
import { connect, useSelector } from 'react-redux';
|
import { connect, useSelector } from 'react-redux';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
@ -27,16 +28,11 @@ function MetricsApplication({ getInitialData }: MetricsProps): JSX.Element {
|
|||||||
>((state) => state.metrics);
|
>((state) => state.metrics);
|
||||||
|
|
||||||
const { servicename } = useParams<ServiceProps>();
|
const { servicename } = useParams<ServiceProps>();
|
||||||
|
const { queries } = useResourceAttribute();
|
||||||
const { resourceAttributeQueries } = useSelector<AppState, MetricReducer>(
|
|
||||||
(state) => state.metrics,
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectedTags = useMemo(
|
const selectedTags = useMemo(
|
||||||
() =>
|
() => (convertRawQueriesToTraceSelectedTags(queries) as Tags[]) || [],
|
||||||
(convertRawQueriesToTraceSelectedTags(resourceAttributeQueries) as Tags[]) ||
|
[queries],
|
||||||
[],
|
|
||||||
[resourceAttributeQueries],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -3,10 +3,11 @@ import getLocalStorageKey from 'api/browser/localstorage/get';
|
|||||||
import ReleaseNote from 'components/ReleaseNote';
|
import ReleaseNote from 'components/ReleaseNote';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import { SKIP_ONBOARDING } from 'constants/onboarding';
|
import { SKIP_ONBOARDING } from 'constants/onboarding';
|
||||||
import ResourceAttributesFilter from 'container/MetricsApplication/ResourceAttributesFilter';
|
|
||||||
import MetricTable from 'container/MetricsTable';
|
import MetricTable from 'container/MetricsTable';
|
||||||
|
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
import { convertRawQueriesToTraceSelectedTags } from 'lib/resourceAttributes';
|
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||||
|
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
||||||
import React, { useEffect, useMemo } from 'react';
|
import React, { useEffect, useMemo } from 'react';
|
||||||
import { connect, useSelector } from 'react-redux';
|
import { connect, useSelector } from 'react-redux';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
@ -25,12 +26,9 @@ function Metrics({ getService }: MetricsProps): JSX.Element {
|
|||||||
GlobalReducer
|
GlobalReducer
|
||||||
>((state) => state.globalTime);
|
>((state) => state.globalTime);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const {
|
const { services, error, errorMessage } = useSelector<AppState, MetricReducer>(
|
||||||
services,
|
(state) => state.metrics,
|
||||||
resourceAttributeQueries,
|
);
|
||||||
error,
|
|
||||||
errorMessage,
|
|
||||||
} = useSelector<AppState, MetricReducer>((state) => state.metrics);
|
|
||||||
const { notifications } = useNotifications();
|
const { notifications } = useNotifications();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -41,12 +39,13 @@ function Metrics({ getService }: MetricsProps): JSX.Element {
|
|||||||
}
|
}
|
||||||
}, [error, errorMessage, notifications]);
|
}, [error, errorMessage, notifications]);
|
||||||
|
|
||||||
|
const { queries } = useResourceAttribute();
|
||||||
|
|
||||||
const selectedTags = useMemo(
|
const selectedTags = useMemo(
|
||||||
() =>
|
() => (convertRawQueriesToTraceSelectedTags(queries, '') as Tags[]) || [],
|
||||||
(convertRawQueriesToTraceSelectedTags(resourceAttributeQueries) as Tags[]) ||
|
[queries],
|
||||||
[],
|
|
||||||
[resourceAttributeQueries],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const isSkipped = getLocalStorageKey(SKIP_ONBOARDING) === 'true';
|
const isSkipped = getLocalStorageKey(SKIP_ONBOARDING) === 'true';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
import { IResourceAttributeQuery } from 'container/MetricsApplication/ResourceAttributesFilter/types';
|
|
||||||
import { decode, encode } from 'js-base64';
|
|
||||||
import history from 'lib/history';
|
|
||||||
import { resourceAttributesQueryToPromQL } from 'lib/resourceAttributes';
|
|
||||||
import { SET_RESOURCE_ATTRIBUTE_QUERIES } from 'types/actions/metrics';
|
|
||||||
|
|
||||||
export function GetResourceAttributeQueriesFromURL():
|
|
||||||
| IResourceAttributeQuery[]
|
|
||||||
| null {
|
|
||||||
const resourceAttributeQuery = new URLSearchParams(
|
|
||||||
history.location.search,
|
|
||||||
).get('resourceAttribute');
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (resourceAttributeQuery) {
|
|
||||||
return JSON.parse(
|
|
||||||
decode(resourceAttributeQuery),
|
|
||||||
) as IResourceAttributeQuery[];
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SetResourceAttributeQueriesFromURL = (
|
|
||||||
queries: IResourceAttributeQuery[],
|
|
||||||
): void => {
|
|
||||||
history.push({
|
|
||||||
pathname: history.location.pathname,
|
|
||||||
search:
|
|
||||||
queries && queries.length
|
|
||||||
? `?resourceAttribute=${encode(JSON.stringify(queries))}`
|
|
||||||
: '',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
export const SetResourceAttributeQueries = (
|
|
||||||
queries: IResourceAttributeQuery[],
|
|
||||||
): {
|
|
||||||
type: typeof SET_RESOURCE_ATTRIBUTE_QUERIES;
|
|
||||||
payload: {
|
|
||||||
queries: IResourceAttributeQuery[];
|
|
||||||
promQLQuery: string;
|
|
||||||
};
|
|
||||||
} => {
|
|
||||||
SetResourceAttributeQueriesFromURL(queries);
|
|
||||||
return {
|
|
||||||
type: SET_RESOURCE_ATTRIBUTE_QUERIES,
|
|
||||||
payload: {
|
|
||||||
queries,
|
|
||||||
promQLQuery: resourceAttributesQueryToPromQL(queries),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,5 +1,3 @@
|
|||||||
import { resourceAttributesQueryToPromQL } from 'lib/resourceAttributes';
|
|
||||||
import { GetResourceAttributeQueriesFromURL } from 'store/actions/metrics/setResourceAttributeQueries';
|
|
||||||
import {
|
import {
|
||||||
GET_INITIAL_APPLICATION_ERROR,
|
GET_INITIAL_APPLICATION_ERROR,
|
||||||
GET_INITIAL_APPLICATION_LOADING,
|
GET_INITIAL_APPLICATION_LOADING,
|
||||||
@ -9,7 +7,6 @@ import {
|
|||||||
GET_SERVICE_LIST_SUCCESS,
|
GET_SERVICE_LIST_SUCCESS,
|
||||||
MetricsActions,
|
MetricsActions,
|
||||||
RESET_INITIAL_APPLICATION_DATA,
|
RESET_INITIAL_APPLICATION_DATA,
|
||||||
SET_RESOURCE_ATTRIBUTE_QUERIES,
|
|
||||||
} from 'types/actions/metrics';
|
} from 'types/actions/metrics';
|
||||||
import InitialValueTypes from 'types/reducer/metrics';
|
import InitialValueTypes from 'types/reducer/metrics';
|
||||||
|
|
||||||
@ -25,10 +22,6 @@ const InitialValue: InitialValueTypes = {
|
|||||||
externalAverageDuration: [],
|
externalAverageDuration: [],
|
||||||
externalError: [],
|
externalError: [],
|
||||||
serviceOverview: [],
|
serviceOverview: [],
|
||||||
resourceAttributeQueries: GetResourceAttributeQueriesFromURL() || [],
|
|
||||||
resourceAttributePromQLQuery: resourceAttributesQueryToPromQL(
|
|
||||||
GetResourceAttributeQueriesFromURL() || [],
|
|
||||||
),
|
|
||||||
topLevelOperations: [],
|
topLevelOperations: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -110,15 +103,6 @@ const metrics = (
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
case SET_RESOURCE_ATTRIBUTE_QUERIES: {
|
|
||||||
const { queries, promQLQuery } = action.payload;
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
resourceAttributeQueries: queries,
|
|
||||||
resourceAttributePromQLQuery: promQLQuery,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,3 @@
|
|||||||
// import { DBOverView } from 'types/api/metrics/getDBOverview';
|
|
||||||
// import { ExternalAverageDuration } from 'types/api/metrics/getExternalAverageDuration';
|
|
||||||
// import { ExternalError } from 'types/api/metrics/getExternalError';
|
|
||||||
// import { ExternalService } from 'types/api/metrics/getExternalService';
|
|
||||||
import { IResourceAttributeQuery } from 'container/MetricsApplication/ResourceAttributesFilter/types';
|
|
||||||
import { ServicesList } from 'types/api/metrics/getService';
|
import { ServicesList } from 'types/api/metrics/getService';
|
||||||
import { ServiceOverview } from 'types/api/metrics/getServiceOverview';
|
import { ServiceOverview } from 'types/api/metrics/getServiceOverview';
|
||||||
import { TopOperations } from 'types/api/metrics/getTopOperations';
|
import { TopOperations } from 'types/api/metrics/getTopOperations';
|
||||||
@ -15,7 +10,6 @@ export const GET_INITIAL_APPLICATION_LOADING =
|
|||||||
export const GET_INITIAL_APPLICATION_ERROR = 'GET_INITIAL_APPLICATION_ERROR';
|
export const GET_INITIAL_APPLICATION_ERROR = 'GET_INITIAL_APPLICATION_ERROR';
|
||||||
export const GET_INTIAL_APPLICATION_DATA = 'GET_INTIAL_APPLICATION_DATA';
|
export const GET_INTIAL_APPLICATION_DATA = 'GET_INTIAL_APPLICATION_DATA';
|
||||||
export const RESET_INITIAL_APPLICATION_DATA = 'RESET_INITIAL_APPLICATION_DATA';
|
export const RESET_INITIAL_APPLICATION_DATA = 'RESET_INITIAL_APPLICATION_DATA';
|
||||||
export const SET_RESOURCE_ATTRIBUTE_QUERIES = 'SET_RESOURCE_ATTRIBUTE_QUERIES';
|
|
||||||
|
|
||||||
export interface GetServiceList {
|
export interface GetServiceList {
|
||||||
type: typeof GET_SERVICE_LIST_SUCCESS;
|
type: typeof GET_SERVICE_LIST_SUCCESS;
|
||||||
@ -52,18 +46,9 @@ export interface ResetInitialApplicationData {
|
|||||||
type: typeof RESET_INITIAL_APPLICATION_DATA;
|
type: typeof RESET_INITIAL_APPLICATION_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SetResourceAttributeQueries {
|
|
||||||
type: typeof SET_RESOURCE_ATTRIBUTE_QUERIES;
|
|
||||||
payload: {
|
|
||||||
queries: IResourceAttributeQuery[];
|
|
||||||
promQLQuery: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MetricsActions =
|
export type MetricsActions =
|
||||||
| GetServiceListError
|
| GetServiceListError
|
||||||
| GetServiceListLoading
|
| GetServiceListLoading
|
||||||
| GetServiceList
|
| GetServiceList
|
||||||
| GetInitialApplicationData
|
| GetInitialApplicationData
|
||||||
| ResetInitialApplicationData
|
| ResetInitialApplicationData;
|
||||||
| SetResourceAttributeQueries;
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { GlobalTime } from 'types/actions/globalTime';
|
import { GlobalTime } from 'types/actions/globalTime';
|
||||||
|
import { Tags } from 'types/reducer/trace';
|
||||||
|
|
||||||
export type Order = 'ascending' | 'descending';
|
export type Order = 'ascending' | 'descending';
|
||||||
export type OrderBy =
|
export type OrderBy =
|
||||||
@ -17,6 +18,7 @@ export interface Props {
|
|||||||
offset?: number;
|
offset?: number;
|
||||||
exceptionType?: string;
|
exceptionType?: string;
|
||||||
serviceName?: string;
|
serviceName?: string;
|
||||||
|
tags?: Tags[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Exception {
|
export interface Exception {
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { GlobalTime } from 'types/actions/globalTime';
|
import { GlobalTime } from 'types/actions/globalTime';
|
||||||
|
import { Tags } from 'types/reducer/trace';
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
start: GlobalTime['minTime'];
|
start: GlobalTime['minTime'];
|
||||||
end: GlobalTime['minTime'];
|
end: GlobalTime['minTime'];
|
||||||
exceptionType: string;
|
exceptionType: string;
|
||||||
serviceName: string;
|
serviceName: string;
|
||||||
|
tags: Tags[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PayloadProps = number;
|
export type PayloadProps = number;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { IResourceAttributeQuery } from 'container/MetricsApplication/ResourceAttributesFilter/types';
|
|
||||||
import { DBOverView } from 'types/api/metrics/getDBOverview';
|
import { DBOverView } from 'types/api/metrics/getDBOverview';
|
||||||
import { ExternalAverageDuration } from 'types/api/metrics/getExternalAverageDuration';
|
import { ExternalAverageDuration } from 'types/api/metrics/getExternalAverageDuration';
|
||||||
import { ExternalError } from 'types/api/metrics/getExternalError';
|
import { ExternalError } from 'types/api/metrics/getExternalError';
|
||||||
@ -19,8 +18,6 @@ interface MetricReducer {
|
|||||||
externalAverageDuration: ExternalAverageDuration[];
|
externalAverageDuration: ExternalAverageDuration[];
|
||||||
externalError: ExternalError[];
|
externalError: ExternalError[];
|
||||||
serviceOverview: ServiceOverview[];
|
serviceOverview: ServiceOverview[];
|
||||||
resourceAttributeQueries: IResourceAttributeQuery[];
|
|
||||||
resourceAttributePromQLQuery: string;
|
|
||||||
topLevelOperations: string[];
|
topLevelOperations: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user