mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-17 12:05:57 +08:00
Shifting of graph from Dashboard to Service layer (#3107)
* refactor: initial setup for full view done * feat: done with shifting of chart to services * refactor: removed the dependency dashboard action * refactor: make ondelete and onclone optional in widgetheader * refactor: optimised the allowdelete, allowclone and allowEdit * fix: build pipline error * refactor: moved contant to contant.js * refactor: create a utils and types and seperated it from component * refactor: merge the latest overview from develop * refactor: review comments changes * refactor: magic string to constants * refactor: handle the isloading for topLevelOperations * refactor: apply loading check for other api's * refactor: seperated the component * refactor: removed the graphwithoutdashboard component * fix: the type of variable from dashboard * refactor: created utils and updated types * refactor: changed the name of variable and fixed typos * fix: the menu option dropdown for services widget header * chore: ts config is updated for the isTwidgetoptions * chore: removed the unwanted file * fix: css on hover of widget header and default value * refactor: renamed the file to index in fullView * refactor: disable the edit delete clone option * fix: typos * chore: types are updated in metrics application * chore: type is updated * fix: build is fixed * refactor: changes the yaxisunit to ns of serviceoverview --------- Co-authored-by: Palash Gupta <palashgdev@gmail.com> Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
This commit is contained in:
parent
f3817d7335
commit
50142321f7
@ -1,137 +0,0 @@
|
|||||||
import { Button } from 'antd';
|
|
||||||
import { GraphOnClickHandler } from 'components/Graph';
|
|
||||||
import Spinner from 'components/Spinner';
|
|
||||||
import TimePreference from 'components/TimePreferenceDropDown';
|
|
||||||
import GridGraphComponent from 'container/GridGraphComponent';
|
|
||||||
import {
|
|
||||||
timeItems,
|
|
||||||
timePreferance,
|
|
||||||
} from 'container/NewWidget/RightContainer/timeItems';
|
|
||||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
|
||||||
import { useStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
|
||||||
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
|
||||||
import getChartData from 'lib/getChartData';
|
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
import { AppState } from 'store/reducers';
|
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
|
||||||
|
|
||||||
import { TimeContainer } from './styles';
|
|
||||||
|
|
||||||
function FullView({
|
|
||||||
widget,
|
|
||||||
fullViewOptions = true,
|
|
||||||
onClickHandler,
|
|
||||||
name,
|
|
||||||
yAxisUnit,
|
|
||||||
onDragSelect,
|
|
||||||
isDependedDataLoaded = false,
|
|
||||||
}: FullViewProps): JSX.Element {
|
|
||||||
const { selectedTime: globalSelectedTime } = useSelector<
|
|
||||||
AppState,
|
|
||||||
GlobalReducer
|
|
||||||
>((state) => state.globalTime);
|
|
||||||
|
|
||||||
const getSelectedTime = useCallback(
|
|
||||||
() =>
|
|
||||||
timeItems.find((e) => e.enum === (widget?.timePreferance || 'GLOBAL_TIME')),
|
|
||||||
[widget],
|
|
||||||
);
|
|
||||||
|
|
||||||
const [selectedTime, setSelectedTime] = useState<timePreferance>({
|
|
||||||
name: getSelectedTime()?.name || '',
|
|
||||||
enum: widget?.timePreferance || 'GLOBAL_TIME',
|
|
||||||
});
|
|
||||||
|
|
||||||
const queryKey = useMemo(
|
|
||||||
() =>
|
|
||||||
`FullViewGetMetricsQueryRange-${selectedTime.enum}-${globalSelectedTime}-${widget.id}`,
|
|
||||||
[selectedTime, globalSelectedTime, widget],
|
|
||||||
);
|
|
||||||
|
|
||||||
const updatedQuery = useStepInterval(widget?.query);
|
|
||||||
|
|
||||||
const response = useGetQueryRange(
|
|
||||||
{
|
|
||||||
selectedTime: selectedTime.enum,
|
|
||||||
graphType: widget.panelTypes,
|
|
||||||
query: updatedQuery,
|
|
||||||
globalSelectedInterval: globalSelectedTime,
|
|
||||||
variables: getDashboardVariables(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
queryKey,
|
|
||||||
enabled: !isDependedDataLoaded,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const chartDataSet = useMemo(
|
|
||||||
() =>
|
|
||||||
getChartData({
|
|
||||||
queryData: [
|
|
||||||
{
|
|
||||||
queryData: response?.data?.payload?.data?.result || [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
[response],
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response.status === 'idle' || response.status === 'loading') {
|
|
||||||
return <Spinner height="100%" size="large" tip="Loading..." />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{fullViewOptions && (
|
|
||||||
<TimeContainer>
|
|
||||||
<TimePreference
|
|
||||||
selectedTime={selectedTime}
|
|
||||||
setSelectedTime={setSelectedTime}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
onClick={(): void => {
|
|
||||||
response.refetch();
|
|
||||||
}}
|
|
||||||
type="primary"
|
|
||||||
>
|
|
||||||
Refresh
|
|
||||||
</Button>
|
|
||||||
</TimeContainer>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<GridGraphComponent
|
|
||||||
GRAPH_TYPES={widget.panelTypes}
|
|
||||||
data={chartDataSet}
|
|
||||||
isStacked={widget.isStacked}
|
|
||||||
opacity={widget.opacity}
|
|
||||||
title={widget.title}
|
|
||||||
onClickHandler={onClickHandler}
|
|
||||||
name={name}
|
|
||||||
yAxisUnit={yAxisUnit}
|
|
||||||
onDragSelect={onDragSelect}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface FullViewProps {
|
|
||||||
widget: Widgets;
|
|
||||||
fullViewOptions?: boolean;
|
|
||||||
onClickHandler?: GraphOnClickHandler;
|
|
||||||
name: string;
|
|
||||||
yAxisUnit?: string;
|
|
||||||
onDragSelect?: (start: number, end: number) => void;
|
|
||||||
isDependedDataLoaded?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
FullView.defaultProps = {
|
|
||||||
fullViewOptions: undefined,
|
|
||||||
onClickHandler: undefined,
|
|
||||||
yAxisUnit: undefined,
|
|
||||||
onDragSelect: undefined,
|
|
||||||
isDependedDataLoaded: undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FullView;
|
|
@ -1,5 +1,4 @@
|
|||||||
import { Button, Typography } from 'antd';
|
import { Button } from 'antd';
|
||||||
import getQueryResult from 'api/widgets/getQuery';
|
|
||||||
import { GraphOnClickHandler } from 'components/Graph';
|
import { GraphOnClickHandler } from 'components/Graph';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import TimePreference from 'components/TimePreferenceDropDown';
|
import TimePreference from 'components/TimePreferenceDropDown';
|
||||||
@ -7,22 +6,18 @@ import GridGraphComponent from 'container/GridGraphComponent';
|
|||||||
import {
|
import {
|
||||||
timeItems,
|
timeItems,
|
||||||
timePreferance,
|
timePreferance,
|
||||||
timePreferenceType,
|
|
||||||
} from 'container/NewWidget/RightContainer/timeItems';
|
} from 'container/NewWidget/RightContainer/timeItems';
|
||||||
import convertToNanoSecondsToSecond from 'lib/convertToNanoSecondsToSecond';
|
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||||
|
import { useStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
||||||
|
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
||||||
import getChartData from 'lib/getChartData';
|
import getChartData from 'lib/getChartData';
|
||||||
import GetMaxMinTime from 'lib/getMaxMinTime';
|
|
||||||
import GetMinMax from 'lib/getMinMax';
|
|
||||||
import getStartAndEndTime from 'lib/getStartAndEndTime';
|
|
||||||
import getStep from 'lib/getStep';
|
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import { useQueries } from 'react-query';
|
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { PromQLWidgets } from 'types/api/dashboard/getAll';
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
|
||||||
import { NotFoundContainer, TimeContainer } from './styles';
|
import { TimeContainer } from './styles';
|
||||||
|
|
||||||
function FullView({
|
function FullView({
|
||||||
widget,
|
widget,
|
||||||
@ -31,8 +26,9 @@ function FullView({
|
|||||||
name,
|
name,
|
||||||
yAxisUnit,
|
yAxisUnit,
|
||||||
onDragSelect,
|
onDragSelect,
|
||||||
|
isDependedDataLoaded = false,
|
||||||
}: FullViewProps): JSX.Element {
|
}: FullViewProps): JSX.Element {
|
||||||
const { minTime, maxTime, selectedTime: globalSelectedTime } = useSelector<
|
const { selectedTime: globalSelectedTime } = useSelector<
|
||||||
AppState,
|
AppState,
|
||||||
GlobalReducer
|
GlobalReducer
|
||||||
>((state) => state.globalTime);
|
>((state) => state.globalTime);
|
||||||
@ -48,110 +44,55 @@ function FullView({
|
|||||||
enum: widget?.timePreferance || 'GLOBAL_TIME',
|
enum: widget?.timePreferance || 'GLOBAL_TIME',
|
||||||
});
|
});
|
||||||
|
|
||||||
const maxMinTime = GetMaxMinTime({
|
const queryKey = useMemo(
|
||||||
graphType: widget.panelTypes,
|
() =>
|
||||||
maxTime,
|
`FullViewGetMetricsQueryRange-${selectedTime.enum}-${globalSelectedTime}-${widget.id}`,
|
||||||
minTime,
|
[selectedTime, globalSelectedTime, widget],
|
||||||
});
|
|
||||||
|
|
||||||
const getMinMax = (
|
|
||||||
time: timePreferenceType,
|
|
||||||
): { min: string | number; max: string | number } => {
|
|
||||||
if (time === 'GLOBAL_TIME') {
|
|
||||||
const minMax = GetMinMax(globalSelectedTime, [
|
|
||||||
minTime / 1000000,
|
|
||||||
maxTime / 1000000,
|
|
||||||
]);
|
|
||||||
return {
|
|
||||||
min: convertToNanoSecondsToSecond(minMax.minTime / 1000),
|
|
||||||
max: convertToNanoSecondsToSecond(minMax.maxTime / 1000),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const minMax = getStartAndEndTime({
|
|
||||||
type: selectedTime.enum,
|
|
||||||
maxTime: maxMinTime.maxTime,
|
|
||||||
minTime: maxMinTime.minTime,
|
|
||||||
});
|
|
||||||
return { min: parseInt(minMax.start, 10), max: parseInt(minMax.end, 10) };
|
|
||||||
};
|
|
||||||
|
|
||||||
const queryMinMax = getMinMax(selectedTime.enum);
|
|
||||||
|
|
||||||
const queryLength = widget.query.filter((e) => e.query.length !== 0);
|
|
||||||
|
|
||||||
const response = useQueries(
|
|
||||||
queryLength.map((query) => ({
|
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
||||||
queryFn: () =>
|
|
||||||
getQueryResult({
|
|
||||||
end: queryMinMax.max.toString(),
|
|
||||||
query: query.query,
|
|
||||||
start: queryMinMax.min.toString(),
|
|
||||||
step: `${getStep({
|
|
||||||
start: queryMinMax.min,
|
|
||||||
end: queryMinMax.max,
|
|
||||||
inputFormat: 's',
|
|
||||||
})}`,
|
|
||||||
}),
|
|
||||||
queryHash: `${query.query}-${query.legend}-${selectedTime.enum}`,
|
|
||||||
retryOnMount: false,
|
|
||||||
})),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const isError =
|
const updatedQuery = useStepInterval(widget?.query);
|
||||||
response.find((e) => e?.data?.statusCode !== 200) !== undefined ||
|
|
||||||
response.some((e) => e.isError === true);
|
|
||||||
|
|
||||||
const isLoading = response.some((e) => e.isLoading === true);
|
const response = useGetQueryRange(
|
||||||
|
{
|
||||||
const errorMessage = response.find((e) => e.data?.error !== null)?.data?.error;
|
selectedTime: selectedTime.enum,
|
||||||
|
graphType: widget.panelTypes,
|
||||||
const data = response.map((responseOfQuery) =>
|
query: updatedQuery,
|
||||||
responseOfQuery?.data?.payload?.result.map((e, index) => ({
|
globalSelectedInterval: globalSelectedTime,
|
||||||
query: queryLength[index]?.query,
|
variables: getDashboardVariables(),
|
||||||
queryData: e,
|
},
|
||||||
legend: queryLength[index]?.legend,
|
{
|
||||||
})),
|
queryKey,
|
||||||
|
enabled: !isDependedDataLoaded,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const chartDataSet = useMemo(
|
const chartDataSet = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getChartData({
|
getChartData({
|
||||||
queryData: data.map((e) => ({
|
queryData: [
|
||||||
query: e?.map((e) => e.query).join(' ') || '',
|
{
|
||||||
queryData: e?.map((e) => e.queryData) || [],
|
queryData: response?.data?.payload?.data?.result || [],
|
||||||
legend: e?.map((e) => e.legend).join('') || '',
|
},
|
||||||
})),
|
],
|
||||||
}),
|
}),
|
||||||
[data],
|
[response],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isLoading) {
|
if (response.status === 'idle' || response.status === 'loading') {
|
||||||
return <Spinner height="100%" size="large" tip="Loading..." />;
|
return <Spinner height="100%" size="large" tip="Loading..." />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isError || data === undefined || data[0] === undefined) {
|
|
||||||
return (
|
|
||||||
<NotFoundContainer>
|
|
||||||
<Typography>{errorMessage}</Typography>
|
|
||||||
</NotFoundContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{fullViewOptions && (
|
{fullViewOptions && (
|
||||||
<TimeContainer>
|
<TimeContainer>
|
||||||
<TimePreference
|
<TimePreference
|
||||||
{...{
|
selectedTime={selectedTime}
|
||||||
selectedTime,
|
setSelectedTime={setSelectedTime}
|
||||||
setSelectedTime,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
onClick={(): void => {
|
onClick={(): void => {
|
||||||
response.forEach((e) => e.refetch());
|
response.refetch();
|
||||||
}}
|
}}
|
||||||
type="primary"
|
type="primary"
|
||||||
>
|
>
|
||||||
@ -176,12 +117,13 @@ function FullView({
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface FullViewProps {
|
interface FullViewProps {
|
||||||
widget: PromQLWidgets;
|
widget: Widgets;
|
||||||
fullViewOptions?: boolean;
|
fullViewOptions?: boolean;
|
||||||
onClickHandler?: GraphOnClickHandler;
|
onClickHandler?: GraphOnClickHandler;
|
||||||
name: string;
|
name: string;
|
||||||
yAxisUnit?: string;
|
yAxisUnit?: string;
|
||||||
onDragSelect?: (start: number, end: number) => void;
|
onDragSelect?: (start: number, end: number) => void;
|
||||||
|
isDependedDataLoaded?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
FullView.defaultProps = {
|
FullView.defaultProps = {
|
||||||
@ -189,6 +131,7 @@ FullView.defaultProps = {
|
|||||||
onClickHandler: undefined,
|
onClickHandler: undefined,
|
||||||
yAxisUnit: undefined,
|
yAxisUnit: undefined,
|
||||||
onDragSelect: undefined,
|
onDragSelect: undefined,
|
||||||
|
isDependedDataLoaded: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FullView;
|
export default FullView;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Typography } from 'antd';
|
import { Typography } from 'antd';
|
||||||
import { ChartData } from 'chart.js';
|
import { ChartData } from 'chart.js';
|
||||||
|
import { GraphOnClickHandler } from 'components/Graph';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import GridGraphComponent from 'container/GridGraphComponent';
|
import GridGraphComponent from 'container/GridGraphComponent';
|
||||||
import { UpdateDashboard } from 'container/GridGraphLayout/utils';
|
import { UpdateDashboard } from 'container/GridGraphLayout/utils';
|
||||||
@ -35,12 +36,16 @@ import { Widgets } from 'types/api/dashboard/getAll';
|
|||||||
import AppReducer from 'types/reducer/app';
|
import AppReducer from 'types/reducer/app';
|
||||||
import DashboardReducer from 'types/reducer/dashboards';
|
import DashboardReducer from 'types/reducer/dashboards';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
import {
|
||||||
|
getSelectedDashboard,
|
||||||
|
getSelectedDashboardVariable,
|
||||||
|
} from 'utils/dashboard/selectedDashboard';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
import { LayoutProps } from '..';
|
import { LayoutProps } from '..';
|
||||||
import EmptyWidget from '../EmptyWidget';
|
import EmptyWidget from '../EmptyWidget';
|
||||||
import WidgetHeader from '../WidgetHeader';
|
import WidgetHeader from '../WidgetHeader';
|
||||||
import FullView from './FullView/index.metricsBuilder';
|
import FullView from './FullView';
|
||||||
import { FullViewContainer, Modal } from './styles';
|
import { FullViewContainer, Modal } from './styles';
|
||||||
|
|
||||||
function GridCardGraph({
|
function GridCardGraph({
|
||||||
@ -51,6 +56,10 @@ function GridCardGraph({
|
|||||||
layout = [],
|
layout = [],
|
||||||
setLayout,
|
setLayout,
|
||||||
onDragSelect,
|
onDragSelect,
|
||||||
|
onClickHandler,
|
||||||
|
allowDelete,
|
||||||
|
allowClone,
|
||||||
|
allowEdit,
|
||||||
}: GridCardGraphProps): JSX.Element {
|
}: GridCardGraphProps): JSX.Element {
|
||||||
const { ref: graphRef, inView: isGraphVisible } = useInView({
|
const { ref: graphRef, inView: isGraphVisible } = useInView({
|
||||||
threshold: 0,
|
threshold: 0,
|
||||||
@ -77,9 +86,9 @@ function GridCardGraph({
|
|||||||
const { dashboards } = useSelector<AppState, DashboardReducer>(
|
const { dashboards } = useSelector<AppState, DashboardReducer>(
|
||||||
(state) => state.dashboards,
|
(state) => state.dashboards,
|
||||||
);
|
);
|
||||||
const [selectedDashboard] = dashboards;
|
|
||||||
const selectedData = selectedDashboard?.data;
|
const selectedDashboard = getSelectedDashboard(dashboards);
|
||||||
const { variables } = selectedData;
|
const variables = getSelectedDashboardVariable(dashboards);
|
||||||
|
|
||||||
const updatedQuery = useStepInterval(widget?.query);
|
const updatedQuery = useStepInterval(widget?.query);
|
||||||
|
|
||||||
@ -172,10 +181,10 @@ function GridCardGraph({
|
|||||||
h: 2,
|
h: 2,
|
||||||
y: 0,
|
y: 0,
|
||||||
},
|
},
|
||||||
...(selectedDashboard.data.layout || []),
|
...(selectedDashboard?.data.layout || []),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (widget) {
|
if (widget && selectedDashboard) {
|
||||||
await UpdateDashboard(
|
await UpdateDashboard(
|
||||||
{
|
{
|
||||||
data: selectedDashboard.data,
|
data: selectedDashboard.data,
|
||||||
@ -257,6 +266,9 @@ function GridCardGraph({
|
|||||||
onClone={onCloneHandler}
|
onClone={onCloneHandler}
|
||||||
queryResponse={queryResponse}
|
queryResponse={queryResponse}
|
||||||
errorMessage={errorMessage}
|
errorMessage={errorMessage}
|
||||||
|
allowClone={allowClone}
|
||||||
|
allowDelete={allowDelete}
|
||||||
|
allowEdit={allowEdit}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<GridGraphComponent
|
<GridGraphComponent
|
||||||
@ -267,6 +279,7 @@ function GridCardGraph({
|
|||||||
title={' '}
|
title={' '}
|
||||||
name={name}
|
name={name}
|
||||||
yAxisUnit={yAxisUnit}
|
yAxisUnit={yAxisUnit}
|
||||||
|
onClickHandler={onClickHandler}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -289,6 +302,9 @@ function GridCardGraph({
|
|||||||
onClone={onCloneHandler}
|
onClone={onCloneHandler}
|
||||||
queryResponse={queryResponse}
|
queryResponse={queryResponse}
|
||||||
errorMessage={errorMessage}
|
errorMessage={errorMessage}
|
||||||
|
allowClone={allowClone}
|
||||||
|
allowDelete={allowDelete}
|
||||||
|
allowEdit={allowEdit}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<GridGraphComponent
|
<GridGraphComponent
|
||||||
@ -299,6 +315,7 @@ function GridCardGraph({
|
|||||||
title={' '}
|
title={' '}
|
||||||
name={name}
|
name={name}
|
||||||
yAxisUnit={yAxisUnit}
|
yAxisUnit={yAxisUnit}
|
||||||
|
onClickHandler={onClickHandler}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@ -335,6 +352,9 @@ function GridCardGraph({
|
|||||||
onClone={onCloneHandler}
|
onClone={onCloneHandler}
|
||||||
queryResponse={queryResponse}
|
queryResponse={queryResponse}
|
||||||
errorMessage={errorMessage}
|
errorMessage={errorMessage}
|
||||||
|
allowClone={allowClone}
|
||||||
|
allowDelete={allowDelete}
|
||||||
|
allowEdit={allowEdit}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -351,6 +371,7 @@ function GridCardGraph({
|
|||||||
name={name}
|
name={name}
|
||||||
yAxisUnit={yAxisUnit}
|
yAxisUnit={yAxisUnit}
|
||||||
onDragSelect={onDragSelect}
|
onDragSelect={onDragSelect}
|
||||||
|
onClickHandler={onClickHandler}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -374,10 +395,18 @@ interface GridCardGraphProps extends DispatchProps {
|
|||||||
// eslint-disable-next-line react/require-default-props
|
// eslint-disable-next-line react/require-default-props
|
||||||
setLayout?: Dispatch<SetStateAction<LayoutProps[]>>;
|
setLayout?: Dispatch<SetStateAction<LayoutProps[]>>;
|
||||||
onDragSelect?: (start: number, end: number) => void;
|
onDragSelect?: (start: number, end: number) => void;
|
||||||
|
onClickHandler?: GraphOnClickHandler;
|
||||||
|
allowDelete?: boolean;
|
||||||
|
allowClone?: boolean;
|
||||||
|
allowEdit?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
GridCardGraph.defaultProps = {
|
GridCardGraph.defaultProps = {
|
||||||
onDragSelect: undefined,
|
onDragSelect: undefined,
|
||||||
|
onClickHandler: undefined,
|
||||||
|
allowDelete: true,
|
||||||
|
allowClone: true,
|
||||||
|
allowEdit: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapDispatchToProps = (
|
const mapDispatchToProps = (
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
export enum MenuItemKeys {
|
||||||
|
View = 'view',
|
||||||
|
Edit = 'edit',
|
||||||
|
Delete = 'delete',
|
||||||
|
Clone = 'clone',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MENUITEM_KEYS_VS_LABELS = {
|
||||||
|
[MenuItemKeys.View]: 'View',
|
||||||
|
[MenuItemKeys.Edit]: 'Edit',
|
||||||
|
[MenuItemKeys.Delete]: 'Delete',
|
||||||
|
[MenuItemKeys.Clone]: 'Clone',
|
||||||
|
};
|
@ -27,24 +27,29 @@ import {
|
|||||||
spinnerStyles,
|
spinnerStyles,
|
||||||
tooltipStyles,
|
tooltipStyles,
|
||||||
} from './config';
|
} from './config';
|
||||||
|
import { MENUITEM_KEYS_VS_LABELS, MenuItemKeys } from './contants';
|
||||||
import {
|
import {
|
||||||
ArrowContainer,
|
ArrowContainer,
|
||||||
HeaderContainer,
|
HeaderContainer,
|
||||||
HeaderContentContainer,
|
HeaderContentContainer,
|
||||||
} from './styles';
|
} from './styles';
|
||||||
|
import { KeyMethodMappingProps, MenuItem, TWidgetOptions } from './types';
|
||||||
|
import { generateMenuList, isTWidgetOptions } from './utils';
|
||||||
|
|
||||||
type TWidgetOptions = 'view' | 'edit' | 'delete' | string;
|
|
||||||
interface IWidgetHeaderProps {
|
interface IWidgetHeaderProps {
|
||||||
title: string;
|
title: string;
|
||||||
widget: Widgets;
|
widget: Widgets;
|
||||||
onView: VoidFunction;
|
onView: VoidFunction;
|
||||||
onDelete: VoidFunction;
|
onDelete?: VoidFunction;
|
||||||
onClone: VoidFunction;
|
onClone?: VoidFunction;
|
||||||
parentHover: boolean;
|
parentHover: boolean;
|
||||||
queryResponse: UseQueryResult<
|
queryResponse: UseQueryResult<
|
||||||
SuccessResponse<MetricRangePayloadProps> | ErrorResponse
|
SuccessResponse<MetricRangePayloadProps> | ErrorResponse
|
||||||
>;
|
>;
|
||||||
errorMessage: string | undefined;
|
errorMessage: string | undefined;
|
||||||
|
allowDelete?: boolean;
|
||||||
|
allowClone?: boolean;
|
||||||
|
allowEdit?: boolean;
|
||||||
}
|
}
|
||||||
function WidgetHeader({
|
function WidgetHeader({
|
||||||
title,
|
title,
|
||||||
@ -55,6 +60,9 @@ function WidgetHeader({
|
|||||||
parentHover,
|
parentHover,
|
||||||
queryResponse,
|
queryResponse,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
|
allowClone = true,
|
||||||
|
allowDelete = true,
|
||||||
|
allowEdit = true,
|
||||||
}: IWidgetHeaderProps): JSX.Element {
|
}: IWidgetHeaderProps): JSX.Element {
|
||||||
const [localHover, setLocalHover] = useState(false);
|
const [localHover, setLocalHover] = useState(false);
|
||||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||||
@ -70,24 +78,22 @@ function WidgetHeader({
|
|||||||
);
|
);
|
||||||
}, [widget.id, widget.panelTypes, widget.query]);
|
}, [widget.id, widget.panelTypes, widget.query]);
|
||||||
|
|
||||||
const keyMethodMapping: {
|
const keyMethodMapping: KeyMethodMappingProps<TWidgetOptions> = useMemo(
|
||||||
[K in TWidgetOptions]: { key: TWidgetOptions; method: VoidFunction };
|
|
||||||
} = useMemo(
|
|
||||||
() => ({
|
() => ({
|
||||||
view: {
|
view: {
|
||||||
key: 'view',
|
key: MenuItemKeys.View,
|
||||||
method: onView,
|
method: onView,
|
||||||
},
|
},
|
||||||
edit: {
|
edit: {
|
||||||
key: 'edit',
|
key: MenuItemKeys.Edit,
|
||||||
method: onEditHandler,
|
method: onEditHandler,
|
||||||
},
|
},
|
||||||
delete: {
|
delete: {
|
||||||
key: 'delete',
|
key: MenuItemKeys.Delete,
|
||||||
method: onDelete,
|
method: onDelete,
|
||||||
},
|
},
|
||||||
clone: {
|
clone: {
|
||||||
key: 'clone',
|
key: MenuItemKeys.Clone,
|
||||||
method: onClone,
|
method: onClone,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -95,11 +101,13 @@ function WidgetHeader({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const onMenuItemSelectHandler: MenuProps['onClick'] = useCallback(
|
const onMenuItemSelectHandler: MenuProps['onClick'] = useCallback(
|
||||||
({ key }: { key: TWidgetOptions }): void => {
|
({ key }: { key: string }): void => {
|
||||||
const functionToCall = keyMethodMapping[key]?.method;
|
if (isTWidgetOptions(key)) {
|
||||||
if (functionToCall) {
|
const functionToCall = keyMethodMapping[key]?.method;
|
||||||
functionToCall();
|
if (functionToCall) {
|
||||||
setIsOpen(false);
|
functionToCall();
|
||||||
|
setIsOpen(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[keyMethodMapping],
|
[keyMethodMapping],
|
||||||
@ -111,45 +119,53 @@ function WidgetHeader({
|
|||||||
role,
|
role,
|
||||||
);
|
);
|
||||||
|
|
||||||
const menuList: MenuItemType[] = useMemo(
|
const actions = useMemo(
|
||||||
() => [
|
(): MenuItem[] => [
|
||||||
{
|
{
|
||||||
key: keyMethodMapping.view.key,
|
key: MenuItemKeys.View,
|
||||||
icon: <FullscreenOutlined />,
|
icon: <FullscreenOutlined />,
|
||||||
|
label: MENUITEM_KEYS_VS_LABELS[MenuItemKeys.View],
|
||||||
|
isVisible: true,
|
||||||
disabled: queryResponse.isLoading,
|
disabled: queryResponse.isLoading,
|
||||||
label: 'View',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: keyMethodMapping.edit.key,
|
key: MenuItemKeys.Edit,
|
||||||
icon: <EditFilled />,
|
icon: <EditFilled />,
|
||||||
|
label: MENUITEM_KEYS_VS_LABELS[MenuItemKeys.Edit],
|
||||||
|
isVisible: allowEdit,
|
||||||
disabled: !editWidget,
|
disabled: !editWidget,
|
||||||
label: 'Edit',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: keyMethodMapping.clone.key,
|
key: MenuItemKeys.Clone,
|
||||||
icon: <CopyOutlined />,
|
icon: <CopyOutlined />,
|
||||||
|
label: MENUITEM_KEYS_VS_LABELS[MenuItemKeys.Clone],
|
||||||
|
isVisible: allowClone,
|
||||||
disabled: !editWidget,
|
disabled: !editWidget,
|
||||||
label: 'Clone',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: keyMethodMapping.delete.key,
|
key: MenuItemKeys.Delete,
|
||||||
icon: <DeleteOutlined />,
|
icon: <DeleteOutlined />,
|
||||||
|
label: MENUITEM_KEYS_VS_LABELS[MenuItemKeys.Delete],
|
||||||
|
isVisible: allowDelete,
|
||||||
disabled: !deleteWidget,
|
disabled: !deleteWidget,
|
||||||
danger: true,
|
danger: true,
|
||||||
label: 'Delete',
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
allowEdit,
|
||||||
|
allowClone,
|
||||||
|
allowDelete,
|
||||||
|
queryResponse.isLoading,
|
||||||
deleteWidget,
|
deleteWidget,
|
||||||
editWidget,
|
editWidget,
|
||||||
keyMethodMapping.delete.key,
|
|
||||||
keyMethodMapping.edit.key,
|
|
||||||
keyMethodMapping.view.key,
|
|
||||||
keyMethodMapping.clone.key,
|
|
||||||
queryResponse.isLoading,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const menuList: MenuItemType[] = useMemo(
|
||||||
|
(): MenuItemType[] => generateMenuList(actions, keyMethodMapping),
|
||||||
|
[actions, keyMethodMapping],
|
||||||
|
);
|
||||||
|
|
||||||
const onClickHandler = useCallback(() => {
|
const onClickHandler = useCallback(() => {
|
||||||
setIsOpen((open) => !open);
|
setIsOpen((open) => !open);
|
||||||
}, []);
|
}, []);
|
||||||
@ -200,4 +216,12 @@ function WidgetHeader({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WidgetHeader.defaultProps = {
|
||||||
|
onDelete: undefined,
|
||||||
|
onClone: undefined,
|
||||||
|
allowDelete: true,
|
||||||
|
allowClone: true,
|
||||||
|
allowEdit: true,
|
||||||
|
};
|
||||||
|
|
||||||
export default WidgetHeader;
|
export default WidgetHeader;
|
||||||
|
@ -9,6 +9,8 @@ export const HeaderContainer = styled.div<{ hover: boolean }>`
|
|||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
cursor: all-scroll;
|
cursor: all-scroll;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const HeaderContentContainer = styled.span`
|
export const HeaderContentContainer = styled.span`
|
||||||
|
25
frontend/src/container/GridGraphLayout/WidgetHeader/types.ts
Normal file
25
frontend/src/container/GridGraphLayout/WidgetHeader/types.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
import { MenuItemKeys } from './contants';
|
||||||
|
|
||||||
|
export interface MenuItem {
|
||||||
|
key: TWidgetOptions;
|
||||||
|
icon: ReactNode;
|
||||||
|
label: string;
|
||||||
|
isVisible: boolean;
|
||||||
|
disabled: boolean;
|
||||||
|
danger?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TWidgetOptions =
|
||||||
|
| MenuItemKeys.View
|
||||||
|
| MenuItemKeys.Edit
|
||||||
|
| MenuItemKeys.Delete
|
||||||
|
| MenuItemKeys.Clone;
|
||||||
|
|
||||||
|
export type KeyMethodMappingProps<T extends TWidgetOptions> = {
|
||||||
|
[K in T]: {
|
||||||
|
key: TWidgetOptions;
|
||||||
|
method?: VoidFunction;
|
||||||
|
};
|
||||||
|
};
|
24
frontend/src/container/GridGraphLayout/WidgetHeader/utils.ts
Normal file
24
frontend/src/container/GridGraphLayout/WidgetHeader/utils.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { MenuItemType } from 'antd/es/menu/hooks/useItems';
|
||||||
|
|
||||||
|
import { MenuItemKeys } from './contants';
|
||||||
|
import { KeyMethodMappingProps, MenuItem, TWidgetOptions } from './types';
|
||||||
|
|
||||||
|
export const generateMenuList = (
|
||||||
|
actions: MenuItem[],
|
||||||
|
keyMethodMapping: KeyMethodMappingProps<TWidgetOptions>,
|
||||||
|
): MenuItemType[] =>
|
||||||
|
actions
|
||||||
|
.filter((action: MenuItem) => action.isVisible)
|
||||||
|
.map(({ key, icon: Icon, label, disabled, ...rest }) => ({
|
||||||
|
key: keyMethodMapping[key].key,
|
||||||
|
icon: Icon,
|
||||||
|
label,
|
||||||
|
disabled,
|
||||||
|
...rest,
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const isTWidgetOptions = (value: string): value is TWidgetOptions =>
|
||||||
|
value === MenuItemKeys.View ||
|
||||||
|
value === MenuItemKeys.Edit ||
|
||||||
|
value === MenuItemKeys.Delete ||
|
||||||
|
value === MenuItemKeys.Clone;
|
@ -2,7 +2,10 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
|
|||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
export const getWidgetQueryBuilder = (query: Widgets['query']): Widgets => ({
|
export const getWidgetQueryBuilder = (
|
||||||
|
query: Widgets['query'],
|
||||||
|
title = '',
|
||||||
|
): Widgets => ({
|
||||||
description: '',
|
description: '',
|
||||||
id: v4(),
|
id: v4(),
|
||||||
isStacked: false,
|
isStacked: false,
|
||||||
@ -11,5 +14,5 @@ export const getWidgetQueryBuilder = (query: Widgets['query']): Widgets => ({
|
|||||||
panelTypes: PANEL_TYPES.TIME_SERIES,
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
query,
|
query,
|
||||||
timePreferance: 'GLOBAL_TIME',
|
timePreferance: 'GLOBAL_TIME',
|
||||||
title: '',
|
title,
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
|
import { OPERATORS } 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';
|
||||||
import { QueryBuilderData } from 'types/common/queryBuilder';
|
import { DataSource, QueryBuilderData } from 'types/common/queryBuilder';
|
||||||
|
|
||||||
|
import { DataType, FORMULA, MetricsType, WidgetKeys } from '../constant';
|
||||||
|
import { IServiceName } from '../Tabs/types';
|
||||||
import {
|
import {
|
||||||
getQueryBuilderQueries,
|
getQueryBuilderQueries,
|
||||||
getQueryBuilderQuerieswithFormula,
|
getQueryBuilderQuerieswithFormula,
|
||||||
@ -12,35 +15,42 @@ export const databaseCallsRPS = ({
|
|||||||
legend,
|
legend,
|
||||||
tagFilterItems,
|
tagFilterItems,
|
||||||
}: DatabaseCallsRPSProps): QueryBuilderData => {
|
}: DatabaseCallsRPSProps): QueryBuilderData => {
|
||||||
const metricName: BaseAutocompleteData = {
|
const autocompleteData: BaseAutocompleteData[] = [
|
||||||
dataType: 'float64',
|
|
||||||
isColumn: true,
|
|
||||||
key: 'signoz_db_latency_count',
|
|
||||||
type: null,
|
|
||||||
};
|
|
||||||
const groupBy: BaseAutocompleteData[] = [
|
|
||||||
{ dataType: 'string', isColumn: false, key: 'db_system', type: 'tag' },
|
|
||||||
];
|
|
||||||
const itemsA: TagFilterItem[] = [
|
|
||||||
{
|
{
|
||||||
id: '',
|
key: WidgetKeys.SignozDBLatencyCount,
|
||||||
key: {
|
dataType: DataType.FLOAT64,
|
||||||
dataType: 'string',
|
isColumn: true,
|
||||||
isColumn: false,
|
type: null,
|
||||||
key: 'service_name',
|
|
||||||
type: 'resource',
|
|
||||||
},
|
|
||||||
op: 'IN',
|
|
||||||
value: [`${servicename}`],
|
|
||||||
},
|
},
|
||||||
...tagFilterItems,
|
];
|
||||||
|
const groupBy: BaseAutocompleteData[] = [
|
||||||
|
{ dataType: DataType.STRING, isColumn: false, key: 'db_system', type: 'tag' },
|
||||||
|
];
|
||||||
|
const filterItems: TagFilterItem[][] = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: {
|
||||||
|
key: WidgetKeys.Service_name,
|
||||||
|
dataType: DataType.STRING,
|
||||||
|
isColumn: false,
|
||||||
|
type: MetricsType.Resource,
|
||||||
|
},
|
||||||
|
op: OPERATORS.IN,
|
||||||
|
value: [`${servicename}`],
|
||||||
|
},
|
||||||
|
...tagFilterItems,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const legends = [legend];
|
||||||
|
|
||||||
return getQueryBuilderQueries({
|
return getQueryBuilderQueries({
|
||||||
metricName,
|
autocompleteData,
|
||||||
groupBy,
|
groupBy,
|
||||||
legend,
|
legends,
|
||||||
itemsA,
|
filterItems,
|
||||||
|
dataSource: DataSource.METRICS,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -48,32 +58,29 @@ export const databaseCallsAvgDuration = ({
|
|||||||
servicename,
|
servicename,
|
||||||
tagFilterItems,
|
tagFilterItems,
|
||||||
}: DatabaseCallProps): QueryBuilderData => {
|
}: DatabaseCallProps): QueryBuilderData => {
|
||||||
const metricNameA: BaseAutocompleteData = {
|
const autocompleteDataA: BaseAutocompleteData = {
|
||||||
dataType: 'float64',
|
key: WidgetKeys.SignozDbLatencySum,
|
||||||
|
dataType: DataType.FLOAT64,
|
||||||
isColumn: true,
|
isColumn: true,
|
||||||
key: 'signoz_db_latency_sum',
|
|
||||||
type: null,
|
type: null,
|
||||||
};
|
};
|
||||||
const metricNameB: BaseAutocompleteData = {
|
const autocompleteDataB: BaseAutocompleteData = {
|
||||||
dataType: 'float64',
|
key: WidgetKeys.SignozDBLatencyCount,
|
||||||
|
dataType: DataType.FLOAT64,
|
||||||
isColumn: true,
|
isColumn: true,
|
||||||
key: 'signoz_db_latency_count',
|
|
||||||
type: null,
|
type: null,
|
||||||
};
|
};
|
||||||
const expression = 'A/B';
|
|
||||||
const legendFormula = 'Average Duration';
|
|
||||||
const legend = '';
|
|
||||||
const disabled = true;
|
|
||||||
const additionalItemsA: TagFilterItem[] = [
|
const additionalItemsA: TagFilterItem[] = [
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
key: {
|
key: {
|
||||||
dataType: 'string',
|
key: WidgetKeys.Service_name,
|
||||||
|
dataType: DataType.STRING,
|
||||||
isColumn: false,
|
isColumn: false,
|
||||||
key: 'service_name',
|
type: MetricsType.Resource,
|
||||||
type: 'resource',
|
|
||||||
},
|
},
|
||||||
op: 'IN',
|
op: OPERATORS.IN,
|
||||||
value: [`${servicename}`],
|
value: [`${servicename}`],
|
||||||
},
|
},
|
||||||
...tagFilterItems,
|
...tagFilterItems,
|
||||||
@ -81,14 +88,14 @@ export const databaseCallsAvgDuration = ({
|
|||||||
const additionalItemsB = additionalItemsA;
|
const additionalItemsB = additionalItemsA;
|
||||||
|
|
||||||
return getQueryBuilderQuerieswithFormula({
|
return getQueryBuilderQuerieswithFormula({
|
||||||
metricNameA,
|
autocompleteDataA,
|
||||||
metricNameB,
|
autocompleteDataB,
|
||||||
additionalItemsA,
|
additionalItemsA,
|
||||||
additionalItemsB,
|
additionalItemsB,
|
||||||
legend,
|
legend: '',
|
||||||
disabled,
|
disabled: true,
|
||||||
expression,
|
expression: FORMULA.DATABASE_CALLS_AVG_DURATION,
|
||||||
legendFormula,
|
legendFormula: 'Average Duration',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -97,6 +104,6 @@ interface DatabaseCallsRPSProps extends DatabaseCallProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface DatabaseCallProps {
|
interface DatabaseCallProps {
|
||||||
servicename: string | undefined;
|
servicename: IServiceName['servicename'];
|
||||||
tagFilterItems: TagFilterItem[];
|
tagFilterItems: TagFilterItem[];
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,22 @@
|
|||||||
|
import { OPERATORS } 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';
|
||||||
import { QueryBuilderData } from 'types/common/queryBuilder';
|
import { DataSource, QueryBuilderData } from 'types/common/queryBuilder';
|
||||||
|
|
||||||
|
import { DataType, FORMULA, MetricsType, WidgetKeys } from '../constant';
|
||||||
|
import { IServiceName } from '../Tabs/types';
|
||||||
import {
|
import {
|
||||||
getQueryBuilderQueries,
|
getQueryBuilderQueries,
|
||||||
getQueryBuilderQuerieswithFormula,
|
getQueryBuilderQuerieswithFormula,
|
||||||
} from './MetricsPageQueriesFactory';
|
} from './MetricsPageQueriesFactory';
|
||||||
|
|
||||||
const groupBy: BaseAutocompleteData[] = [
|
const groupBy: BaseAutocompleteData[] = [
|
||||||
{ dataType: 'string', isColumn: false, key: 'address', type: 'tag' },
|
{
|
||||||
|
dataType: DataType.STRING,
|
||||||
|
isColumn: false,
|
||||||
|
key: WidgetKeys.Address,
|
||||||
|
type: MetricsType.Tag,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const externalCallErrorPercent = ({
|
export const externalCallErrorPercent = ({
|
||||||
@ -16,39 +24,39 @@ export const externalCallErrorPercent = ({
|
|||||||
legend,
|
legend,
|
||||||
tagFilterItems,
|
tagFilterItems,
|
||||||
}: ExternalCallDurationByAddressProps): QueryBuilderData => {
|
}: ExternalCallDurationByAddressProps): QueryBuilderData => {
|
||||||
const metricNameA: BaseAutocompleteData = {
|
const autocompleteDataA: BaseAutocompleteData = {
|
||||||
dataType: 'float64',
|
key: WidgetKeys.SignozExternalCallLatencyCount,
|
||||||
|
dataType: DataType.FLOAT64,
|
||||||
isColumn: true,
|
isColumn: true,
|
||||||
key: 'signoz_external_call_latency_count',
|
|
||||||
type: null,
|
type: null,
|
||||||
};
|
};
|
||||||
const metricNameB: BaseAutocompleteData = {
|
const autocompleteDataB: BaseAutocompleteData = {
|
||||||
dataType: 'float64',
|
key: WidgetKeys.SignozExternalCallLatencyCount,
|
||||||
|
dataType: DataType.FLOAT64,
|
||||||
isColumn: true,
|
isColumn: true,
|
||||||
key: 'signoz_external_call_latency_count',
|
|
||||||
type: null,
|
type: null,
|
||||||
};
|
};
|
||||||
const additionalItemsA: TagFilterItem[] = [
|
const additionalItemsA: TagFilterItem[] = [
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
key: {
|
key: {
|
||||||
dataType: 'string',
|
key: WidgetKeys.Service_name,
|
||||||
|
dataType: DataType.STRING,
|
||||||
isColumn: false,
|
isColumn: false,
|
||||||
key: 'service_name',
|
type: MetricsType.Resource,
|
||||||
type: 'resource',
|
|
||||||
},
|
},
|
||||||
op: 'IN',
|
op: OPERATORS.IN,
|
||||||
value: [`${servicename}`],
|
value: [`${servicename}`],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
key: {
|
key: {
|
||||||
dataType: 'int64',
|
key: WidgetKeys.StatusCode,
|
||||||
|
dataType: DataType.INT64,
|
||||||
isColumn: false,
|
isColumn: false,
|
||||||
key: 'status_code',
|
type: MetricsType.Tag,
|
||||||
type: 'tag',
|
|
||||||
},
|
},
|
||||||
op: 'IN',
|
op: OPERATORS.IN,
|
||||||
value: ['STATUS_CODE_ERROR'],
|
value: ['STATUS_CODE_ERROR'],
|
||||||
},
|
},
|
||||||
...tagFilterItems,
|
...tagFilterItems,
|
||||||
@ -57,22 +65,22 @@ export const externalCallErrorPercent = ({
|
|||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
key: {
|
key: {
|
||||||
dataType: 'string',
|
key: WidgetKeys.Service_name,
|
||||||
|
dataType: DataType.STRING,
|
||||||
isColumn: false,
|
isColumn: false,
|
||||||
key: 'service_name',
|
type: MetricsType.Resource,
|
||||||
type: 'resource',
|
|
||||||
},
|
},
|
||||||
op: 'IN',
|
op: OPERATORS.IN,
|
||||||
value: [`${servicename}`],
|
value: [`${servicename}`],
|
||||||
},
|
},
|
||||||
...tagFilterItems,
|
...tagFilterItems,
|
||||||
];
|
];
|
||||||
const legendFormula = legend;
|
const legendFormula = legend;
|
||||||
const expression = 'A*100/B';
|
const expression = FORMULA.ERROR_PERCENTAGE;
|
||||||
const disabled = true;
|
const disabled = true;
|
||||||
return getQueryBuilderQuerieswithFormula({
|
return getQueryBuilderQuerieswithFormula({
|
||||||
metricNameA,
|
autocompleteDataA,
|
||||||
metricNameB,
|
autocompleteDataB,
|
||||||
additionalItemsA,
|
additionalItemsA,
|
||||||
additionalItemsB,
|
additionalItemsB,
|
||||||
legend,
|
legend,
|
||||||
@ -87,19 +95,19 @@ export const externalCallDuration = ({
|
|||||||
servicename,
|
servicename,
|
||||||
tagFilterItems,
|
tagFilterItems,
|
||||||
}: ExternalCallProps): QueryBuilderData => {
|
}: ExternalCallProps): QueryBuilderData => {
|
||||||
const metricNameA: BaseAutocompleteData = {
|
const autocompleteDataA: BaseAutocompleteData = {
|
||||||
dataType: 'float64',
|
dataType: DataType.FLOAT64,
|
||||||
isColumn: true,
|
isColumn: true,
|
||||||
key: 'signoz_external_call_latency_sum',
|
key: WidgetKeys.SignozExternalCallLatencySum,
|
||||||
type: null,
|
type: null,
|
||||||
};
|
};
|
||||||
const metricNameB: BaseAutocompleteData = {
|
const autocompleteDataB: BaseAutocompleteData = {
|
||||||
dataType: 'float64',
|
dataType: DataType.FLOAT64,
|
||||||
isColumn: true,
|
isColumn: true,
|
||||||
key: 'signoz_external_call_latency_count',
|
key: WidgetKeys.SignozExternalCallLatencyCount,
|
||||||
type: null,
|
type: null,
|
||||||
};
|
};
|
||||||
const expression = 'A/B';
|
const expression = FORMULA.DATABASE_CALLS_AVG_DURATION;
|
||||||
const legendFormula = 'Average Duration';
|
const legendFormula = 'Average Duration';
|
||||||
const legend = '';
|
const legend = '';
|
||||||
const disabled = true;
|
const disabled = true;
|
||||||
@ -107,12 +115,12 @@ export const externalCallDuration = ({
|
|||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
key: {
|
key: {
|
||||||
dataType: 'string',
|
dataType: DataType.STRING,
|
||||||
isColumn: false,
|
isColumn: false,
|
||||||
key: 'service_name',
|
key: WidgetKeys.Service_name,
|
||||||
type: 'resource',
|
type: MetricsType.Resource,
|
||||||
},
|
},
|
||||||
op: 'IN',
|
op: OPERATORS.IN,
|
||||||
value: [`${servicename}`],
|
value: [`${servicename}`],
|
||||||
},
|
},
|
||||||
...tagFilterItems,
|
...tagFilterItems,
|
||||||
@ -120,8 +128,8 @@ export const externalCallDuration = ({
|
|||||||
const additionalItemsB = additionalItemsA;
|
const additionalItemsB = additionalItemsA;
|
||||||
|
|
||||||
return getQueryBuilderQuerieswithFormula({
|
return getQueryBuilderQuerieswithFormula({
|
||||||
metricNameA,
|
autocompleteDataA,
|
||||||
metricNameB,
|
autocompleteDataB,
|
||||||
additionalItemsA,
|
additionalItemsA,
|
||||||
additionalItemsB,
|
additionalItemsB,
|
||||||
legend,
|
legend,
|
||||||
@ -136,31 +144,38 @@ export const externalCallRpsByAddress = ({
|
|||||||
legend,
|
legend,
|
||||||
tagFilterItems,
|
tagFilterItems,
|
||||||
}: ExternalCallDurationByAddressProps): QueryBuilderData => {
|
}: ExternalCallDurationByAddressProps): QueryBuilderData => {
|
||||||
const metricName: BaseAutocompleteData = {
|
const autocompleteData: BaseAutocompleteData[] = [
|
||||||
dataType: 'float64',
|
|
||||||
isColumn: true,
|
|
||||||
key: 'signoz_external_call_latency_count',
|
|
||||||
type: null,
|
|
||||||
};
|
|
||||||
const itemsA: TagFilterItem[] = [
|
|
||||||
{
|
{
|
||||||
id: '',
|
dataType: DataType.FLOAT64,
|
||||||
key: {
|
isColumn: true,
|
||||||
dataType: 'string',
|
key: WidgetKeys.SignozExternalCallLatencyCount,
|
||||||
isColumn: false,
|
type: null,
|
||||||
key: 'service_name',
|
|
||||||
type: 'resource',
|
|
||||||
},
|
|
||||||
op: 'IN',
|
|
||||||
value: [`${servicename}`],
|
|
||||||
},
|
},
|
||||||
...tagFilterItems,
|
|
||||||
];
|
];
|
||||||
|
const filterItems: TagFilterItem[][] = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: {
|
||||||
|
dataType: DataType.STRING,
|
||||||
|
isColumn: false,
|
||||||
|
key: WidgetKeys.Service_name,
|
||||||
|
type: MetricsType.Resource,
|
||||||
|
},
|
||||||
|
op: OPERATORS.IN,
|
||||||
|
value: [`${servicename}`],
|
||||||
|
},
|
||||||
|
...tagFilterItems,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
const legends: string[] = [legend];
|
||||||
return getQueryBuilderQueries({
|
return getQueryBuilderQueries({
|
||||||
metricName,
|
autocompleteData,
|
||||||
groupBy,
|
groupBy,
|
||||||
legend,
|
legends,
|
||||||
itemsA,
|
filterItems,
|
||||||
|
dataSource: DataSource.METRICS,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -169,31 +184,31 @@ export const externalCallDurationByAddress = ({
|
|||||||
legend,
|
legend,
|
||||||
tagFilterItems,
|
tagFilterItems,
|
||||||
}: ExternalCallDurationByAddressProps): QueryBuilderData => {
|
}: ExternalCallDurationByAddressProps): QueryBuilderData => {
|
||||||
const metricNameA: BaseAutocompleteData = {
|
const autocompleteDataA: BaseAutocompleteData = {
|
||||||
dataType: 'float64',
|
dataType: DataType.FLOAT64,
|
||||||
isColumn: true,
|
isColumn: true,
|
||||||
key: 'signoz_external_call_latency_sum',
|
key: WidgetKeys.SignozExternalCallLatencySum,
|
||||||
type: null,
|
type: null,
|
||||||
};
|
};
|
||||||
const metricNameB: BaseAutocompleteData = {
|
const autocompleteDataB: BaseAutocompleteData = {
|
||||||
dataType: 'float64',
|
dataType: DataType.FLOAT64,
|
||||||
isColumn: true,
|
isColumn: true,
|
||||||
key: 'signoz_external_call_latency_count',
|
key: WidgetKeys.SignozExternalCallLatencyCount,
|
||||||
type: null,
|
type: null,
|
||||||
};
|
};
|
||||||
const expression = 'A/B';
|
const expression = FORMULA.DATABASE_CALLS_AVG_DURATION;
|
||||||
const legendFormula = legend;
|
const legendFormula = legend;
|
||||||
const disabled = true;
|
const disabled = true;
|
||||||
const additionalItemsA: TagFilterItem[] = [
|
const additionalItemsA: TagFilterItem[] = [
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
key: {
|
key: {
|
||||||
dataType: 'string',
|
dataType: DataType.STRING,
|
||||||
isColumn: false,
|
isColumn: false,
|
||||||
key: 'service_name',
|
key: WidgetKeys.Service_name,
|
||||||
type: 'resource',
|
type: MetricsType.Resource,
|
||||||
},
|
},
|
||||||
op: 'IN',
|
op: OPERATORS.IN,
|
||||||
value: [`${servicename}`],
|
value: [`${servicename}`],
|
||||||
},
|
},
|
||||||
...tagFilterItems,
|
...tagFilterItems,
|
||||||
@ -201,8 +216,8 @@ export const externalCallDurationByAddress = ({
|
|||||||
const additionalItemsB = additionalItemsA;
|
const additionalItemsB = additionalItemsA;
|
||||||
|
|
||||||
return getQueryBuilderQuerieswithFormula({
|
return getQueryBuilderQuerieswithFormula({
|
||||||
metricNameA,
|
autocompleteDataA,
|
||||||
metricNameB,
|
autocompleteDataB,
|
||||||
additionalItemsA,
|
additionalItemsA,
|
||||||
additionalItemsB,
|
additionalItemsB,
|
||||||
legend,
|
legend,
|
||||||
@ -218,6 +233,6 @@ interface ExternalCallDurationByAddressProps extends ExternalCallProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ExternalCallProps {
|
export interface ExternalCallProps {
|
||||||
servicename: string | undefined;
|
servicename: IServiceName['servicename'];
|
||||||
tagFilterItems: TagFilterItem[];
|
tagFilterItems: TagFilterItem[];
|
||||||
}
|
}
|
||||||
|
@ -5,27 +5,39 @@ import {
|
|||||||
import getStep from 'lib/getStep';
|
import getStep from 'lib/getStep';
|
||||||
import store from 'store';
|
import store from 'store';
|
||||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||||
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
|
||||||
import {
|
import {
|
||||||
|
IBuilderQuery,
|
||||||
|
TagFilterItem,
|
||||||
|
} from 'types/api/queryBuilder/queryBuilderData';
|
||||||
|
import {
|
||||||
|
DataSource,
|
||||||
MetricAggregateOperator,
|
MetricAggregateOperator,
|
||||||
QueryBuilderData,
|
QueryBuilderData,
|
||||||
} from 'types/common/queryBuilder';
|
} from 'types/common/queryBuilder';
|
||||||
|
|
||||||
export const getQueryBuilderQueries = ({
|
export const getQueryBuilderQueries = ({
|
||||||
metricName,
|
autocompleteData,
|
||||||
groupBy = [],
|
groupBy = [],
|
||||||
legend,
|
legends,
|
||||||
itemsA,
|
filterItems,
|
||||||
|
aggregateOperator,
|
||||||
|
dataSource,
|
||||||
|
queryNameAndExpression,
|
||||||
}: BuilderQueriesProps): QueryBuilderData => ({
|
}: BuilderQueriesProps): QueryBuilderData => ({
|
||||||
queryFormulas: [],
|
queryFormulas: [],
|
||||||
queryData: [
|
queryData: autocompleteData.map((item, index) => {
|
||||||
{
|
const newQueryData: IBuilderQuery = {
|
||||||
...initialQueryBuilderFormValuesMap.metrics,
|
...initialQueryBuilderFormValuesMap.metrics,
|
||||||
aggregateOperator: MetricAggregateOperator.SUM_RATE,
|
aggregateOperator: ((): string => {
|
||||||
|
if (aggregateOperator) {
|
||||||
|
return aggregateOperator[index];
|
||||||
|
}
|
||||||
|
return MetricAggregateOperator.SUM_RATE;
|
||||||
|
})(),
|
||||||
disabled: false,
|
disabled: false,
|
||||||
groupBy,
|
groupBy,
|
||||||
aggregateAttribute: metricName,
|
aggregateAttribute: item,
|
||||||
legend,
|
legend: legends[index],
|
||||||
stepInterval: getStep({
|
stepInterval: getStep({
|
||||||
end: store.getState().globalTime.maxTime,
|
end: store.getState().globalTime.maxTime,
|
||||||
inputFormat: 'ns',
|
inputFormat: 'ns',
|
||||||
@ -33,16 +45,24 @@ export const getQueryBuilderQueries = ({
|
|||||||
}),
|
}),
|
||||||
reduceTo: 'sum',
|
reduceTo: 'sum',
|
||||||
filters: {
|
filters: {
|
||||||
items: itemsA,
|
items: filterItems[index],
|
||||||
op: 'AND',
|
op: 'AND',
|
||||||
},
|
},
|
||||||
},
|
dataSource,
|
||||||
],
|
};
|
||||||
|
|
||||||
|
if (queryNameAndExpression) {
|
||||||
|
newQueryData.queryName = queryNameAndExpression[index];
|
||||||
|
newQueryData.expression = queryNameAndExpression[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
return newQueryData;
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getQueryBuilderQuerieswithFormula = ({
|
export const getQueryBuilderQuerieswithFormula = ({
|
||||||
metricNameA,
|
autocompleteDataA,
|
||||||
metricNameB,
|
autocompleteDataB,
|
||||||
additionalItemsA,
|
additionalItemsA,
|
||||||
additionalItemsB,
|
additionalItemsB,
|
||||||
legend,
|
legend,
|
||||||
@ -65,7 +85,7 @@ export const getQueryBuilderQuerieswithFormula = ({
|
|||||||
disabled,
|
disabled,
|
||||||
groupBy,
|
groupBy,
|
||||||
legend,
|
legend,
|
||||||
aggregateAttribute: metricNameA,
|
aggregateAttribute: autocompleteDataA,
|
||||||
reduceTo: 'sum',
|
reduceTo: 'sum',
|
||||||
filters: {
|
filters: {
|
||||||
items: additionalItemsA,
|
items: additionalItemsA,
|
||||||
@ -83,7 +103,7 @@ export const getQueryBuilderQuerieswithFormula = ({
|
|||||||
disabled,
|
disabled,
|
||||||
groupBy,
|
groupBy,
|
||||||
legend,
|
legend,
|
||||||
aggregateAttribute: metricNameB,
|
aggregateAttribute: autocompleteDataB,
|
||||||
queryName: 'B',
|
queryName: 'B',
|
||||||
expression: 'B',
|
expression: 'B',
|
||||||
reduceTo: 'sum',
|
reduceTo: 'sum',
|
||||||
@ -101,15 +121,18 @@ export const getQueryBuilderQuerieswithFormula = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
interface BuilderQueriesProps {
|
interface BuilderQueriesProps {
|
||||||
metricName: BaseAutocompleteData;
|
autocompleteData: BaseAutocompleteData[];
|
||||||
groupBy?: BaseAutocompleteData[];
|
groupBy?: BaseAutocompleteData[];
|
||||||
legend: string;
|
legends: string[];
|
||||||
itemsA: TagFilterItem[];
|
filterItems: TagFilterItem[][];
|
||||||
|
aggregateOperator?: string[];
|
||||||
|
dataSource: DataSource;
|
||||||
|
queryNameAndExpression?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BuilderQuerieswithFormulaProps {
|
interface BuilderQuerieswithFormulaProps {
|
||||||
metricNameA: BaseAutocompleteData;
|
autocompleteDataA: BaseAutocompleteData;
|
||||||
metricNameB: BaseAutocompleteData;
|
autocompleteDataB: BaseAutocompleteData;
|
||||||
legend: string;
|
legend: string;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
groupBy?: BaseAutocompleteData[];
|
groupBy?: BaseAutocompleteData[];
|
||||||
|
@ -1,55 +1,151 @@
|
|||||||
|
import { OPERATORS } 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';
|
||||||
import { QueryBuilderData } from 'types/common/queryBuilder';
|
import { DataSource, QueryBuilderData } from 'types/common/queryBuilder';
|
||||||
|
|
||||||
|
import {
|
||||||
|
DataType,
|
||||||
|
FORMULA,
|
||||||
|
GraphTitle,
|
||||||
|
LETENCY_LEGENDS_AGGREGATEOPERATOR,
|
||||||
|
MetricsType,
|
||||||
|
OPERATION_LEGENDS,
|
||||||
|
QUERYNAME_AND_EXPRESSION,
|
||||||
|
WidgetKeys,
|
||||||
|
} from '../constant';
|
||||||
|
import { IServiceName } from '../Tabs/types';
|
||||||
import {
|
import {
|
||||||
getQueryBuilderQueries,
|
getQueryBuilderQueries,
|
||||||
getQueryBuilderQuerieswithFormula,
|
getQueryBuilderQuerieswithFormula,
|
||||||
} from './MetricsPageQueriesFactory';
|
} from './MetricsPageQueriesFactory';
|
||||||
|
|
||||||
|
export const latency = ({
|
||||||
|
servicename,
|
||||||
|
tagFilterItems,
|
||||||
|
}: LatencyProps): QueryBuilderData => {
|
||||||
|
const autocompleteData: BaseAutocompleteData[] = [
|
||||||
|
{
|
||||||
|
key: WidgetKeys.DurationNano,
|
||||||
|
dataType: DataType.FLOAT64,
|
||||||
|
isColumn: true,
|
||||||
|
type: MetricsType.Tag,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: WidgetKeys.DurationNano,
|
||||||
|
dataType: DataType.FLOAT64,
|
||||||
|
isColumn: true,
|
||||||
|
type: MetricsType.Tag,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: WidgetKeys.DurationNano,
|
||||||
|
dataType: DataType.FLOAT64,
|
||||||
|
isColumn: true,
|
||||||
|
type: MetricsType.Tag,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const filterItems: TagFilterItem[][] = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: {
|
||||||
|
key: WidgetKeys.ServiceName,
|
||||||
|
dataType: DataType.STRING,
|
||||||
|
type: MetricsType.Tag,
|
||||||
|
isColumn: true,
|
||||||
|
},
|
||||||
|
op: OPERATORS['='],
|
||||||
|
value: `${servicename}`,
|
||||||
|
},
|
||||||
|
...tagFilterItems,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: {
|
||||||
|
key: WidgetKeys.ServiceName,
|
||||||
|
dataType: DataType.STRING,
|
||||||
|
type: MetricsType.Tag,
|
||||||
|
isColumn: true,
|
||||||
|
},
|
||||||
|
op: OPERATORS['='],
|
||||||
|
value: `${servicename}`,
|
||||||
|
},
|
||||||
|
...tagFilterItems,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: {
|
||||||
|
key: WidgetKeys.ServiceName,
|
||||||
|
dataType: DataType.STRING,
|
||||||
|
type: MetricsType.Tag,
|
||||||
|
isColumn: true,
|
||||||
|
},
|
||||||
|
op: OPERATORS['='],
|
||||||
|
value: `${servicename}`,
|
||||||
|
},
|
||||||
|
...tagFilterItems,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
return getQueryBuilderQueries({
|
||||||
|
autocompleteData,
|
||||||
|
legends: LETENCY_LEGENDS_AGGREGATEOPERATOR,
|
||||||
|
filterItems,
|
||||||
|
aggregateOperator: LETENCY_LEGENDS_AGGREGATEOPERATOR,
|
||||||
|
dataSource: DataSource.TRACES,
|
||||||
|
queryNameAndExpression: QUERYNAME_AND_EXPRESSION,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const operationPerSec = ({
|
export const operationPerSec = ({
|
||||||
servicename,
|
servicename,
|
||||||
tagFilterItems,
|
tagFilterItems,
|
||||||
topLevelOperations,
|
topLevelOperations,
|
||||||
}: OperationPerSecProps): QueryBuilderData => {
|
}: OperationPerSecProps): QueryBuilderData => {
|
||||||
const metricName: BaseAutocompleteData = {
|
const autocompleteData: BaseAutocompleteData[] = [
|
||||||
dataType: 'float64',
|
{
|
||||||
isColumn: true,
|
key: WidgetKeys.SignozLatencyCount,
|
||||||
key: 'signoz_latency_count',
|
dataType: DataType.FLOAT64,
|
||||||
type: null,
|
isColumn: true,
|
||||||
};
|
type: null,
|
||||||
const legend = 'Operations';
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const itemsA: TagFilterItem[] = [
|
const filterItems: TagFilterItem[][] = [
|
||||||
{
|
[
|
||||||
id: '',
|
{
|
||||||
key: {
|
id: '',
|
||||||
dataType: 'string',
|
key: {
|
||||||
isColumn: false,
|
key: WidgetKeys.Service_name,
|
||||||
key: 'service_name',
|
dataType: DataType.STRING,
|
||||||
type: 'resource',
|
isColumn: false,
|
||||||
|
type: MetricsType.Resource,
|
||||||
|
},
|
||||||
|
op: OPERATORS.IN,
|
||||||
|
value: [`${servicename}`],
|
||||||
},
|
},
|
||||||
op: 'IN',
|
{
|
||||||
value: [`${servicename}`],
|
id: '',
|
||||||
},
|
key: {
|
||||||
{
|
key: WidgetKeys.Operation,
|
||||||
id: '',
|
dataType: DataType.STRING,
|
||||||
key: {
|
isColumn: false,
|
||||||
dataType: 'string',
|
type: MetricsType.Tag,
|
||||||
isColumn: false,
|
},
|
||||||
key: 'operation',
|
op: OPERATORS.IN,
|
||||||
type: 'tag',
|
value: topLevelOperations,
|
||||||
},
|
},
|
||||||
op: 'IN',
|
...tagFilterItems,
|
||||||
value: topLevelOperations,
|
],
|
||||||
},
|
|
||||||
...tagFilterItems,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
return getQueryBuilderQueries({
|
return getQueryBuilderQueries({
|
||||||
metricName,
|
autocompleteData,
|
||||||
legend,
|
legends: OPERATION_LEGENDS,
|
||||||
itemsA,
|
filterItems,
|
||||||
|
dataSource: DataSource.METRICS,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -58,50 +154,50 @@ export const errorPercentage = ({
|
|||||||
tagFilterItems,
|
tagFilterItems,
|
||||||
topLevelOperations,
|
topLevelOperations,
|
||||||
}: OperationPerSecProps): QueryBuilderData => {
|
}: OperationPerSecProps): QueryBuilderData => {
|
||||||
const metricNameA: BaseAutocompleteData = {
|
const autocompleteDataA: BaseAutocompleteData = {
|
||||||
dataType: 'float64',
|
key: WidgetKeys.SignozCallsTotal,
|
||||||
|
dataType: DataType.FLOAT64,
|
||||||
isColumn: true,
|
isColumn: true,
|
||||||
key: 'signoz_calls_total',
|
|
||||||
type: null,
|
type: null,
|
||||||
};
|
};
|
||||||
const metricNameB: BaseAutocompleteData = {
|
const autocompleteDataB: BaseAutocompleteData = {
|
||||||
dataType: 'float64',
|
key: WidgetKeys.SignozCallsTotal,
|
||||||
|
dataType: DataType.FLOAT64,
|
||||||
isColumn: true,
|
isColumn: true,
|
||||||
key: 'signoz_calls_total',
|
|
||||||
type: null,
|
type: null,
|
||||||
};
|
};
|
||||||
const additionalItemsA: TagFilterItem[] = [
|
const additionalItemsA: TagFilterItem[] = [
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
key: {
|
key: {
|
||||||
dataType: 'string',
|
key: WidgetKeys.Service_name,
|
||||||
|
dataType: DataType.STRING,
|
||||||
isColumn: false,
|
isColumn: false,
|
||||||
key: 'service_name',
|
type: MetricsType.Resource,
|
||||||
type: 'resource',
|
|
||||||
},
|
},
|
||||||
op: 'IN',
|
op: OPERATORS.IN,
|
||||||
value: [`${servicename}`],
|
value: [`${servicename}`],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
key: {
|
key: {
|
||||||
dataType: 'string',
|
key: WidgetKeys.Operation,
|
||||||
|
dataType: DataType.STRING,
|
||||||
isColumn: false,
|
isColumn: false,
|
||||||
key: 'operation',
|
type: MetricsType.Tag,
|
||||||
type: 'tag',
|
|
||||||
},
|
},
|
||||||
op: 'IN',
|
op: OPERATORS.IN,
|
||||||
value: topLevelOperations,
|
value: topLevelOperations,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
key: {
|
key: {
|
||||||
dataType: 'int64',
|
key: WidgetKeys.StatusCode,
|
||||||
|
dataType: DataType.INT64,
|
||||||
isColumn: false,
|
isColumn: false,
|
||||||
key: 'status_code',
|
type: MetricsType.Tag,
|
||||||
type: 'tag',
|
|
||||||
},
|
},
|
||||||
op: 'IN',
|
op: OPERATORS.IN,
|
||||||
value: ['STATUS_CODE_ERROR'],
|
value: ['STATUS_CODE_ERROR'],
|
||||||
},
|
},
|
||||||
...tagFilterItems,
|
...tagFilterItems,
|
||||||
@ -111,46 +207,47 @@ export const errorPercentage = ({
|
|||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
key: {
|
key: {
|
||||||
dataType: 'string',
|
key: WidgetKeys.Service_name,
|
||||||
|
dataType: DataType.STRING,
|
||||||
isColumn: false,
|
isColumn: false,
|
||||||
key: 'service_name',
|
type: MetricsType.Resource,
|
||||||
type: 'resource',
|
|
||||||
},
|
},
|
||||||
op: 'IN',
|
op: OPERATORS.IN,
|
||||||
value: [`${servicename}`],
|
value: [`${servicename}`],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
key: {
|
key: {
|
||||||
dataType: 'string',
|
key: WidgetKeys.Operation,
|
||||||
|
dataType: DataType.STRING,
|
||||||
isColumn: false,
|
isColumn: false,
|
||||||
key: 'operation',
|
type: MetricsType.Tag,
|
||||||
type: 'tag',
|
|
||||||
},
|
},
|
||||||
op: 'IN',
|
op: OPERATORS.IN,
|
||||||
value: topLevelOperations,
|
value: topLevelOperations,
|
||||||
},
|
},
|
||||||
...tagFilterItems,
|
...tagFilterItems,
|
||||||
];
|
];
|
||||||
|
|
||||||
const legendFormula = 'Error Percentage';
|
|
||||||
const legend = legendFormula;
|
|
||||||
const expression = 'A*100/B';
|
|
||||||
const disabled = true;
|
|
||||||
return getQueryBuilderQuerieswithFormula({
|
return getQueryBuilderQuerieswithFormula({
|
||||||
metricNameA,
|
autocompleteDataA,
|
||||||
metricNameB,
|
autocompleteDataB,
|
||||||
additionalItemsA,
|
additionalItemsA,
|
||||||
additionalItemsB,
|
additionalItemsB,
|
||||||
legend,
|
legend: GraphTitle.ERROR_PERCENTAGE,
|
||||||
disabled,
|
disabled: true,
|
||||||
expression,
|
expression: FORMULA.ERROR_PERCENTAGE,
|
||||||
legendFormula,
|
legendFormula: GraphTitle.ERROR_PERCENTAGE,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface OperationPerSecProps {
|
export interface OperationPerSecProps {
|
||||||
servicename: string | undefined;
|
servicename: IServiceName['servicename'];
|
||||||
tagFilterItems: TagFilterItem[];
|
tagFilterItems: TagFilterItem[];
|
||||||
topLevelOperations: string[];
|
topLevelOperations: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface LatencyProps {
|
||||||
|
servicename: IServiceName['servicename'];
|
||||||
|
tagFilterItems: TagFilterItem[];
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Col } from 'antd';
|
import { Col } from 'antd';
|
||||||
import FullView from 'container/GridGraphLayout/Graph/FullView/index.metricsBuilder';
|
import Graph from 'container/GridGraphLayout/Graph/';
|
||||||
import {
|
import {
|
||||||
databaseCallsAvgDuration,
|
databaseCallsAvgDuration,
|
||||||
databaseCallsRPS,
|
databaseCallsRPS,
|
||||||
@ -15,9 +15,11 @@ 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 { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
|
import { GraphTitle } from '../constant';
|
||||||
import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
|
import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
|
||||||
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
|
import { Card, GraphContainer, Row } from '../styles';
|
||||||
import { Button } from './styles';
|
import { Button } from './styles';
|
||||||
|
import { IServiceName } from './types';
|
||||||
import {
|
import {
|
||||||
dbSystemTags,
|
dbSystemTags,
|
||||||
handleNonInQueryRange,
|
handleNonInQueryRange,
|
||||||
@ -26,7 +28,7 @@ import {
|
|||||||
} from './util';
|
} from './util';
|
||||||
|
|
||||||
function DBCall(): JSX.Element {
|
function DBCall(): JSX.Element {
|
||||||
const { servicename } = useParams<{ servicename?: string }>();
|
const { servicename } = useParams<IServiceName>();
|
||||||
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
||||||
const { queries } = useResourceAttribute();
|
const { queries } = useResourceAttribute();
|
||||||
|
|
||||||
@ -48,31 +50,37 @@ function DBCall(): JSX.Element {
|
|||||||
|
|
||||||
const databaseCallsRPSWidget = useMemo(
|
const databaseCallsRPSWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder({
|
getWidgetQueryBuilder(
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
{
|
||||||
promql: [],
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
builder: databaseCallsRPS({
|
promql: [],
|
||||||
servicename,
|
builder: databaseCallsRPS({
|
||||||
legend,
|
servicename,
|
||||||
tagFilterItems,
|
legend,
|
||||||
}),
|
tagFilterItems,
|
||||||
clickhouse_sql: [],
|
}),
|
||||||
id: uuid(),
|
clickhouse_sql: [],
|
||||||
}),
|
id: uuid(),
|
||||||
|
},
|
||||||
|
GraphTitle.DATABASE_CALLS_RPS,
|
||||||
|
),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
const databaseCallsAverageDurationWidget = useMemo(
|
const databaseCallsAverageDurationWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder({
|
getWidgetQueryBuilder(
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
{
|
||||||
promql: [],
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
builder: databaseCallsAvgDuration({
|
promql: [],
|
||||||
servicename,
|
builder: databaseCallsAvgDuration({
|
||||||
tagFilterItems,
|
servicename,
|
||||||
}),
|
tagFilterItems,
|
||||||
clickhouse_sql: [],
|
}),
|
||||||
id: uuid(),
|
clickhouse_sql: [],
|
||||||
}),
|
id: uuid(),
|
||||||
|
},
|
||||||
|
GraphTitle.DATABASE_CALLS_AVG_DURATION,
|
||||||
|
),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -92,11 +100,9 @@ function DBCall(): JSX.Element {
|
|||||||
View Traces
|
View Traces
|
||||||
</Button>
|
</Button>
|
||||||
<Card>
|
<Card>
|
||||||
<GraphTitle>Database Calls RPS</GraphTitle>
|
|
||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<FullView
|
<Graph
|
||||||
name="database_call_rps"
|
name="database_call_rps"
|
||||||
fullViewOptions={false}
|
|
||||||
widget={databaseCallsRPSWidget}
|
widget={databaseCallsRPSWidget}
|
||||||
yAxisUnit="reqps"
|
yAxisUnit="reqps"
|
||||||
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
||||||
@ -108,6 +114,9 @@ function DBCall(): JSX.Element {
|
|||||||
'database_call_rps',
|
'database_call_rps',
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
allowClone={false}
|
||||||
|
allowDelete={false}
|
||||||
|
allowEdit={false}
|
||||||
/>
|
/>
|
||||||
</GraphContainer>
|
</GraphContainer>
|
||||||
</Card>
|
</Card>
|
||||||
@ -127,11 +136,9 @@ function DBCall(): JSX.Element {
|
|||||||
View Traces
|
View Traces
|
||||||
</Button>
|
</Button>
|
||||||
<Card>
|
<Card>
|
||||||
<GraphTitle>Database Calls Avg Duration</GraphTitle>
|
|
||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<FullView
|
<Graph
|
||||||
name="database_call_avg_duration"
|
name="database_call_avg_duration"
|
||||||
fullViewOptions={false}
|
|
||||||
widget={databaseCallsAverageDurationWidget}
|
widget={databaseCallsAverageDurationWidget}
|
||||||
yAxisUnit="ms"
|
yAxisUnit="ms"
|
||||||
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
||||||
@ -143,6 +150,9 @@ function DBCall(): JSX.Element {
|
|||||||
'database_call_avg_duration',
|
'database_call_avg_duration',
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
allowClone={false}
|
||||||
|
allowDelete={false}
|
||||||
|
allowEdit={false}
|
||||||
/>
|
/>
|
||||||
</GraphContainer>
|
</GraphContainer>
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Col } from 'antd';
|
import { Col } from 'antd';
|
||||||
import FullView from 'container/GridGraphLayout/Graph/FullView/index.metricsBuilder';
|
import Graph from 'container/GridGraphLayout/Graph/';
|
||||||
import {
|
import {
|
||||||
externalCallDuration,
|
externalCallDuration,
|
||||||
externalCallDurationByAddress,
|
externalCallDurationByAddress,
|
||||||
@ -16,10 +16,11 @@ import { useParams } from 'react-router-dom';
|
|||||||
import { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
|
import { GraphTitle, legend } from '../constant';
|
||||||
import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
|
import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
|
||||||
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
|
import { Card, GraphContainer, Row } from '../styles';
|
||||||
import { legend } from './constant';
|
|
||||||
import { Button } from './styles';
|
import { Button } from './styles';
|
||||||
|
import { IServiceName } from './types';
|
||||||
import {
|
import {
|
||||||
handleNonInQueryRange,
|
handleNonInQueryRange,
|
||||||
onGraphClickHandler,
|
onGraphClickHandler,
|
||||||
@ -29,7 +30,7 @@ import {
|
|||||||
function External(): JSX.Element {
|
function External(): JSX.Element {
|
||||||
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
||||||
|
|
||||||
const { servicename } = useParams<{ servicename?: string }>();
|
const { servicename } = useParams<IServiceName>();
|
||||||
const { queries } = useResourceAttribute();
|
const { queries } = useResourceAttribute();
|
||||||
|
|
||||||
const tagFilterItems = useMemo(
|
const tagFilterItems = useMemo(
|
||||||
@ -40,17 +41,20 @@ function External(): JSX.Element {
|
|||||||
|
|
||||||
const externalCallErrorWidget = useMemo(
|
const externalCallErrorWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder({
|
getWidgetQueryBuilder(
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
{
|
||||||
promql: [],
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
builder: externalCallErrorPercent({
|
promql: [],
|
||||||
servicename,
|
builder: externalCallErrorPercent({
|
||||||
legend: legend.address,
|
servicename,
|
||||||
tagFilterItems,
|
legend: legend.address,
|
||||||
}),
|
tagFilterItems,
|
||||||
clickhouse_sql: [],
|
}),
|
||||||
id: uuid(),
|
clickhouse_sql: [],
|
||||||
}),
|
id: uuid(),
|
||||||
|
},
|
||||||
|
GraphTitle.EXTERNAL_CALL_ERROR_PERCENTAGE,
|
||||||
|
),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -61,48 +65,57 @@ function External(): JSX.Element {
|
|||||||
|
|
||||||
const externalCallDurationWidget = useMemo(
|
const externalCallDurationWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder({
|
getWidgetQueryBuilder(
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
{
|
||||||
promql: [],
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
builder: externalCallDuration({
|
promql: [],
|
||||||
servicename,
|
builder: externalCallDuration({
|
||||||
tagFilterItems,
|
servicename,
|
||||||
}),
|
tagFilterItems,
|
||||||
clickhouse_sql: [],
|
}),
|
||||||
id: uuid(),
|
clickhouse_sql: [],
|
||||||
}),
|
id: uuid(),
|
||||||
|
},
|
||||||
|
GraphTitle.EXTERNAL_CALL_DURATION,
|
||||||
|
),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
const externalCallRPSWidget = useMemo(
|
const externalCallRPSWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder({
|
getWidgetQueryBuilder(
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
{
|
||||||
promql: [],
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
builder: externalCallRpsByAddress({
|
promql: [],
|
||||||
servicename,
|
builder: externalCallRpsByAddress({
|
||||||
legend: legend.address,
|
servicename,
|
||||||
tagFilterItems,
|
legend: legend.address,
|
||||||
}),
|
tagFilterItems,
|
||||||
clickhouse_sql: [],
|
}),
|
||||||
id: uuid(),
|
clickhouse_sql: [],
|
||||||
}),
|
id: uuid(),
|
||||||
|
},
|
||||||
|
GraphTitle.EXTERNAL_CALL_RPS_BY_ADDRESS,
|
||||||
|
),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
const externalCallDurationAddressWidget = useMemo(
|
const externalCallDurationAddressWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder({
|
getWidgetQueryBuilder(
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
{
|
||||||
promql: [],
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
builder: externalCallDurationByAddress({
|
promql: [],
|
||||||
servicename,
|
builder: externalCallDurationByAddress({
|
||||||
legend: legend.address,
|
servicename,
|
||||||
tagFilterItems,
|
legend: legend.address,
|
||||||
}),
|
tagFilterItems,
|
||||||
clickhouse_sql: [],
|
}),
|
||||||
id: uuid(),
|
clickhouse_sql: [],
|
||||||
}),
|
id: uuid(),
|
||||||
|
},
|
||||||
|
GraphTitle.EXTERNAL_CALL_DURATION_BY_ADDRESS,
|
||||||
|
),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -124,11 +137,9 @@ function External(): JSX.Element {
|
|||||||
View Traces
|
View Traces
|
||||||
</Button>
|
</Button>
|
||||||
<Card>
|
<Card>
|
||||||
<GraphTitle>External Call Error Percentage</GraphTitle>
|
|
||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<FullView
|
<Graph
|
||||||
name="external_call_error_percentage"
|
name="external_call_error_percentage"
|
||||||
fullViewOptions={false}
|
|
||||||
widget={externalCallErrorWidget}
|
widget={externalCallErrorWidget}
|
||||||
yAxisUnit="%"
|
yAxisUnit="%"
|
||||||
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
||||||
@ -140,6 +151,9 @@ function External(): JSX.Element {
|
|||||||
'external_call_error_percentage',
|
'external_call_error_percentage',
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
allowClone={false}
|
||||||
|
allowDelete={false}
|
||||||
|
allowEdit={false}
|
||||||
/>
|
/>
|
||||||
</GraphContainer>
|
</GraphContainer>
|
||||||
</Card>
|
</Card>
|
||||||
@ -161,11 +175,9 @@ function External(): JSX.Element {
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<GraphTitle>External Call duration</GraphTitle>
|
|
||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<FullView
|
<Graph
|
||||||
name="external_call_duration"
|
name="external_call_duration"
|
||||||
fullViewOptions={false}
|
|
||||||
widget={externalCallDurationWidget}
|
widget={externalCallDurationWidget}
|
||||||
yAxisUnit="ms"
|
yAxisUnit="ms"
|
||||||
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
||||||
@ -177,6 +189,9 @@ function External(): JSX.Element {
|
|||||||
'external_call_duration',
|
'external_call_duration',
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
allowClone={false}
|
||||||
|
allowDelete={false}
|
||||||
|
allowEdit={false}
|
||||||
/>
|
/>
|
||||||
</GraphContainer>
|
</GraphContainer>
|
||||||
</Card>
|
</Card>
|
||||||
@ -199,11 +214,9 @@ function External(): JSX.Element {
|
|||||||
View Traces
|
View Traces
|
||||||
</Button>
|
</Button>
|
||||||
<Card>
|
<Card>
|
||||||
<GraphTitle>External Call RPS(by Address)</GraphTitle>
|
|
||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<FullView
|
<Graph
|
||||||
name="external_call_rps_by_address"
|
name="external_call_rps_by_address"
|
||||||
fullViewOptions={false}
|
|
||||||
widget={externalCallRPSWidget}
|
widget={externalCallRPSWidget}
|
||||||
yAxisUnit="reqps"
|
yAxisUnit="reqps"
|
||||||
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
||||||
@ -215,6 +228,9 @@ function External(): JSX.Element {
|
|||||||
'external_call_rps_by_address',
|
'external_call_rps_by_address',
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
allowClone={false}
|
||||||
|
allowDelete={false}
|
||||||
|
allowEdit={false}
|
||||||
/>
|
/>
|
||||||
</GraphContainer>
|
</GraphContainer>
|
||||||
</Card>
|
</Card>
|
||||||
@ -236,11 +252,9 @@ function External(): JSX.Element {
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<GraphTitle>External Call duration(by Address)</GraphTitle>
|
|
||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<FullView
|
<Graph
|
||||||
name="external_call_duration_by_address"
|
name="external_call_duration_by_address"
|
||||||
fullViewOptions={false}
|
|
||||||
widget={externalCallDurationAddressWidget}
|
widget={externalCallDurationAddressWidget}
|
||||||
yAxisUnit="ms"
|
yAxisUnit="ms"
|
||||||
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
||||||
@ -252,6 +266,9 @@ function External(): JSX.Element {
|
|||||||
'external_call_duration_by_address',
|
'external_call_duration_by_address',
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
allowClone={false}
|
||||||
|
allowDelete={false}
|
||||||
|
allowEdit={false}
|
||||||
/>
|
/>
|
||||||
</GraphContainer>
|
</GraphContainer>
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -1,16 +1,9 @@
|
|||||||
import { Typography } from 'antd';
|
|
||||||
import getServiceOverview from 'api/metrics/getServiceOverview';
|
|
||||||
import getTopLevelOperations, {
|
import getTopLevelOperations, {
|
||||||
ServiceDataProps,
|
ServiceDataProps,
|
||||||
} from 'api/metrics/getTopLevelOperations';
|
} from 'api/metrics/getTopLevelOperations';
|
||||||
import getTopOperations from 'api/metrics/getTopOperations';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { ActiveElement, Chart, ChartData, ChartEvent } from 'chart.js';
|
import { ActiveElement, Chart, ChartData, ChartEvent } from 'chart.js';
|
||||||
import Graph from 'components/Graph';
|
|
||||||
import Spinner from 'components/Spinner';
|
|
||||||
import { QueryParams } from 'constants/query';
|
import { QueryParams } from 'constants/query';
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
import FullView from 'container/GridGraphLayout/Graph/FullView/index.metricsBuilder';
|
|
||||||
import { routeConfig } from 'container/SideNav/config';
|
import { routeConfig } from 'container/SideNav/config';
|
||||||
import { getQueryString } from 'container/SideNav/helper';
|
import { getQueryString } from 'container/SideNav/helper';
|
||||||
import useResourceAttribute from 'hooks/useResourceAttribute';
|
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||||
@ -18,32 +11,30 @@ import {
|
|||||||
convertRawQueriesToTraceSelectedTags,
|
convertRawQueriesToTraceSelectedTags,
|
||||||
resourceAttributesToTagFilterItems,
|
resourceAttributesToTagFilterItems,
|
||||||
} from 'hooks/useResourceAttribute/utils';
|
} from 'hooks/useResourceAttribute/utils';
|
||||||
import convertToNanoSecondsToSecond from 'lib/convertToNanoSecondsToSecond';
|
|
||||||
import { colors } from 'lib/getRandomColor';
|
|
||||||
import getStep from 'lib/getStep';
|
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import { useQueries, UseQueryResult } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { useLocation, useParams } from 'react-router-dom';
|
import { useLocation, useParams } from 'react-router-dom';
|
||||||
import { UpdateTimeInterval } from 'store/actions';
|
import { UpdateTimeInterval } from 'store/actions';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { PayloadProps } from 'types/api/metrics/getServiceOverview';
|
|
||||||
import { PayloadProps as PayloadPropsTopOpertions } from 'types/api/metrics/getTopOperations';
|
|
||||||
import { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
import { Tags } from 'types/reducer/trace';
|
import { Tags } from 'types/reducer/trace';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
import { SOMETHING_WENT_WRONG } from '../../../constants/api';
|
import { GraphTitle } from '../constant';
|
||||||
import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
|
import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
|
||||||
import {
|
import {
|
||||||
errorPercentage,
|
errorPercentage,
|
||||||
operationPerSec,
|
operationPerSec,
|
||||||
} from '../MetricsPageQueries/OverviewQueries';
|
} from '../MetricsPageQueries/OverviewQueries';
|
||||||
import { Card, Col, GraphContainer, GraphTitle, Row } from '../styles';
|
import { Col, Row } from '../styles';
|
||||||
import TopOperationsTable from '../TopOperationsTable';
|
import ServiceOverview from './Overview/ServiceOverview';
|
||||||
|
import TopLevelOperation from './Overview/TopLevelOperations';
|
||||||
|
import TopOperation from './Overview/TopOperation';
|
||||||
import { Button } from './styles';
|
import { Button } from './styles';
|
||||||
|
import { IServiceName } from './types';
|
||||||
import {
|
import {
|
||||||
handleNonInQueryRange,
|
handleNonInQueryRange,
|
||||||
onGraphClickHandler,
|
onGraphClickHandler,
|
||||||
@ -54,7 +45,7 @@ function Application(): JSX.Element {
|
|||||||
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
||||||
(state) => state.globalTime,
|
(state) => state.globalTime,
|
||||||
);
|
);
|
||||||
const { servicename } = useParams<{ servicename?: string }>();
|
const { servicename } = useParams<IServiceName>();
|
||||||
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
||||||
const { search } = useLocation();
|
const { search } = useLocation();
|
||||||
const { queries } = useResourceAttribute();
|
const { queries } = useResourceAttribute();
|
||||||
@ -86,53 +77,15 @@ function Application(): JSX.Element {
|
|||||||
[handleSetTimeStamp],
|
[handleSetTimeStamp],
|
||||||
);
|
);
|
||||||
|
|
||||||
const queryResult = useQueries<
|
const {
|
||||||
[
|
data: topLevelOperations,
|
||||||
UseQueryResult<PayloadProps>,
|
isLoading: topLevelOperationsLoading,
|
||||||
UseQueryResult<PayloadPropsTopOpertions>,
|
error: topLevelOperationsError,
|
||||||
UseQueryResult<ServiceDataProps>,
|
isError: topLevelOperationsIsError,
|
||||||
]
|
} = useQuery<ServiceDataProps>({
|
||||||
>([
|
queryKey: [servicename, minTime, maxTime, selectedTags],
|
||||||
{
|
queryFn: getTopLevelOperations,
|
||||||
queryKey: [servicename, selectedTags, minTime, maxTime],
|
});
|
||||||
queryFn: (): Promise<PayloadProps> =>
|
|
||||||
getServiceOverview({
|
|
||||||
service: servicename || '',
|
|
||||||
start: minTime,
|
|
||||||
end: maxTime,
|
|
||||||
step: getStep({
|
|
||||||
start: minTime,
|
|
||||||
end: maxTime,
|
|
||||||
inputFormat: 'ns',
|
|
||||||
}),
|
|
||||||
selectedTags,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
queryKey: [minTime, maxTime, servicename, selectedTags],
|
|
||||||
queryFn: (): Promise<PayloadPropsTopOpertions> =>
|
|
||||||
getTopOperations({
|
|
||||||
service: servicename || '',
|
|
||||||
start: minTime,
|
|
||||||
end: maxTime,
|
|
||||||
selectedTags,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
queryKey: [servicename, minTime, maxTime, selectedTags],
|
|
||||||
queryFn: (): Promise<ServiceDataProps> => getTopLevelOperations(),
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const serviceOverview = queryResult[0].data;
|
|
||||||
const serviceOverviewError = queryResult[0].error;
|
|
||||||
const serviceOverviewIsError = queryResult[0].isError;
|
|
||||||
const serviceOverviewIsLoading = queryResult[0].isLoading;
|
|
||||||
const topOperations = queryResult[1].data;
|
|
||||||
const topLevelOperations = queryResult[2].data;
|
|
||||||
const topLevelOperationsError = queryResult[2].error;
|
|
||||||
const topLevelOperationsIsError = queryResult[2].isError;
|
|
||||||
const topLevelOperationsIsLoading = queryResult[2].isLoading;
|
|
||||||
|
|
||||||
const selectedTraceTags: string = JSON.stringify(
|
const selectedTraceTags: string = JSON.stringify(
|
||||||
convertRawQueriesToTraceSelectedTags(queries) || [],
|
convertRawQueriesToTraceSelectedTags(queries) || [],
|
||||||
@ -146,37 +99,43 @@ function Application(): JSX.Element {
|
|||||||
|
|
||||||
const operationPerSecWidget = useMemo(
|
const operationPerSecWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder({
|
getWidgetQueryBuilder(
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
{
|
||||||
promql: [],
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
builder: operationPerSec({
|
promql: [],
|
||||||
servicename,
|
builder: operationPerSec({
|
||||||
tagFilterItems,
|
servicename,
|
||||||
topLevelOperations: topLevelOperations
|
tagFilterItems,
|
||||||
? topLevelOperations[servicename || '']
|
topLevelOperations: topLevelOperations
|
||||||
: [],
|
? topLevelOperations[servicename || '']
|
||||||
}),
|
: [],
|
||||||
clickhouse_sql: [],
|
}),
|
||||||
id: uuid(),
|
clickhouse_sql: [],
|
||||||
}),
|
id: uuid(),
|
||||||
|
},
|
||||||
|
GraphTitle.RATE_PER_OPS,
|
||||||
|
),
|
||||||
[servicename, topLevelOperations, tagFilterItems],
|
[servicename, topLevelOperations, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
const errorPercentageWidget = useMemo(
|
const errorPercentageWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder({
|
getWidgetQueryBuilder(
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
{
|
||||||
promql: [],
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
builder: errorPercentage({
|
promql: [],
|
||||||
servicename,
|
builder: errorPercentage({
|
||||||
tagFilterItems,
|
servicename,
|
||||||
topLevelOperations: topLevelOperations
|
tagFilterItems,
|
||||||
? topLevelOperations[servicename || '']
|
topLevelOperations: topLevelOperations
|
||||||
: [],
|
? topLevelOperations[servicename || '']
|
||||||
}),
|
: [],
|
||||||
clickhouse_sql: [],
|
}),
|
||||||
id: uuid(),
|
clickhouse_sql: [],
|
||||||
}),
|
id: uuid(),
|
||||||
|
},
|
||||||
|
GraphTitle.ERROR_PERCENTAGE,
|
||||||
|
),
|
||||||
[servicename, topLevelOperations, tagFilterItems],
|
[servicename, topLevelOperations, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -212,107 +171,17 @@ function Application(): JSX.Element {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const generalChartDataProperties = useCallback(
|
|
||||||
(title: string, colorIndex: number) => ({
|
|
||||||
borderColor: colors[colorIndex],
|
|
||||||
label: title,
|
|
||||||
showLine: true,
|
|
||||||
borderWidth: 1.5,
|
|
||||||
spanGaps: true,
|
|
||||||
pointRadius: 2,
|
|
||||||
pointHoverRadius: 4,
|
|
||||||
}),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const dataSets = useMemo(() => {
|
|
||||||
if (!serviceOverview) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
data: serviceOverview.map((e) =>
|
|
||||||
parseFloat(convertToNanoSecondsToSecond(e.p99)),
|
|
||||||
),
|
|
||||||
...generalChartDataProperties('p99 Latency', 0),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: serviceOverview.map((e) =>
|
|
||||||
parseFloat(convertToNanoSecondsToSecond(e.p95)),
|
|
||||||
),
|
|
||||||
...generalChartDataProperties('p95 Latency', 1),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: serviceOverview.map((e) =>
|
|
||||||
parseFloat(convertToNanoSecondsToSecond(e.p50)),
|
|
||||||
),
|
|
||||||
...generalChartDataProperties('p50 Latency', 2),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}, [generalChartDataProperties, serviceOverview]);
|
|
||||||
|
|
||||||
const data = useMemo(() => {
|
|
||||||
if (!serviceOverview) {
|
|
||||||
return {
|
|
||||||
datasets: [],
|
|
||||||
labels: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
datasets: dataSets,
|
|
||||||
labels: serviceOverview.map(
|
|
||||||
(e) => new Date(parseFloat(convertToNanoSecondsToSecond(e.timestamp))),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}, [serviceOverview, dataSets]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Row gutter={24}>
|
<Row gutter={24}>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Button
|
<ServiceOverview
|
||||||
type="default"
|
onDragSelect={onDragSelect}
|
||||||
size="small"
|
handleGraphClick={handleGraphClick}
|
||||||
id="Service_button"
|
selectedTimeStamp={selectedTimeStamp}
|
||||||
onClick={onViewTracePopupClick({
|
selectedTraceTags={selectedTraceTags}
|
||||||
servicename,
|
tagFilterItems={tagFilterItems}
|
||||||
selectedTraceTags,
|
/>
|
||||||
timestamp: selectedTimeStamp,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
View Traces
|
|
||||||
</Button>
|
|
||||||
<Card>
|
|
||||||
{serviceOverviewIsError ? (
|
|
||||||
<Typography>
|
|
||||||
{axios.isAxiosError(serviceOverviewError)
|
|
||||||
? serviceOverviewError.response?.data
|
|
||||||
: SOMETHING_WENT_WRONG}
|
|
||||||
</Typography>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<GraphTitle>Latency</GraphTitle>
|
|
||||||
{serviceOverviewIsLoading && (
|
|
||||||
<Spinner size="large" tip="Loading..." height="40vh" />
|
|
||||||
)}
|
|
||||||
{!serviceOverviewIsLoading && (
|
|
||||||
<GraphContainer>
|
|
||||||
<Graph
|
|
||||||
animate={false}
|
|
||||||
onClickHandler={handleGraphClick('Service')}
|
|
||||||
name="service_latency"
|
|
||||||
type="line"
|
|
||||||
data={data}
|
|
||||||
yAxisUnit="ms"
|
|
||||||
onDragSelect={onDragSelect}
|
|
||||||
/>
|
|
||||||
</GraphContainer>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
@ -328,30 +197,17 @@ function Application(): JSX.Element {
|
|||||||
>
|
>
|
||||||
View Traces
|
View Traces
|
||||||
</Button>
|
</Button>
|
||||||
<Card>
|
<TopLevelOperation
|
||||||
{topLevelOperationsIsError ? (
|
handleGraphClick={handleGraphClick}
|
||||||
<Typography>
|
onDragSelect={onDragSelect}
|
||||||
{axios.isAxiosError(topLevelOperationsError)
|
topLevelOperationsError={topLevelOperationsError}
|
||||||
? topLevelOperationsError.response?.data
|
topLevelOperationsLoading={topLevelOperationsLoading}
|
||||||
: SOMETHING_WENT_WRONG}
|
topLevelOperationsIsError={topLevelOperationsIsError}
|
||||||
</Typography>
|
name="operations_per_sec"
|
||||||
) : (
|
widget={operationPerSecWidget}
|
||||||
<>
|
yAxisUnit="ops"
|
||||||
<GraphTitle>Rate (ops/s)</GraphTitle>
|
opName="Rate"
|
||||||
<GraphContainer>
|
/>
|
||||||
<FullView
|
|
||||||
name="operations_per_sec"
|
|
||||||
fullViewOptions={false}
|
|
||||||
onClickHandler={handleGraphClick('Rate')}
|
|
||||||
widget={operationPerSecWidget}
|
|
||||||
yAxisUnit="ops"
|
|
||||||
onDragSelect={onDragSelect}
|
|
||||||
isDependedDataLoaded={topLevelOperationsIsLoading}
|
|
||||||
/>
|
|
||||||
</GraphContainer>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row gutter={24}>
|
<Row gutter={24}>
|
||||||
@ -367,43 +223,28 @@ function Application(): JSX.Element {
|
|||||||
View Traces
|
View Traces
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Card>
|
<TopLevelOperation
|
||||||
{topLevelOperationsIsError ? (
|
handleGraphClick={handleGraphClick}
|
||||||
<Typography>
|
onDragSelect={onDragSelect}
|
||||||
{axios.isAxiosError(topLevelOperationsError)
|
topLevelOperationsError={topLevelOperationsError}
|
||||||
? topLevelOperationsError.response?.data
|
topLevelOperationsLoading={topLevelOperationsLoading}
|
||||||
: SOMETHING_WENT_WRONG}
|
topLevelOperationsIsError={topLevelOperationsIsError}
|
||||||
</Typography>
|
name="error_percentage_%"
|
||||||
) : (
|
widget={errorPercentageWidget}
|
||||||
<>
|
yAxisUnit="%"
|
||||||
<GraphTitle>Error Percentage</GraphTitle>
|
opName="Error"
|
||||||
<GraphContainer>
|
/>
|
||||||
<FullView
|
|
||||||
name="error_percentage_%"
|
|
||||||
fullViewOptions={false}
|
|
||||||
onClickHandler={handleGraphClick('Error')}
|
|
||||||
widget={errorPercentageWidget}
|
|
||||||
yAxisUnit="%"
|
|
||||||
onDragSelect={onDragSelect}
|
|
||||||
isDependedDataLoaded={topLevelOperationsIsLoading}
|
|
||||||
/>
|
|
||||||
</GraphContainer>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Card>
|
<TopOperation />
|
||||||
<TopOperationsTable data={topOperations || []} />
|
|
||||||
</Card>
|
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClickHandlerType = (
|
export type ClickHandlerType = (
|
||||||
ChartEvent: ChartEvent,
|
ChartEvent: ChartEvent,
|
||||||
activeElements: ActiveElement[],
|
activeElements: ActiveElement[],
|
||||||
chart: Chart,
|
chart: Chart,
|
||||||
|
@ -0,0 +1,84 @@
|
|||||||
|
import Graph from 'container/GridGraphLayout/Graph/';
|
||||||
|
import { GraphTitle } from 'container/MetricsApplication/constant';
|
||||||
|
import { getWidgetQueryBuilder } from 'container/MetricsApplication/MetricsApplication.factory';
|
||||||
|
import { latency } from 'container/MetricsApplication/MetricsPageQueries/OverviewQueries';
|
||||||
|
import { Card, GraphContainer } from 'container/MetricsApplication/styles';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
|
import { ClickHandlerType } from '../Overview';
|
||||||
|
import { Button } from '../styles';
|
||||||
|
import { IServiceName } from '../types';
|
||||||
|
import { onViewTracePopupClick } from '../util';
|
||||||
|
|
||||||
|
function ServiceOverview({
|
||||||
|
onDragSelect,
|
||||||
|
handleGraphClick,
|
||||||
|
selectedTraceTags,
|
||||||
|
selectedTimeStamp,
|
||||||
|
tagFilterItems,
|
||||||
|
}: ServiceOverviewProps): JSX.Element {
|
||||||
|
const { servicename } = useParams<IServiceName>();
|
||||||
|
|
||||||
|
const latencyWidget = useMemo(
|
||||||
|
() =>
|
||||||
|
getWidgetQueryBuilder(
|
||||||
|
{
|
||||||
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
|
promql: [],
|
||||||
|
builder: latency({
|
||||||
|
servicename,
|
||||||
|
tagFilterItems,
|
||||||
|
}),
|
||||||
|
clickhouse_sql: [],
|
||||||
|
id: uuid(),
|
||||||
|
},
|
||||||
|
GraphTitle.LATENCY,
|
||||||
|
),
|
||||||
|
[servicename, tagFilterItems],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
type="default"
|
||||||
|
size="small"
|
||||||
|
id="Service_button"
|
||||||
|
onClick={onViewTracePopupClick({
|
||||||
|
servicename,
|
||||||
|
selectedTraceTags,
|
||||||
|
timestamp: selectedTimeStamp,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
View Traces
|
||||||
|
</Button>
|
||||||
|
<Card>
|
||||||
|
<GraphContainer>
|
||||||
|
<Graph
|
||||||
|
name="service_latency"
|
||||||
|
onDragSelect={onDragSelect}
|
||||||
|
widget={latencyWidget}
|
||||||
|
yAxisUnit="ns"
|
||||||
|
onClickHandler={handleGraphClick('Service')}
|
||||||
|
allowClone={false}
|
||||||
|
allowDelete={false}
|
||||||
|
allowEdit={false}
|
||||||
|
/>
|
||||||
|
</GraphContainer>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ServiceOverviewProps {
|
||||||
|
selectedTimeStamp: number;
|
||||||
|
selectedTraceTags: string;
|
||||||
|
onDragSelect: (start: number, end: number) => void;
|
||||||
|
handleGraphClick: (type: string) => ClickHandlerType;
|
||||||
|
tagFilterItems: TagFilterItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ServiceOverview;
|
@ -0,0 +1,65 @@
|
|||||||
|
import { Typography } from 'antd';
|
||||||
|
import axios from 'axios';
|
||||||
|
import Spinner from 'components/Spinner';
|
||||||
|
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||||
|
import Graph from 'container/GridGraphLayout/Graph/';
|
||||||
|
import { Card, GraphContainer } from 'container/MetricsApplication/styles';
|
||||||
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
|
|
||||||
|
import { ClickHandlerType } from '../Overview';
|
||||||
|
|
||||||
|
function TopLevelOperation({
|
||||||
|
name,
|
||||||
|
opName,
|
||||||
|
topLevelOperationsIsError,
|
||||||
|
topLevelOperationsError,
|
||||||
|
topLevelOperationsLoading,
|
||||||
|
onDragSelect,
|
||||||
|
handleGraphClick,
|
||||||
|
widget,
|
||||||
|
yAxisUnit,
|
||||||
|
}: TopLevelOperationProps): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
{topLevelOperationsIsError ? (
|
||||||
|
<Typography>
|
||||||
|
{axios.isAxiosError(topLevelOperationsError)
|
||||||
|
? topLevelOperationsError.response?.data
|
||||||
|
: SOMETHING_WENT_WRONG}
|
||||||
|
</Typography>
|
||||||
|
) : (
|
||||||
|
<GraphContainer>
|
||||||
|
{topLevelOperationsLoading && (
|
||||||
|
<Spinner size="large" tip="Loading..." height="40vh" />
|
||||||
|
)}
|
||||||
|
{!topLevelOperationsLoading && (
|
||||||
|
<Graph
|
||||||
|
name={name}
|
||||||
|
widget={widget}
|
||||||
|
onClickHandler={handleGraphClick(opName)}
|
||||||
|
yAxisUnit={yAxisUnit}
|
||||||
|
onDragSelect={onDragSelect}
|
||||||
|
allowClone={false}
|
||||||
|
allowDelete={false}
|
||||||
|
allowEdit={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</GraphContainer>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TopLevelOperationProps {
|
||||||
|
name: string;
|
||||||
|
opName: string;
|
||||||
|
topLevelOperationsIsError: boolean;
|
||||||
|
topLevelOperationsError: unknown;
|
||||||
|
topLevelOperationsLoading: boolean;
|
||||||
|
onDragSelect: (start: number, end: number) => void;
|
||||||
|
handleGraphClick: (type: string) => ClickHandlerType;
|
||||||
|
widget: Widgets;
|
||||||
|
yAxisUnit: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TopLevelOperation;
|
@ -0,0 +1,46 @@
|
|||||||
|
import getTopOperations from 'api/metrics/getTopOperations';
|
||||||
|
import Spinner from 'components/Spinner';
|
||||||
|
import { Card } from 'container/MetricsApplication/styles';
|
||||||
|
import TopOperationsTable from 'container/MetricsApplication/TopOperationsTable';
|
||||||
|
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||||
|
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
|
import { PayloadProps } from 'types/api/metrics/getTopOperations';
|
||||||
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
import { Tags } from 'types/reducer/trace';
|
||||||
|
|
||||||
|
function TopOperation(): JSX.Element {
|
||||||
|
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
||||||
|
(state) => state.globalTime,
|
||||||
|
);
|
||||||
|
const { servicename } = useParams<{ servicename?: string }>();
|
||||||
|
const { queries } = useResourceAttribute();
|
||||||
|
const selectedTags = useMemo(
|
||||||
|
() => (convertRawQueriesToTraceSelectedTags(queries) as Tags[]) || [],
|
||||||
|
[queries],
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data, isLoading } = useQuery<PayloadProps>({
|
||||||
|
queryKey: [minTime, maxTime, servicename, selectedTags],
|
||||||
|
queryFn: (): Promise<PayloadProps> =>
|
||||||
|
getTopOperations({
|
||||||
|
service: servicename || '',
|
||||||
|
start: minTime,
|
||||||
|
end: maxTime,
|
||||||
|
selectedTags,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
{isLoading && <Spinner size="large" tip="Loading..." height="40vh" />}
|
||||||
|
{!isLoading && <TopOperationsTable data={data || []} />}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TopOperation;
|
@ -1,3 +0,0 @@
|
|||||||
export const legend = {
|
|
||||||
address: '{{address}}',
|
|
||||||
};
|
|
3
frontend/src/container/MetricsApplication/Tabs/types.ts
Normal file
3
frontend/src/container/MetricsApplication/Tabs/types.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export interface IServiceName {
|
||||||
|
servicename: string;
|
||||||
|
}
|
53
frontend/src/container/MetricsApplication/constant.ts
Normal file
53
frontend/src/container/MetricsApplication/constant.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
export const legend = {
|
||||||
|
address: '{{address}}',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const QUERYNAME_AND_EXPRESSION = ['A', 'B', 'C'];
|
||||||
|
export const LETENCY_LEGENDS_AGGREGATEOPERATOR = ['p50', 'p90', 'p99'];
|
||||||
|
export const OPERATION_LEGENDS = ['Operations'];
|
||||||
|
|
||||||
|
export enum FORMULA {
|
||||||
|
ERROR_PERCENTAGE = 'A*100/B',
|
||||||
|
DATABASE_CALLS_AVG_DURATION = 'A/B',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum GraphTitle {
|
||||||
|
LATENCY = 'Latency',
|
||||||
|
RATE_PER_OPS = 'Rate (ops/s)',
|
||||||
|
ERROR_PERCENTAGE = 'Error Percentage',
|
||||||
|
DATABASE_CALLS_RPS = 'Database Calls RPS',
|
||||||
|
DATABASE_CALLS_AVG_DURATION = 'Database Calls Avg Duration',
|
||||||
|
EXTERNAL_CALL_ERROR_PERCENTAGE = 'External Call Error Percentage',
|
||||||
|
EXTERNAL_CALL_DURATION = 'External Call duration',
|
||||||
|
EXTERNAL_CALL_RPS_BY_ADDRESS = 'External Call RPS(by Address)',
|
||||||
|
EXTERNAL_CALL_DURATION_BY_ADDRESS = 'External Call duration(by Address)',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum DataType {
|
||||||
|
STRING = 'string',
|
||||||
|
FLOAT64 = 'float64',
|
||||||
|
INT64 = 'int64',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum MetricsType {
|
||||||
|
Tag = 'tag',
|
||||||
|
Resource = 'resource',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum WidgetKeys {
|
||||||
|
Address = 'address',
|
||||||
|
DurationNano = 'durationNano',
|
||||||
|
StatusCode = 'status_code',
|
||||||
|
Operation = 'operation',
|
||||||
|
OperationName = 'operationName',
|
||||||
|
Service_name = 'service_name',
|
||||||
|
ServiceName = 'serviceName',
|
||||||
|
SignozLatencyCount = 'signoz_latency_count',
|
||||||
|
SignozDBLatencyCount = 'signoz_db_latency_count',
|
||||||
|
DatabaseCallCount = 'signoz_database_call_count',
|
||||||
|
DatabaseCallLatencySum = 'signoz_database_call_latency_sum',
|
||||||
|
SignozDbLatencySum = 'signoz_db_latency_sum',
|
||||||
|
SignozCallsTotal = 'signoz_calls_total',
|
||||||
|
SignozExternalCallLatencyCount = 'signoz_external_call_latency_count',
|
||||||
|
SignozExternalCallLatencySum = 'signoz_external_call_latency_sum',
|
||||||
|
}
|
18
frontend/src/utils/dashboard/selectedDashboard.ts
Normal file
18
frontend/src/utils/dashboard/selectedDashboard.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Dashboard, IDashboardVariable } from 'types/api/dashboard/getAll';
|
||||||
|
|
||||||
|
export const getSelectedDashboard = (dashboard: Dashboard[]): Dashboard => {
|
||||||
|
if (dashboard.length > 0) {
|
||||||
|
return dashboard[0];
|
||||||
|
}
|
||||||
|
return {} as Dashboard;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getSelectedDashboardVariable = (
|
||||||
|
dashboard: Dashboard[],
|
||||||
|
): Record<string, IDashboardVariable> => {
|
||||||
|
if (dashboard.length > 0) {
|
||||||
|
const { variables } = dashboard[0].data;
|
||||||
|
return variables;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user