mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-07-26 18:12:02 +08:00
Dashboard Clean up and list view improvement. (#4675)
* refactor: initial setup * refactor: created panelWrapper to separate panel data * fix: type error * fix: the dimension issue for graphs * refactor: done with table value uplot panels * refactor: done with logs panel component * refactor: updated props for log panel component * fix: query range duplicate issue for logs * refactor: trace list view done * fix: full view support * refactor: done with edit mode for panels * refactor: type and props * refactor: reduce an extra api call on edit for list view * refactor: done with full graph visibility handler * refactor: removed commented code * refactor: removed commented code * fix: build failure * refactor: updated service layer graphs * refactor: updated top level oparation query key * refactor: added drag select * refactor: done with drag select in chart * refactor: code cleanup * refactor: legend should not need stage and run query
This commit is contained in:
parent
7a7d814288
commit
ec9dbb6853
@ -1,62 +1,60 @@
|
|||||||
import './WidgetFullView.styles.scss';
|
import './WidgetFullView.styles.scss';
|
||||||
|
|
||||||
import { SyncOutlined } from '@ant-design/icons';
|
import { LoadingOutlined, SyncOutlined } from '@ant-design/icons';
|
||||||
import { Button } from 'antd';
|
import { Button, Spin } from 'antd';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import { ToggleGraphProps } from 'components/Graph/types';
|
import { ToggleGraphProps } from 'components/Graph/types';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import TimePreference from 'components/TimePreferenceDropDown';
|
import TimePreference from 'components/TimePreferenceDropDown';
|
||||||
import { DEFAULT_ENTITY_VERSION } from 'constants/app';
|
import { DEFAULT_ENTITY_VERSION } from 'constants/app';
|
||||||
|
import { QueryParams } from 'constants/query';
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import GridPanelSwitch from 'container/GridPanelSwitch';
|
|
||||||
import {
|
import {
|
||||||
timeItems,
|
timeItems,
|
||||||
timePreferance,
|
timePreferance,
|
||||||
} from 'container/NewWidget/RightContainer/timeItems';
|
} from 'container/NewWidget/RightContainer/timeItems';
|
||||||
|
import PanelWrapper from 'container/PanelWrapper/PanelWrapper';
|
||||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||||
import { useStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
import { useStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
||||||
import { useChartMutable } from 'hooks/useChartMutable';
|
import { useChartMutable } from 'hooks/useChartMutable';
|
||||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
import useUrlQuery from 'hooks/useUrlQuery';
|
||||||
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
||||||
import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions';
|
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||||
import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData';
|
import GetMinMax from 'lib/getMinMax';
|
||||||
|
import history from 'lib/history';
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
import { UpdateTimeInterval } from 'store/actions';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
import uPlot from 'uplot';
|
import { getGraphType } from 'utils/getGraphType';
|
||||||
import { getSortedSeriesData } from 'utils/getSortedSeriesData';
|
import { getSortedSeriesData } from 'utils/getSortedSeriesData';
|
||||||
import { getTimeRange } from 'utils/getTimeRange';
|
|
||||||
|
|
||||||
import { getLocalStorageGraphVisibilityState } from '../utils';
|
import { getLocalStorageGraphVisibilityState } from '../utils';
|
||||||
import { PANEL_TYPES_VS_FULL_VIEW_TABLE } from './contants';
|
import { PANEL_TYPES_VS_FULL_VIEW_TABLE } from './contants';
|
||||||
import GraphManager from './GraphManager';
|
|
||||||
import { GraphContainer, TimeContainer } from './styles';
|
import { GraphContainer, TimeContainer } from './styles';
|
||||||
import { FullViewProps } from './types';
|
import { FullViewProps } from './types';
|
||||||
|
|
||||||
function FullView({
|
function FullView({
|
||||||
widget,
|
widget,
|
||||||
fullViewOptions = true,
|
fullViewOptions = true,
|
||||||
onClickHandler,
|
|
||||||
name,
|
|
||||||
version,
|
version,
|
||||||
originalName,
|
originalName,
|
||||||
yAxisUnit,
|
|
||||||
onDragSelect,
|
|
||||||
isDependedDataLoaded = false,
|
isDependedDataLoaded = false,
|
||||||
onToggleModelHandler,
|
onToggleModelHandler,
|
||||||
parentChartRef,
|
|
||||||
}: FullViewProps): JSX.Element {
|
}: FullViewProps): JSX.Element {
|
||||||
const { selectedTime: globalSelectedTime } = useSelector<
|
const { selectedTime: globalSelectedTime } = useSelector<
|
||||||
AppState,
|
AppState,
|
||||||
GlobalReducer
|
GlobalReducer
|
||||||
>((state) => state.globalTime);
|
>((state) => state.globalTime);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const urlQuery = useUrlQuery();
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
const fullViewRef = useRef<HTMLDivElement>(null);
|
const fullViewRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const [chartOptions, setChartOptions] = useState<uPlot.Options>();
|
|
||||||
|
|
||||||
const { selectedDashboard, isDashboardLocked } = useDashboard();
|
const { selectedDashboard, isDashboardLocked } = useDashboard();
|
||||||
|
|
||||||
const getSelectedTime = useCallback(
|
const getSelectedTime = useCallback(
|
||||||
@ -74,24 +72,70 @@ function FullView({
|
|||||||
|
|
||||||
const updatedQuery = useStepInterval(widget?.query);
|
const updatedQuery = useStepInterval(widget?.query);
|
||||||
|
|
||||||
const response = useGetQueryRange(
|
const [requestData, setRequestData] = useState<GetQueryResultsProps>(() => {
|
||||||
{
|
if (widget.panelTypes !== PANEL_TYPES.LIST) {
|
||||||
selectedTime: selectedTime.enum,
|
return {
|
||||||
graphType:
|
selectedTime: selectedTime.enum,
|
||||||
widget.panelTypes === PANEL_TYPES.BAR
|
graphType: getGraphType(widget.panelTypes),
|
||||||
? PANEL_TYPES.TIME_SERIES
|
query: updatedQuery,
|
||||||
: widget.panelTypes,
|
globalSelectedInterval: globalSelectedTime,
|
||||||
|
variables: getDashboardVariables(selectedDashboard?.data.variables),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
updatedQuery.builder.queryData[0].pageSize = 10;
|
||||||
|
return {
|
||||||
query: updatedQuery,
|
query: updatedQuery,
|
||||||
|
graphType: PANEL_TYPES.LIST,
|
||||||
|
selectedTime: 'GLOBAL_TIME',
|
||||||
globalSelectedInterval: globalSelectedTime,
|
globalSelectedInterval: globalSelectedTime,
|
||||||
variables: getDashboardVariables(selectedDashboard?.data.variables),
|
tableParams: {
|
||||||
},
|
pagination: {
|
||||||
|
offset: 0,
|
||||||
|
limit: updatedQuery.builder.queryData[0].limit || 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setRequestData((prev) => ({
|
||||||
|
...prev,
|
||||||
|
selectedTime: selectedTime.enum,
|
||||||
|
}));
|
||||||
|
}, [selectedTime]);
|
||||||
|
|
||||||
|
const response = useGetQueryRange(
|
||||||
|
requestData,
|
||||||
selectedDashboard?.data?.version || version || DEFAULT_ENTITY_VERSION,
|
selectedDashboard?.data?.version || version || DEFAULT_ENTITY_VERSION,
|
||||||
{
|
{
|
||||||
queryKey: `FullViewGetMetricsQueryRange-${selectedTime.enum}-${globalSelectedTime}-${widget.id}`,
|
queryKey: [widget?.query, widget?.panelTypes, requestData, version],
|
||||||
enabled: !isDependedDataLoaded && widget.panelTypes !== PANEL_TYPES.LIST, // Internally both the list view panel has it's own query range api call, so we don't need to call it again
|
enabled: !isDependedDataLoaded,
|
||||||
|
keepPreviousData: true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onDragSelect = useCallback(
|
||||||
|
(start: number, end: number): void => {
|
||||||
|
const startTimestamp = Math.trunc(start);
|
||||||
|
const endTimestamp = Math.trunc(end);
|
||||||
|
|
||||||
|
if (startTimestamp !== endTimestamp) {
|
||||||
|
dispatch(UpdateTimeInterval('custom', [startTimestamp, endTimestamp]));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { maxTime, minTime } = GetMinMax('custom', [
|
||||||
|
startTimestamp,
|
||||||
|
endTimestamp,
|
||||||
|
]);
|
||||||
|
|
||||||
|
urlQuery.set(QueryParams.startTime, minTime.toString());
|
||||||
|
urlQuery.set(QueryParams.endTime, maxTime.toString());
|
||||||
|
const generatedUrl = `${location.pathname}?${urlQuery.toString()}`;
|
||||||
|
history.push(generatedUrl);
|
||||||
|
},
|
||||||
|
[dispatch, location.pathname, urlQuery],
|
||||||
|
);
|
||||||
|
|
||||||
const [graphsVisibilityStates, setGraphsVisibilityStates] = useState<
|
const [graphsVisibilityStates, setGraphsVisibilityStates] = useState<
|
||||||
boolean[]
|
boolean[]
|
||||||
>(Array(response.data?.payload.data.result.length).fill(true));
|
>(Array(response.data?.payload.data.result.length).fill(true));
|
||||||
@ -118,60 +162,6 @@ function FullView({
|
|||||||
response.data.payload.data.result = sortedSeriesData;
|
response.data.payload.data.result = sortedSeriesData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const chartData = getUPlotChartData(response?.data?.payload, widget.fillSpans);
|
|
||||||
|
|
||||||
const isDarkMode = useIsDarkMode();
|
|
||||||
|
|
||||||
const [minTimeScale, setMinTimeScale] = useState<number>();
|
|
||||||
const [maxTimeScale, setMaxTimeScale] = useState<number>();
|
|
||||||
|
|
||||||
const { minTime, maxTime, selectedTime: globalSelectedInterval } = useSelector<
|
|
||||||
AppState,
|
|
||||||
GlobalReducer
|
|
||||||
>((state) => state.globalTime);
|
|
||||||
|
|
||||||
useEffect((): void => {
|
|
||||||
const { startTime, endTime } = getTimeRange(response);
|
|
||||||
|
|
||||||
setMinTimeScale(startTime);
|
|
||||||
setMaxTimeScale(endTime);
|
|
||||||
}, [maxTime, minTime, globalSelectedInterval, response]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!response.isFetching && fullViewRef.current) {
|
|
||||||
const width = fullViewRef.current?.clientWidth
|
|
||||||
? fullViewRef.current.clientWidth - 45
|
|
||||||
: 700;
|
|
||||||
|
|
||||||
const height = fullViewRef.current?.clientWidth
|
|
||||||
? fullViewRef.current.clientHeight
|
|
||||||
: 300;
|
|
||||||
|
|
||||||
const newChartOptions = getUPlotChartOptions({
|
|
||||||
id: originalName,
|
|
||||||
yAxisUnit: yAxisUnit || '',
|
|
||||||
apiResponse: response.data?.payload,
|
|
||||||
dimensions: {
|
|
||||||
height,
|
|
||||||
width,
|
|
||||||
},
|
|
||||||
isDarkMode,
|
|
||||||
onDragSelect,
|
|
||||||
graphsVisibilityStates,
|
|
||||||
setGraphsVisibilityStates,
|
|
||||||
thresholds: widget.thresholds,
|
|
||||||
minTimeScale,
|
|
||||||
maxTimeScale,
|
|
||||||
softMax: widget.softMax === undefined ? null : widget.softMax,
|
|
||||||
softMin: widget.softMin === undefined ? null : widget.softMin,
|
|
||||||
panelType: widget.panelTypes,
|
|
||||||
});
|
|
||||||
|
|
||||||
setChartOptions(newChartOptions);
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [response.isFetching, graphsVisibilityStates, fullViewRef.current]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
graphsVisibilityStates?.forEach((e, i) => {
|
graphsVisibilityStates?.forEach((e, i) => {
|
||||||
fullViewChartRef?.current?.toggleGraph(i, e);
|
fullViewChartRef?.current?.toggleGraph(i, e);
|
||||||
@ -180,7 +170,7 @@ function FullView({
|
|||||||
|
|
||||||
const isListView = widget.panelTypes === PANEL_TYPES.LIST;
|
const isListView = widget.panelTypes === PANEL_TYPES.LIST;
|
||||||
|
|
||||||
if (response.isFetching) {
|
if (response.isLoading && widget.panelTypes !== PANEL_TYPES.LIST) {
|
||||||
return <Spinner height="100%" size="large" tip="Loading..." />;
|
return <Spinner height="100%" size="large" tip="Loading..." />;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,6 +179,9 @@ function FullView({
|
|||||||
<div className="full-view-header-container">
|
<div className="full-view-header-container">
|
||||||
{fullViewOptions && (
|
{fullViewOptions && (
|
||||||
<TimeContainer $panelType={widget.panelTypes}>
|
<TimeContainer $panelType={widget.panelTypes}>
|
||||||
|
{response.isFetching && (
|
||||||
|
<Spin spinning indicator={<LoadingOutlined spin />} />
|
||||||
|
)}
|
||||||
<TimePreference
|
<TimePreference
|
||||||
selectedTime={selectedTime}
|
selectedTime={selectedTime}
|
||||||
setSelectedTime={setSelectedTime}
|
setSelectedTime={setSelectedTime}
|
||||||
@ -214,47 +207,24 @@ function FullView({
|
|||||||
})}
|
})}
|
||||||
ref={fullViewRef}
|
ref={fullViewRef}
|
||||||
>
|
>
|
||||||
{chartOptions && (
|
<GraphContainer
|
||||||
<GraphContainer
|
style={{
|
||||||
style={{
|
height: isListView ? '100%' : '90%',
|
||||||
height: isListView ? '100%' : '90%',
|
}}
|
||||||
}}
|
isGraphLegendToggleAvailable={canModifyChart}
|
||||||
isGraphLegendToggleAvailable={canModifyChart}
|
>
|
||||||
>
|
<PanelWrapper
|
||||||
<GridPanelSwitch
|
queryResponse={response}
|
||||||
panelType={widget.panelTypes}
|
widget={widget}
|
||||||
data={chartData}
|
setRequestData={setRequestData}
|
||||||
options={chartOptions}
|
isFullViewMode
|
||||||
onClickHandler={onClickHandler}
|
onToggleModelHandler={onToggleModelHandler}
|
||||||
name={name}
|
setGraphVisibility={setGraphsVisibilityStates}
|
||||||
yAxisUnit={yAxisUnit}
|
graphVisibility={graphsVisibilityStates}
|
||||||
onDragSelect={onDragSelect}
|
onDragSelect={onDragSelect}
|
||||||
panelData={response.data?.payload.data.newResult.data.result || []}
|
/>
|
||||||
query={widget.query}
|
</GraphContainer>
|
||||||
ref={fullViewChartRef}
|
|
||||||
thresholds={widget.thresholds}
|
|
||||||
selectedLogFields={widget.selectedLogFields}
|
|
||||||
dataSource={widget.query.builder.queryData[0].dataSource}
|
|
||||||
selectedTracesFields={widget.selectedTracesFields}
|
|
||||||
selectedTime={selectedTime}
|
|
||||||
/>
|
|
||||||
</GraphContainer>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{canModifyChart && chartOptions && !isDashboardLocked && (
|
|
||||||
<GraphManager
|
|
||||||
data={chartData}
|
|
||||||
name={originalName}
|
|
||||||
options={chartOptions}
|
|
||||||
yAxisUnit={yAxisUnit}
|
|
||||||
onToggleModelHandler={onToggleModelHandler}
|
|
||||||
setGraphsVisibilityStates={setGraphsVisibilityStates}
|
|
||||||
graphsVisibilityStates={graphsVisibilityStates}
|
|
||||||
lineChartRef={fullViewChartRef}
|
|
||||||
parentChartRef={parentChartRef}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ export const NotFoundContainer = styled.div`
|
|||||||
export const TimeContainer = styled.div<Props>`
|
export const TimeContainer = styled.div<Props>`
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
${({ $panelType }): FlattenSimpleInterpolation =>
|
${({ $panelType }): FlattenSimpleInterpolation =>
|
||||||
$panelType === PANEL_TYPES.TABLE
|
$panelType === PANEL_TYPES.TABLE
|
||||||
? css`
|
? css`
|
||||||
|
@ -53,10 +53,8 @@ export interface FullViewProps {
|
|||||||
version?: string;
|
version?: string;
|
||||||
originalName: string;
|
originalName: string;
|
||||||
yAxisUnit?: string;
|
yAxisUnit?: string;
|
||||||
onDragSelect: (start: number, end: number) => void;
|
|
||||||
isDependedDataLoaded?: boolean;
|
isDependedDataLoaded?: boolean;
|
||||||
onToggleModelHandler?: GraphManagerProps['onToggleModelHandler'];
|
onToggleModelHandler?: GraphManagerProps['onToggleModelHandler'];
|
||||||
parentChartRef: GraphManagerProps['lineChartRef'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GraphManagerProps extends UplotProps {
|
export interface GraphManagerProps extends UplotProps {
|
||||||
|
@ -6,7 +6,7 @@ import { ToggleGraphProps } from 'components/Graph/types';
|
|||||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||||
import { QueryParams } from 'constants/query';
|
import { QueryParams } from 'constants/query';
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import GridPanelSwitch from 'container/GridPanelSwitch';
|
import PanelWrapper from 'container/PanelWrapper/PanelWrapper';
|
||||||
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
import useUrlQuery from 'hooks/useUrlQuery';
|
import useUrlQuery from 'hooks/useUrlQuery';
|
||||||
@ -33,23 +33,20 @@ import FullView from './FullView';
|
|||||||
import { Modal } from './styles';
|
import { Modal } from './styles';
|
||||||
import { WidgetGraphComponentProps } from './types';
|
import { WidgetGraphComponentProps } from './types';
|
||||||
import { getLocalStorageGraphVisibilityState } from './utils';
|
import { getLocalStorageGraphVisibilityState } from './utils';
|
||||||
|
// import { getLocalStorageGraphVisibilityState } from './utils';
|
||||||
|
|
||||||
function WidgetGraphComponent({
|
function WidgetGraphComponent({
|
||||||
widget,
|
widget,
|
||||||
queryResponse,
|
queryResponse,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
name,
|
|
||||||
version,
|
version,
|
||||||
threshold,
|
threshold,
|
||||||
headerMenuList,
|
headerMenuList,
|
||||||
isWarning,
|
isWarning,
|
||||||
data,
|
isFetchingResponse,
|
||||||
options,
|
setRequestData,
|
||||||
graphVisibiltyState,
|
|
||||||
onClickHandler,
|
onClickHandler,
|
||||||
onDragSelect,
|
onDragSelect,
|
||||||
setGraphVisibility,
|
|
||||||
isFetchingResponse,
|
|
||||||
}: WidgetGraphComponentProps): JSX.Element {
|
}: WidgetGraphComponentProps): JSX.Element {
|
||||||
const [deleteModal, setDeleteModal] = useState(false);
|
const [deleteModal, setDeleteModal] = useState(false);
|
||||||
const [hovered, setHovered] = useState(false);
|
const [hovered, setHovered] = useState(false);
|
||||||
@ -61,12 +58,15 @@ function WidgetGraphComponent({
|
|||||||
const isFullViewOpen = params.get(QueryParams.expandedWidgetId) === widget.id;
|
const isFullViewOpen = params.get(QueryParams.expandedWidgetId) === widget.id;
|
||||||
|
|
||||||
const lineChartRef = useRef<ToggleGraphProps>();
|
const lineChartRef = useRef<ToggleGraphProps>();
|
||||||
|
const [graphVisibility, setGraphVisibility] = useState<boolean[]>(
|
||||||
|
Array(queryResponse.data?.payload?.data.result.length || 0).fill(true),
|
||||||
|
);
|
||||||
const graphRef = useRef<HTMLDivElement>(null);
|
const graphRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!lineChartRef.current) return;
|
if (!lineChartRef.current) return;
|
||||||
|
|
||||||
graphVisibiltyState.forEach((state, index) => {
|
graphVisibility.forEach((state, index) => {
|
||||||
lineChartRef.current?.toggleGraph(index, state);
|
lineChartRef.current?.toggleGraph(index, state);
|
||||||
});
|
});
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
@ -210,7 +210,7 @@ function WidgetGraphComponent({
|
|||||||
graphVisibilityStates: localStoredVisibilityState,
|
graphVisibilityStates: localStoredVisibilityState,
|
||||||
} = getLocalStorageGraphVisibilityState({
|
} = getLocalStorageGraphVisibilityState({
|
||||||
apiResponse: queryResponse.data.payload.data.result,
|
apiResponse: queryResponse.data.payload.data.result,
|
||||||
name,
|
name: widget.id,
|
||||||
});
|
});
|
||||||
setGraphVisibility(localStoredVisibilityState);
|
setGraphVisibility(localStoredVisibilityState);
|
||||||
}
|
}
|
||||||
@ -252,7 +252,7 @@ function WidgetGraphComponent({
|
|||||||
onBlur={(): void => {
|
onBlur={(): void => {
|
||||||
setHovered(false);
|
setHovered(false);
|
||||||
}}
|
}}
|
||||||
id={name}
|
id={widget.id}
|
||||||
>
|
>
|
||||||
<Modal
|
<Modal
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
@ -278,14 +278,12 @@ function WidgetGraphComponent({
|
|||||||
className="widget-full-view"
|
className="widget-full-view"
|
||||||
>
|
>
|
||||||
<FullView
|
<FullView
|
||||||
name={`${name}expanded`}
|
name={`${widget.id}expanded`}
|
||||||
version={version}
|
version={version}
|
||||||
originalName={name}
|
originalName={widget.id}
|
||||||
widget={widget}
|
widget={widget}
|
||||||
yAxisUnit={widget.yAxisUnit}
|
yAxisUnit={widget.yAxisUnit}
|
||||||
onToggleModelHandler={onToggleModelHandler}
|
onToggleModelHandler={onToggleModelHandler}
|
||||||
parentChartRef={lineChartRef}
|
|
||||||
onDragSelect={onDragSelect}
|
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
@ -305,26 +303,22 @@ function WidgetGraphComponent({
|
|||||||
isFetchingResponse={isFetchingResponse}
|
isFetchingResponse={isFetchingResponse}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{queryResponse.isLoading && <Skeleton />}
|
{queryResponse.isLoading && widget.panelTypes !== PANEL_TYPES.LIST && (
|
||||||
|
<Skeleton />
|
||||||
|
)}
|
||||||
{(queryResponse.isSuccess || widget.panelTypes === PANEL_TYPES.LIST) && (
|
{(queryResponse.isSuccess || widget.panelTypes === PANEL_TYPES.LIST) && (
|
||||||
<div
|
<div
|
||||||
className={cx('widget-graph-container', widget.panelTypes)}
|
className={cx('widget-graph-container', widget.panelTypes)}
|
||||||
ref={graphRef}
|
ref={graphRef}
|
||||||
>
|
>
|
||||||
<GridPanelSwitch
|
<PanelWrapper
|
||||||
panelType={widget.panelTypes}
|
widget={widget}
|
||||||
data={data}
|
queryResponse={queryResponse}
|
||||||
name={name}
|
setRequestData={setRequestData}
|
||||||
ref={lineChartRef}
|
setGraphVisibility={setGraphVisibility}
|
||||||
options={options}
|
graphVisibility={graphVisibility}
|
||||||
yAxisUnit={widget.yAxisUnit}
|
|
||||||
onClickHandler={onClickHandler}
|
onClickHandler={onClickHandler}
|
||||||
panelData={queryResponse.data?.payload?.data.newResult.data.result || []}
|
onDragSelect={onDragSelect}
|
||||||
query={widget.query}
|
|
||||||
thresholds={widget.thresholds}
|
|
||||||
selectedLogFields={widget.selectedLogFields}
|
|
||||||
dataSource={widget.query.builder?.queryData[0]?.dataSource}
|
|
||||||
selectedTracesFields={widget.selectedTracesFields}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -4,80 +4,43 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
|
|||||||
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config';
|
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config';
|
||||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||||
import { useStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
import { useStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
||||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
|
||||||
import { useResizeObserver } from 'hooks/useDimensions';
|
|
||||||
import { useIntersectionObserver } from 'hooks/useIntersectionObserver';
|
import { useIntersectionObserver } from 'hooks/useIntersectionObserver';
|
||||||
import useUrlQuery from 'hooks/useUrlQuery';
|
|
||||||
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
||||||
import GetMinMax from 'lib/getMinMax';
|
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||||
import getTimeString from 'lib/getTimeString';
|
import getTimeString from 'lib/getTimeString';
|
||||||
import history from 'lib/history';
|
|
||||||
import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions';
|
|
||||||
import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData';
|
|
||||||
import isEmpty from 'lodash-es/isEmpty';
|
import isEmpty from 'lodash-es/isEmpty';
|
||||||
import _noop from 'lodash-es/noop';
|
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { memo, useEffect, useRef, useState } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { useLocation } 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 { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
import { getGraphType } from 'utils/getGraphType';
|
import { getGraphType } from 'utils/getGraphType';
|
||||||
import { getSortedSeriesData } from 'utils/getSortedSeriesData';
|
import { getSortedSeriesData } from 'utils/getSortedSeriesData';
|
||||||
import { getTimeRange } from 'utils/getTimeRange';
|
|
||||||
|
|
||||||
import EmptyWidget from '../EmptyWidget';
|
import EmptyWidget from '../EmptyWidget';
|
||||||
import { MenuItemKeys } from '../WidgetHeader/contants';
|
import { MenuItemKeys } from '../WidgetHeader/contants';
|
||||||
import { GridCardGraphProps } from './types';
|
import { GridCardGraphProps } from './types';
|
||||||
import { getLocalStorageGraphVisibilityState } from './utils';
|
|
||||||
import WidgetGraphComponent from './WidgetGraphComponent';
|
import WidgetGraphComponent from './WidgetGraphComponent';
|
||||||
|
|
||||||
function GridCardGraph({
|
function GridCardGraph({
|
||||||
widget,
|
widget,
|
||||||
name,
|
|
||||||
onClickHandler = _noop,
|
|
||||||
headerMenuList = [MenuItemKeys.View],
|
headerMenuList = [MenuItemKeys.View],
|
||||||
isQueryEnabled,
|
isQueryEnabled,
|
||||||
threshold,
|
threshold,
|
||||||
variables,
|
variables,
|
||||||
fillSpans = false,
|
|
||||||
version,
|
version,
|
||||||
|
onClickHandler,
|
||||||
|
onDragSelect,
|
||||||
}: GridCardGraphProps): JSX.Element {
|
}: GridCardGraphProps): JSX.Element {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const [errorMessage, setErrorMessage] = useState<string>();
|
const [errorMessage, setErrorMessage] = useState<string>();
|
||||||
const { toScrollWidgetId, setToScrollWidgetId } = useDashboard();
|
const { toScrollWidgetId, setToScrollWidgetId } = useDashboard();
|
||||||
const [minTimeScale, setMinTimeScale] = useState<number>();
|
|
||||||
const [maxTimeScale, setMaxTimeScale] = useState<number>();
|
|
||||||
const urlQuery = useUrlQuery();
|
|
||||||
const location = useLocation();
|
|
||||||
const { minTime, maxTime, selectedTime: globalSelectedInterval } = useSelector<
|
const { minTime, maxTime, selectedTime: globalSelectedInterval } = useSelector<
|
||||||
AppState,
|
AppState,
|
||||||
GlobalReducer
|
GlobalReducer
|
||||||
>((state) => state.globalTime);
|
>((state) => state.globalTime);
|
||||||
|
|
||||||
const onDragSelect = useCallback(
|
|
||||||
(start: number, end: number): void => {
|
|
||||||
const startTimestamp = Math.trunc(start);
|
|
||||||
const endTimestamp = Math.trunc(end);
|
|
||||||
|
|
||||||
if (startTimestamp !== endTimestamp) {
|
|
||||||
dispatch(UpdateTimeInterval('custom', [startTimestamp, endTimestamp]));
|
|
||||||
}
|
|
||||||
|
|
||||||
const { maxTime, minTime } = GetMinMax('custom', [
|
|
||||||
startTimestamp,
|
|
||||||
endTimestamp,
|
|
||||||
]);
|
|
||||||
|
|
||||||
urlQuery.set(QueryParams.startTime, minTime.toString());
|
|
||||||
urlQuery.set(QueryParams.endTime, maxTime.toString());
|
|
||||||
const generatedUrl = `${location.pathname}?${urlQuery.toString()}`;
|
|
||||||
history.push(generatedUrl);
|
|
||||||
},
|
|
||||||
[dispatch, location.pathname, urlQuery],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleBackNavigation = (): void => {
|
const handleBackNavigation = (): void => {
|
||||||
const searchParams = new URLSearchParams(window.location.search);
|
const searchParams = new URLSearchParams(window.location.search);
|
||||||
const startTime = searchParams.get(QueryParams.startTime);
|
const startTime = searchParams.get(QueryParams.startTime);
|
||||||
@ -127,19 +90,39 @@ function GridCardGraph({
|
|||||||
const isEmptyWidget =
|
const isEmptyWidget =
|
||||||
widget?.id === PANEL_TYPES.EMPTY_WIDGET || isEmpty(widget);
|
widget?.id === PANEL_TYPES.EMPTY_WIDGET || isEmpty(widget);
|
||||||
|
|
||||||
const queryEnabledCondition =
|
const queryEnabledCondition = isVisible && !isEmptyWidget && isQueryEnabled;
|
||||||
isVisible &&
|
|
||||||
!isEmptyWidget &&
|
const [requestData, setRequestData] = useState<GetQueryResultsProps>(() => {
|
||||||
isQueryEnabled &&
|
if (widget.panelTypes !== PANEL_TYPES.LIST) {
|
||||||
widget.panelTypes !== PANEL_TYPES.LIST;
|
return {
|
||||||
|
selectedTime: widget?.timePreferance,
|
||||||
|
graphType: getGraphType(widget.panelTypes),
|
||||||
|
query: updatedQuery,
|
||||||
|
globalSelectedInterval,
|
||||||
|
variables: getDashboardVariables(variables),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
updatedQuery.builder.queryData[0].pageSize = 10;
|
||||||
|
return {
|
||||||
|
query: updatedQuery,
|
||||||
|
graphType: PANEL_TYPES.LIST,
|
||||||
|
selectedTime: 'GLOBAL_TIME',
|
||||||
|
globalSelectedInterval,
|
||||||
|
tableParams: {
|
||||||
|
pagination: {
|
||||||
|
offset: 0,
|
||||||
|
limit: updatedQuery.builder.queryData[0].limit || 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const queryResponse = useGetQueryRange(
|
const queryResponse = useGetQueryRange(
|
||||||
{
|
{
|
||||||
selectedTime: widget?.timePreferance,
|
...requestData,
|
||||||
graphType: getGraphType(widget.panelTypes),
|
|
||||||
query: updatedQuery,
|
|
||||||
globalSelectedInterval,
|
|
||||||
variables: getDashboardVariables(variables),
|
variables: getDashboardVariables(variables),
|
||||||
|
selectedTime: 'GLOBAL_TIME',
|
||||||
|
globalSelectedInterval,
|
||||||
},
|
},
|
||||||
version || DEFAULT_ENTITY_VERSION,
|
version || DEFAULT_ENTITY_VERSION,
|
||||||
{
|
{
|
||||||
@ -151,6 +134,7 @@ function GridCardGraph({
|
|||||||
widget?.query,
|
widget?.query,
|
||||||
widget?.panelTypes,
|
widget?.panelTypes,
|
||||||
widget.timePreferance,
|
widget.timePreferance,
|
||||||
|
requestData,
|
||||||
],
|
],
|
||||||
retry(failureCount, error): boolean {
|
retry(failureCount, error): boolean {
|
||||||
if (
|
if (
|
||||||
@ -173,15 +157,6 @@ function GridCardGraph({
|
|||||||
|
|
||||||
const isEmptyLayout = widget?.id === PANEL_TYPES.EMPTY_WIDGET;
|
const isEmptyLayout = widget?.id === PANEL_TYPES.EMPTY_WIDGET;
|
||||||
|
|
||||||
const containerDimensions = useResizeObserver(graphRef);
|
|
||||||
|
|
||||||
useEffect((): void => {
|
|
||||||
const { startTime, endTime } = getTimeRange(queryResponse);
|
|
||||||
|
|
||||||
setMinTimeScale(startTime);
|
|
||||||
setMaxTimeScale(endTime);
|
|
||||||
}, [maxTime, minTime, globalSelectedInterval, queryResponse]);
|
|
||||||
|
|
||||||
if (queryResponse.data && widget.panelTypes === PANEL_TYPES.BAR) {
|
if (queryResponse.data && widget.panelTypes === PANEL_TYPES.BAR) {
|
||||||
const sortedSeriesData = getSortedSeriesData(
|
const sortedSeriesData = getSortedSeriesData(
|
||||||
queryResponse.data?.payload.data.result,
|
queryResponse.data?.payload.data.result,
|
||||||
@ -189,89 +164,29 @@ function GridCardGraph({
|
|||||||
queryResponse.data.payload.data.result = sortedSeriesData;
|
queryResponse.data.payload.data.result = sortedSeriesData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const chartData = getUPlotChartData(queryResponse?.data?.payload, fillSpans);
|
|
||||||
|
|
||||||
const isDarkMode = useIsDarkMode();
|
|
||||||
|
|
||||||
const menuList =
|
const menuList =
|
||||||
widget.panelTypes === PANEL_TYPES.TABLE ||
|
widget.panelTypes === PANEL_TYPES.TABLE ||
|
||||||
widget.panelTypes === PANEL_TYPES.LIST
|
widget.panelTypes === PANEL_TYPES.LIST
|
||||||
? headerMenuList.filter((menu) => menu !== MenuItemKeys.CreateAlerts)
|
? headerMenuList.filter((menu) => menu !== MenuItemKeys.CreateAlerts)
|
||||||
: headerMenuList;
|
: headerMenuList;
|
||||||
|
|
||||||
const [graphVisibility, setGraphVisibility] = useState<boolean[]>(
|
|
||||||
Array(queryResponse.data?.payload?.data.result.length || 0).fill(true),
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const {
|
|
||||||
graphVisibilityStates: localStoredVisibilityState,
|
|
||||||
} = getLocalStorageGraphVisibilityState({
|
|
||||||
apiResponse: queryResponse.data?.payload.data.result || [],
|
|
||||||
name,
|
|
||||||
});
|
|
||||||
setGraphVisibility(localStoredVisibilityState);
|
|
||||||
}, [name, queryResponse.data?.payload.data.result]);
|
|
||||||
|
|
||||||
const options = useMemo(
|
|
||||||
() =>
|
|
||||||
getUPlotChartOptions({
|
|
||||||
id: widget?.id,
|
|
||||||
apiResponse: queryResponse.data?.payload,
|
|
||||||
dimensions: containerDimensions,
|
|
||||||
isDarkMode,
|
|
||||||
onDragSelect,
|
|
||||||
yAxisUnit: widget?.yAxisUnit,
|
|
||||||
onClickHandler,
|
|
||||||
thresholds: widget.thresholds,
|
|
||||||
minTimeScale,
|
|
||||||
maxTimeScale,
|
|
||||||
softMax: widget.softMax === undefined ? null : widget.softMax,
|
|
||||||
softMin: widget.softMin === undefined ? null : widget.softMin,
|
|
||||||
graphsVisibilityStates: graphVisibility,
|
|
||||||
setGraphsVisibilityStates: setGraphVisibility,
|
|
||||||
panelType: widget.panelTypes,
|
|
||||||
}),
|
|
||||||
[
|
|
||||||
widget?.id,
|
|
||||||
widget?.yAxisUnit,
|
|
||||||
widget.thresholds,
|
|
||||||
widget.softMax,
|
|
||||||
widget.softMin,
|
|
||||||
queryResponse.data?.payload,
|
|
||||||
containerDimensions,
|
|
||||||
isDarkMode,
|
|
||||||
onDragSelect,
|
|
||||||
onClickHandler,
|
|
||||||
minTimeScale,
|
|
||||||
maxTimeScale,
|
|
||||||
graphVisibility,
|
|
||||||
setGraphVisibility,
|
|
||||||
widget.panelTypes,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: '100%', width: '100%' }} ref={graphRef}>
|
<div style={{ height: '100%', width: '100%' }} ref={graphRef}>
|
||||||
{isEmptyLayout ? (
|
{isEmptyLayout ? (
|
||||||
<EmptyWidget />
|
<EmptyWidget />
|
||||||
) : (
|
) : (
|
||||||
<WidgetGraphComponent
|
<WidgetGraphComponent
|
||||||
data={chartData}
|
|
||||||
options={options}
|
|
||||||
widget={widget}
|
widget={widget}
|
||||||
queryResponse={queryResponse}
|
queryResponse={queryResponse}
|
||||||
errorMessage={errorMessage}
|
errorMessage={errorMessage}
|
||||||
isWarning={false}
|
isWarning={false}
|
||||||
name={name}
|
|
||||||
version={version}
|
version={version}
|
||||||
onDragSelect={onDragSelect}
|
|
||||||
threshold={threshold}
|
threshold={threshold}
|
||||||
headerMenuList={menuList}
|
headerMenuList={menuList}
|
||||||
onClickHandler={onClickHandler}
|
|
||||||
graphVisibiltyState={graphVisibility}
|
|
||||||
setGraphVisibility={setGraphVisibility}
|
|
||||||
isFetchingResponse={queryResponse.isFetching}
|
isFetchingResponse={queryResponse.isFetching}
|
||||||
|
setRequestData={setRequestData}
|
||||||
|
onClickHandler={onClickHandler}
|
||||||
|
onDragSelect={onDragSelect}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { ToggleGraphProps } from 'components/Graph/types';
|
import { ToggleGraphProps } from 'components/Graph/types';
|
||||||
import { UplotProps } from 'components/Uplot/Uplot';
|
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||||
import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin';
|
import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin';
|
||||||
import { Dispatch, MutableRefObject, ReactNode, SetStateAction } from 'react';
|
import { Dispatch, MutableRefObject, ReactNode, SetStateAction } from 'react';
|
||||||
import { UseQueryResult } from 'react-query';
|
import { UseQueryResult } from 'react-query';
|
||||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
import { SuccessResponse } from 'types/api';
|
||||||
import { Dashboard, Widgets } from 'types/api/dashboard/getAll';
|
import { Dashboard, Widgets } from 'types/api/dashboard/getAll';
|
||||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||||
import uPlot from 'uplot';
|
import uPlot from 'uplot';
|
||||||
@ -16,35 +16,32 @@ export interface GraphVisibilityLegendEntryProps {
|
|||||||
legendEntry: LegendEntryProps[];
|
legendEntry: LegendEntryProps[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WidgetGraphComponentProps extends UplotProps {
|
export interface WidgetGraphComponentProps {
|
||||||
widget: Widgets;
|
widget: Widgets;
|
||||||
queryResponse: UseQueryResult<
|
queryResponse: UseQueryResult<
|
||||||
SuccessResponse<MetricRangePayloadProps> | ErrorResponse
|
SuccessResponse<MetricRangePayloadProps, unknown>,
|
||||||
|
Error
|
||||||
>;
|
>;
|
||||||
errorMessage: string | undefined;
|
errorMessage: string | undefined;
|
||||||
name: string;
|
|
||||||
version?: string;
|
version?: string;
|
||||||
onDragSelect: (start: number, end: number) => void;
|
|
||||||
onClickHandler?: OnClickPluginOpts['onClick'];
|
|
||||||
threshold?: ReactNode;
|
threshold?: ReactNode;
|
||||||
headerMenuList: MenuItemKeys[];
|
headerMenuList: MenuItemKeys[];
|
||||||
isWarning: boolean;
|
isWarning: boolean;
|
||||||
graphVisibiltyState: boolean[];
|
|
||||||
setGraphVisibility: Dispatch<SetStateAction<boolean[]>>;
|
|
||||||
isFetchingResponse: boolean;
|
isFetchingResponse: boolean;
|
||||||
|
setRequestData?: Dispatch<SetStateAction<GetQueryResultsProps>>;
|
||||||
|
onClickHandler?: OnClickPluginOpts['onClick'];
|
||||||
|
onDragSelect: (start: number, end: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GridCardGraphProps {
|
export interface GridCardGraphProps {
|
||||||
widget: Widgets;
|
widget: Widgets;
|
||||||
name: string;
|
|
||||||
onDragSelect?: (start: number, end: number) => void;
|
|
||||||
onClickHandler?: OnClickPluginOpts['onClick'];
|
|
||||||
threshold?: ReactNode;
|
threshold?: ReactNode;
|
||||||
headerMenuList?: WidgetGraphComponentProps['headerMenuList'];
|
headerMenuList?: WidgetGraphComponentProps['headerMenuList'];
|
||||||
|
onClickHandler?: OnClickPluginOpts['onClick'];
|
||||||
isQueryEnabled: boolean;
|
isQueryEnabled: boolean;
|
||||||
variables?: Dashboard['data']['variables'];
|
variables?: Dashboard['data']['variables'];
|
||||||
fillSpans?: boolean;
|
|
||||||
version?: string;
|
version?: string;
|
||||||
|
onDragSelect: (start: number, end: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GetGraphVisibilityStateOnLegendClickProps {
|
export interface GetGraphVisibilityStateOnLegendClickProps {
|
||||||
|
@ -3,20 +3,25 @@ import './GridCardLayout.styles.scss';
|
|||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
import { Tooltip } from 'antd';
|
import { Tooltip } from 'antd';
|
||||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||||
|
import { QueryParams } from 'constants/query';
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import { themeColors } from 'constants/theme';
|
import { themeColors } from 'constants/theme';
|
||||||
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
||||||
import useComponentPermission from 'hooks/useComponentPermission';
|
import useComponentPermission from 'hooks/useComponentPermission';
|
||||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
|
import useUrlQuery from 'hooks/useUrlQuery';
|
||||||
|
import history from 'lib/history';
|
||||||
import isEqual from 'lodash-es/isEqual';
|
import isEqual from 'lodash-es/isEqual';
|
||||||
import { FullscreenIcon } from 'lucide-react';
|
import { FullscreenIcon } from 'lucide-react';
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||||
import { useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { FullScreen, useFullScreenHandle } from 'react-full-screen';
|
import { FullScreen, useFullScreenHandle } from 'react-full-screen';
|
||||||
import { Layout } from 'react-grid-layout';
|
import { Layout } from 'react-grid-layout';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
import { UpdateTimeInterval } from 'store/actions';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { Dashboard, Widgets } from 'types/api/dashboard/getAll';
|
import { Dashboard, Widgets } from 'types/api/dashboard/getAll';
|
||||||
import AppReducer from 'types/reducer/app';
|
import AppReducer from 'types/reducer/app';
|
||||||
@ -45,6 +50,8 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
} = useDashboard();
|
} = useDashboard();
|
||||||
const { data } = selectedDashboard || {};
|
const { data } = selectedDashboard || {};
|
||||||
const handle = useFullScreenHandle();
|
const handle = useFullScreenHandle();
|
||||||
|
const { pathname } = useLocation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const { widgets, variables } = data || {};
|
const { widgets, variables } = data || {};
|
||||||
|
|
||||||
@ -61,6 +68,7 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
const updateDashboardMutation = useUpdateDashboard();
|
const updateDashboardMutation = useUpdateDashboard();
|
||||||
|
|
||||||
const { notifications } = useNotifications();
|
const { notifications } = useNotifications();
|
||||||
|
const urlQuery = useUrlQuery();
|
||||||
|
|
||||||
let permissions: ComponentTypes[] = ['save_layout', 'add_panel'];
|
let permissions: ComponentTypes[] = ['save_layout', 'add_panel'];
|
||||||
|
|
||||||
@ -126,6 +134,23 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onDragSelect = useCallback(
|
||||||
|
(start: number, end: number) => {
|
||||||
|
const startTimestamp = Math.trunc(start);
|
||||||
|
const endTimestamp = Math.trunc(end);
|
||||||
|
|
||||||
|
urlQuery.set(QueryParams.startTime, startTimestamp.toString());
|
||||||
|
urlQuery.set(QueryParams.endTime, endTimestamp.toString());
|
||||||
|
const generatedUrl = `${pathname}?${urlQuery.toString()}`;
|
||||||
|
history.replace(generatedUrl);
|
||||||
|
|
||||||
|
if (startTimestamp !== endTimestamp) {
|
||||||
|
dispatch(UpdateTimeInterval('custom', [startTimestamp, endTimestamp]));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[dispatch, pathname, urlQuery],
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
dashboardLayout &&
|
dashboardLayout &&
|
||||||
@ -200,11 +225,10 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
>
|
>
|
||||||
<GridCard
|
<GridCard
|
||||||
widget={currentWidget || ({ id, query: {} } as Widgets)}
|
widget={currentWidget || ({ id, query: {} } as Widgets)}
|
||||||
name={currentWidget?.id || ''}
|
|
||||||
headerMenuList={widgetActions}
|
headerMenuList={widgetActions}
|
||||||
variables={variables}
|
variables={variables}
|
||||||
fillSpans={currentWidget?.fillSpans}
|
|
||||||
version={selectedDashboard?.data?.version}
|
version={selectedDashboard?.data?.version}
|
||||||
|
onDragSelect={onDragSelect}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</CardContainer>
|
</CardContainer>
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import { ToggleGraphProps } from 'components/Graph/types';
|
import { ToggleGraphProps } from 'components/Graph/types';
|
||||||
import { DEFAULT_ENTITY_VERSION } from 'constants/app';
|
|
||||||
import { getComponentForPanelType } from 'constants/panelTypes';
|
import { getComponentForPanelType } from 'constants/panelTypes';
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import { GRID_TABLE_CONFIG } from 'container/GridTableComponent/config';
|
import { GRID_TABLE_CONFIG } from 'container/GridTableComponent/config';
|
||||||
import { FC, forwardRef, memo, useMemo } from 'react';
|
import { FC, forwardRef, memo, useMemo } from 'react';
|
||||||
import { DataSource } from 'types/common/queryBuilder';
|
|
||||||
|
|
||||||
import { GridPanelSwitchProps, PropsTypePropsMap } from './types';
|
import { GridPanelSwitchProps, PropsTypePropsMap } from './types';
|
||||||
|
|
||||||
@ -21,10 +19,7 @@ const GridPanelSwitch = forwardRef<
|
|||||||
query,
|
query,
|
||||||
options,
|
options,
|
||||||
thresholds,
|
thresholds,
|
||||||
selectedLogFields,
|
|
||||||
selectedTracesFields,
|
|
||||||
dataSource,
|
dataSource,
|
||||||
selectedTime,
|
|
||||||
},
|
},
|
||||||
ref,
|
ref,
|
||||||
): JSX.Element | null => {
|
): JSX.Element | null => {
|
||||||
@ -46,20 +41,7 @@ const GridPanelSwitch = forwardRef<
|
|||||||
query,
|
query,
|
||||||
thresholds,
|
thresholds,
|
||||||
},
|
},
|
||||||
[PANEL_TYPES.LIST]:
|
[PANEL_TYPES.LIST]: null,
|
||||||
dataSource === DataSource.LOGS
|
|
||||||
? {
|
|
||||||
selectedLogsFields: selectedLogFields || [],
|
|
||||||
query,
|
|
||||||
version: DEFAULT_ENTITY_VERSION, // As we don't support for Metrics, defaulting to v3
|
|
||||||
selectedTime,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
selectedTracesFields: selectedTracesFields || [],
|
|
||||||
query,
|
|
||||||
version: DEFAULT_ENTITY_VERSION, // As we don't support for Metrics, defaulting to v3
|
|
||||||
selectedTime,
|
|
||||||
},
|
|
||||||
[PANEL_TYPES.TRACE]: null,
|
[PANEL_TYPES.TRACE]: null,
|
||||||
[PANEL_TYPES.BAR]: {
|
[PANEL_TYPES.BAR]: {
|
||||||
data,
|
data,
|
||||||
@ -70,19 +52,7 @@ const GridPanelSwitch = forwardRef<
|
|||||||
};
|
};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}, [
|
}, [data, options, ref, yAxisUnit, thresholds, panelData, query]);
|
||||||
data,
|
|
||||||
options,
|
|
||||||
ref,
|
|
||||||
yAxisUnit,
|
|
||||||
thresholds,
|
|
||||||
panelData,
|
|
||||||
query,
|
|
||||||
dataSource,
|
|
||||||
selectedLogFields,
|
|
||||||
selectedTime,
|
|
||||||
selectedTracesFields,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const Component = getComponentForPanelType(panelType, dataSource) as FC<
|
const Component = getComponentForPanelType(panelType, dataSource) as FC<
|
||||||
PropsTypePropsMap[typeof panelType]
|
PropsTypePropsMap[typeof panelType]
|
||||||
|
@ -2,9 +2,7 @@ import { StaticLineProps, ToggleGraphProps } from 'components/Graph/types';
|
|||||||
import { UplotProps } from 'components/Uplot/Uplot';
|
import { UplotProps } from 'components/Uplot/Uplot';
|
||||||
import { GridTableComponentProps } from 'container/GridTableComponent/types';
|
import { GridTableComponentProps } from 'container/GridTableComponent/types';
|
||||||
import { GridValueComponentProps } from 'container/GridValueComponent/types';
|
import { GridValueComponentProps } from 'container/GridValueComponent/types';
|
||||||
import { LogsPanelComponentProps } from 'container/LogsPanelTable/LogsPanelComponent';
|
|
||||||
import { timePreferance } from 'container/NewWidget/RightContainer/timeItems';
|
import { timePreferance } from 'container/NewWidget/RightContainer/timeItems';
|
||||||
import { TracesTableComponentProps } from 'container/TracesTableComponent/TracesTableComponent';
|
|
||||||
import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin';
|
import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin';
|
||||||
import { ForwardedRef } from 'react';
|
import { ForwardedRef } from 'react';
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
@ -40,7 +38,7 @@ export type PropsTypePropsMap = {
|
|||||||
[PANEL_TYPES.VALUE]: GridValueComponentProps;
|
[PANEL_TYPES.VALUE]: GridValueComponentProps;
|
||||||
[PANEL_TYPES.TABLE]: GridTableComponentProps;
|
[PANEL_TYPES.TABLE]: GridTableComponentProps;
|
||||||
[PANEL_TYPES.TRACE]: null;
|
[PANEL_TYPES.TRACE]: null;
|
||||||
[PANEL_TYPES.LIST]: LogsPanelComponentProps | TracesTableComponentProps;
|
[PANEL_TYPES.LIST]: null;
|
||||||
[PANEL_TYPES.BAR]: UplotProps & {
|
[PANEL_TYPES.BAR]: UplotProps & {
|
||||||
ref: ForwardedRef<ToggleGraphProps | undefined>;
|
ref: ForwardedRef<ToggleGraphProps | undefined>;
|
||||||
};
|
};
|
||||||
|
@ -4,82 +4,53 @@ import { Table } from 'antd';
|
|||||||
import LogDetail from 'components/LogDetail';
|
import LogDetail from 'components/LogDetail';
|
||||||
import { VIEW_TYPES } from 'components/LogDetail/constants';
|
import { VIEW_TYPES } from 'components/LogDetail/constants';
|
||||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||||
import { DEFAULT_ENTITY_VERSION } from 'constants/app';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import { OPERATORS, PANEL_TYPES } from 'constants/queryBuilder';
|
|
||||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
|
||||||
import Controls from 'container/Controls';
|
import Controls from 'container/Controls';
|
||||||
import { timePreferance } from 'container/NewWidget/RightContainer/timeItems';
|
|
||||||
import { PER_PAGE_OPTIONS } from 'container/TracesExplorer/ListView/configs';
|
import { PER_PAGE_OPTIONS } from 'container/TracesExplorer/ListView/configs';
|
||||||
import { tableStyles } from 'container/TracesExplorer/ListView/styles';
|
import { tableStyles } from 'container/TracesExplorer/ListView/styles';
|
||||||
import { useActiveLog } from 'hooks/logs/useActiveLog';
|
import { useActiveLog } from 'hooks/logs/useActiveLog';
|
||||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
|
||||||
import { Pagination } from 'hooks/queryPagination';
|
import { Pagination } from 'hooks/queryPagination';
|
||||||
import { useLogsData } from 'hooks/useLogsData';
|
import { useLogsData } from 'hooks/useLogsData';
|
||||||
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
|
||||||
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||||
import { FlatLogData } from 'lib/logs/flatLogData';
|
import { FlatLogData } from 'lib/logs/flatLogData';
|
||||||
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
|
||||||
import {
|
import {
|
||||||
|
Dispatch,
|
||||||
HTMLAttributes,
|
HTMLAttributes,
|
||||||
|
SetStateAction,
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { UseQueryResult } from 'react-query';
|
||||||
import { AppState } from 'store/reducers';
|
import { SuccessResponse } from 'types/api';
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
import { ILog } from 'types/api/logs/log';
|
import { ILog } from 'types/api/logs/log';
|
||||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
|
||||||
import { v4 as uuid } from 'uuid';
|
|
||||||
|
|
||||||
import { getLogPanelColumnsList } from './utils';
|
import { getLogPanelColumnsList, getNextOrPreviousItems } from './utils';
|
||||||
|
|
||||||
function LogsPanelComponent({
|
function LogsPanelComponent({
|
||||||
selectedLogsFields,
|
widget,
|
||||||
query,
|
setRequestData,
|
||||||
selectedTime,
|
queryResponse,
|
||||||
}: LogsPanelComponentProps): JSX.Element {
|
}: LogsPanelComponentProps): JSX.Element {
|
||||||
const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector<
|
|
||||||
AppState,
|
|
||||||
GlobalReducer
|
|
||||||
>((state) => state.globalTime);
|
|
||||||
|
|
||||||
const [pagination, setPagination] = useState<Pagination>({
|
const [pagination, setPagination] = useState<Pagination>({
|
||||||
offset: 0,
|
offset: 0,
|
||||||
limit: query.builder.queryData[0].limit || 0,
|
limit: widget.query.builder.queryData[0].limit || 0,
|
||||||
});
|
|
||||||
|
|
||||||
const [requestData, setRequestData] = useState<GetQueryResultsProps>(() => {
|
|
||||||
const updatedQuery = { ...query };
|
|
||||||
updatedQuery.builder.queryData[0].pageSize = 10;
|
|
||||||
return {
|
|
||||||
query: updatedQuery,
|
|
||||||
graphType: PANEL_TYPES.LIST,
|
|
||||||
selectedTime: 'GLOBAL_TIME',
|
|
||||||
globalSelectedInterval: globalSelectedTime,
|
|
||||||
tableParams: {
|
|
||||||
pagination,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setRequestData({
|
setRequestData((prev) => ({
|
||||||
...requestData,
|
...prev,
|
||||||
globalSelectedInterval: globalSelectedTime,
|
|
||||||
tableParams: {
|
tableParams: {
|
||||||
pagination,
|
pagination,
|
||||||
},
|
},
|
||||||
});
|
}));
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
}, [pagination, setRequestData]);
|
||||||
}, [pagination]);
|
|
||||||
|
|
||||||
const [pageSize, setPageSize] = useState<number>(10);
|
const [pageSize, setPageSize] = useState<number>(10);
|
||||||
const { selectedDashboard } = useDashboard();
|
|
||||||
|
|
||||||
const handleChangePageSize = (value: number): void => {
|
const handleChangePageSize = (value: number): void => {
|
||||||
setPagination({
|
setPagination({
|
||||||
@ -88,53 +59,35 @@ function LogsPanelComponent({
|
|||||||
offset: value,
|
offset: value,
|
||||||
});
|
});
|
||||||
setPageSize(value);
|
setPageSize(value);
|
||||||
const newQueryData = { ...requestData.query };
|
setRequestData((prev) => {
|
||||||
newQueryData.builder.queryData[0].pageSize = value;
|
const newQueryData = { ...prev.query };
|
||||||
const newRequestData = {
|
newQueryData.builder.queryData[0].pageSize = value;
|
||||||
...requestData,
|
return {
|
||||||
query: newQueryData,
|
...prev,
|
||||||
tableParams: {
|
query: newQueryData,
|
||||||
pagination,
|
tableParams: {
|
||||||
},
|
pagination: {
|
||||||
};
|
limit: 0,
|
||||||
setRequestData(newRequestData);
|
offset: value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const { data, isFetching, isError } = useGetQueryRange(
|
const columns = getLogPanelColumnsList(widget.selectedLogFields);
|
||||||
{
|
|
||||||
...requestData,
|
|
||||||
globalSelectedInterval: globalSelectedTime,
|
|
||||||
selectedTime: selectedTime?.enum || 'GLOBAL_TIME',
|
|
||||||
variables: getDashboardVariables(selectedDashboard?.data.variables),
|
|
||||||
},
|
|
||||||
DEFAULT_ENTITY_VERSION,
|
|
||||||
{
|
|
||||||
queryKey: [
|
|
||||||
REACT_QUERY_KEY.GET_QUERY_RANGE,
|
|
||||||
globalSelectedTime,
|
|
||||||
maxTime,
|
|
||||||
minTime,
|
|
||||||
requestData,
|
|
||||||
pagination,
|
|
||||||
selectedDashboard?.data.variables,
|
|
||||||
],
|
|
||||||
enabled: !!requestData.query && !!selectedLogsFields?.length,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const columns = getLogPanelColumnsList(selectedLogsFields);
|
|
||||||
|
|
||||||
const dataLength =
|
const dataLength =
|
||||||
data?.payload?.data?.newResult?.data?.result[0]?.list?.length;
|
queryResponse.data?.payload?.data?.newResult?.data?.result[0]?.list?.length;
|
||||||
const totalCount = useMemo(() => dataLength || 0, [dataLength]);
|
const totalCount = useMemo(() => dataLength || 0, [dataLength]);
|
||||||
|
|
||||||
const [firstLog, setFirstLog] = useState<ILog>();
|
const [firstLog, setFirstLog] = useState<ILog>();
|
||||||
const [lastLog, setLastLog] = useState<ILog>();
|
const [lastLog, setLastLog] = useState<ILog>();
|
||||||
|
|
||||||
const { logs } = useLogsData({
|
const { logs } = useLogsData({
|
||||||
result: data?.payload.data.newResult.data.result,
|
result: queryResponse.data?.payload.data.newResult.data.result,
|
||||||
panelType: PANEL_TYPES.LIST,
|
panelType: PANEL_TYPES.LIST,
|
||||||
stagedQuery: query,
|
stagedQuery: widget.query,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -167,92 +120,86 @@ function LogsPanelComponent({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const isOrderByTimeStamp =
|
const isOrderByTimeStamp =
|
||||||
query.builder.queryData[0].orderBy.length > 0 &&
|
widget.query.builder.queryData[0].orderBy.length > 0 &&
|
||||||
query.builder.queryData[0].orderBy[0].columnName === 'timestamp';
|
widget.query.builder.queryData[0].orderBy[0].columnName === 'timestamp';
|
||||||
|
|
||||||
const handlePreviousPagination = (): void => {
|
const handlePreviousPagination = (): void => {
|
||||||
if (isOrderByTimeStamp) {
|
if (isOrderByTimeStamp) {
|
||||||
setRequestData({
|
setRequestData((prev) => ({
|
||||||
...requestData,
|
...prev,
|
||||||
query: {
|
query: {
|
||||||
...requestData.query,
|
...prev.query,
|
||||||
builder: {
|
builder: {
|
||||||
...requestData.query.builder,
|
...prev.query.builder,
|
||||||
queryData: [
|
queryData: [
|
||||||
{
|
{
|
||||||
...requestData.query.builder.queryData[0],
|
...prev.query.builder.queryData[0],
|
||||||
filters: {
|
filters: {
|
||||||
...requestData.query.builder.queryData[0].filters,
|
...prev.query.builder.queryData[0].filters,
|
||||||
items: [
|
items: [
|
||||||
{
|
...getNextOrPreviousItems(
|
||||||
id: uuid(),
|
prev.query.builder.queryData[0].filters.items,
|
||||||
key: {
|
'PREV',
|
||||||
key: 'id',
|
firstLog,
|
||||||
type: '',
|
),
|
||||||
dataType: DataTypes.String,
|
|
||||||
isColumn: true,
|
|
||||||
},
|
|
||||||
op: OPERATORS['>'],
|
|
||||||
value: firstLog?.id || '',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
limit: 0,
|
||||||
|
offset: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
}));
|
||||||
return;
|
}
|
||||||
|
if (!isOrderByTimeStamp) {
|
||||||
|
setPagination({
|
||||||
|
...pagination,
|
||||||
|
limit: 0,
|
||||||
|
offset: pagination.offset - pageSize,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
setPagination({
|
|
||||||
...pagination,
|
|
||||||
limit: 0,
|
|
||||||
offset: pagination.offset - pageSize,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleNextPagination = (): void => {
|
const handleNextPagination = (): void => {
|
||||||
if (isOrderByTimeStamp) {
|
if (isOrderByTimeStamp) {
|
||||||
setRequestData({
|
setRequestData((prev) => ({
|
||||||
...requestData,
|
...prev,
|
||||||
query: {
|
query: {
|
||||||
...requestData.query,
|
...prev.query,
|
||||||
builder: {
|
builder: {
|
||||||
...requestData.query.builder,
|
...prev.query.builder,
|
||||||
queryData: [
|
queryData: [
|
||||||
{
|
{
|
||||||
...requestData.query.builder.queryData[0],
|
...prev.query.builder.queryData[0],
|
||||||
filters: {
|
filters: {
|
||||||
...requestData.query.builder.queryData[0].filters,
|
...prev.query.builder.queryData[0].filters,
|
||||||
items: [
|
items: [
|
||||||
{
|
...getNextOrPreviousItems(
|
||||||
id: uuid(),
|
prev.query.builder.queryData[0].filters.items,
|
||||||
key: {
|
'NEXT',
|
||||||
key: 'id',
|
lastLog,
|
||||||
type: '',
|
),
|
||||||
dataType: DataTypes.String,
|
|
||||||
isColumn: true,
|
|
||||||
},
|
|
||||||
op: OPERATORS['<'],
|
|
||||||
value: lastLog?.id || '',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
limit: 0,
|
||||||
|
offset: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
}));
|
||||||
return;
|
}
|
||||||
|
if (!isOrderByTimeStamp) {
|
||||||
|
setPagination({
|
||||||
|
...pagination,
|
||||||
|
limit: 0,
|
||||||
|
offset: pagination.offset + pageSize,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
setPagination({
|
|
||||||
...pagination,
|
|
||||||
limit: 0,
|
|
||||||
offset: pagination.offset + pageSize,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isError) {
|
if (queryResponse.isError) {
|
||||||
return <div>{SOMETHING_WENT_WRONG}</div>;
|
return <div>{SOMETHING_WENT_WRONG}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,19 +212,19 @@ function LogsPanelComponent({
|
|||||||
tableLayout="fixed"
|
tableLayout="fixed"
|
||||||
scroll={{ x: `calc(50vw - 10px)` }}
|
scroll={{ x: `calc(50vw - 10px)` }}
|
||||||
sticky
|
sticky
|
||||||
loading={isFetching}
|
loading={queryResponse.isFetching}
|
||||||
style={tableStyles}
|
style={tableStyles}
|
||||||
dataSource={flattenLogData}
|
dataSource={flattenLogData}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
onRow={handleRow}
|
onRow={handleRow}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{!query.builder.queryData[0].limit && (
|
{!widget.query.builder.queryData[0].limit && (
|
||||||
<div className="controller">
|
<div className="controller">
|
||||||
<Controls
|
<Controls
|
||||||
totalCount={totalCount}
|
totalCount={totalCount}
|
||||||
perPageOptions={PER_PAGE_OPTIONS}
|
perPageOptions={PER_PAGE_OPTIONS}
|
||||||
isLoading={isFetching}
|
isLoading={queryResponse.isFetching}
|
||||||
offset={pagination.offset}
|
offset={pagination.offset}
|
||||||
countPerPage={pageSize}
|
countPerPage={pageSize}
|
||||||
handleNavigatePrevious={handlePreviousPagination}
|
handleNavigatePrevious={handlePreviousPagination}
|
||||||
@ -301,13 +248,12 @@ function LogsPanelComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type LogsPanelComponentProps = {
|
export type LogsPanelComponentProps = {
|
||||||
selectedLogsFields: Widgets['selectedLogFields'];
|
setRequestData: Dispatch<SetStateAction<GetQueryResultsProps>>;
|
||||||
query: Query;
|
queryResponse: UseQueryResult<
|
||||||
selectedTime?: timePreferance;
|
SuccessResponse<MetricRangePayloadProps, unknown>,
|
||||||
};
|
Error
|
||||||
|
>;
|
||||||
LogsPanelComponent.defaultProps = {
|
widget: Widgets;
|
||||||
selectedTime: undefined,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LogsPanelComponent;
|
export default LogsPanelComponent;
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
import { ColumnsType } from 'antd/es/table';
|
import { ColumnsType } from 'antd/es/table';
|
||||||
import { Typography } from 'antd/lib';
|
import { Typography } from 'antd/lib';
|
||||||
|
import { OPERATORS } from 'constants/queryBuilder';
|
||||||
// import Typography from 'antd/es/typography/Typography';
|
// import Typography from 'antd/es/typography/Typography';
|
||||||
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
import { IField } from 'types/api/logs/fields';
|
import { IField } from 'types/api/logs/fields';
|
||||||
|
import { ILog } from 'types/api/logs/log';
|
||||||
|
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||||
|
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
export const getLogPanelColumnsList = (
|
export const getLogPanelColumnsList = (
|
||||||
selectedLogFields: Widgets['selectedLogFields'],
|
selectedLogFields: Widgets['selectedLogFields'],
|
||||||
@ -36,3 +41,49 @@ export const getLogPanelColumnsList = (
|
|||||||
|
|
||||||
return [...initialColumns, ...columns];
|
return [...initialColumns, ...columns];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getNextOrPreviousItems = (
|
||||||
|
items: TagFilterItem[],
|
||||||
|
direction: 'NEXT' | 'PREV',
|
||||||
|
log?: ILog,
|
||||||
|
): TagFilterItem[] => {
|
||||||
|
const nextItem = {
|
||||||
|
id: uuid(),
|
||||||
|
key: {
|
||||||
|
key: 'id',
|
||||||
|
type: '',
|
||||||
|
dataType: DataTypes.String,
|
||||||
|
isColumn: true,
|
||||||
|
},
|
||||||
|
op: OPERATORS['<'],
|
||||||
|
value: log?.id || '',
|
||||||
|
};
|
||||||
|
const prevItem = {
|
||||||
|
id: uuid(),
|
||||||
|
key: {
|
||||||
|
key: 'id',
|
||||||
|
type: '',
|
||||||
|
dataType: DataTypes.String,
|
||||||
|
isColumn: true,
|
||||||
|
},
|
||||||
|
op: OPERATORS['>'],
|
||||||
|
value: log?.id || '',
|
||||||
|
};
|
||||||
|
let index = items.findIndex((item) => item.op === OPERATORS['<']);
|
||||||
|
if (index === -1) {
|
||||||
|
index = items.findIndex((item) => item.op === OPERATORS['>']);
|
||||||
|
}
|
||||||
|
if (index === -1) {
|
||||||
|
if (direction === 'NEXT') {
|
||||||
|
return [...items, nextItem];
|
||||||
|
}
|
||||||
|
return [...items, prevItem];
|
||||||
|
}
|
||||||
|
const newItems = [...items];
|
||||||
|
if (direction === 'NEXT') {
|
||||||
|
newItems[index] = nextItem;
|
||||||
|
} else {
|
||||||
|
newItems[index] = prevItem;
|
||||||
|
}
|
||||||
|
return newItems;
|
||||||
|
};
|
||||||
|
@ -8,6 +8,7 @@ export const getWidgetQueryBuilder = ({
|
|||||||
title = '',
|
title = '',
|
||||||
panelTypes,
|
panelTypes,
|
||||||
yAxisUnit = '',
|
yAxisUnit = '',
|
||||||
|
fillSpans = false,
|
||||||
id,
|
id,
|
||||||
}: GetWidgetQueryBuilderProps): Widgets => ({
|
}: GetWidgetQueryBuilderProps): Widgets => ({
|
||||||
description: '',
|
description: '',
|
||||||
@ -24,4 +25,5 @@ export const getWidgetQueryBuilder = ({
|
|||||||
softMin: null,
|
softMin: null,
|
||||||
selectedLogFields: [],
|
selectedLogFields: [],
|
||||||
selectedTracesFields: [],
|
selectedTracesFields: [],
|
||||||
|
fillSpans,
|
||||||
});
|
});
|
||||||
|
@ -70,6 +70,7 @@ function DBCall(): JSX.Element {
|
|||||||
panelTypes: PANEL_TYPES.TIME_SERIES,
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
yAxisUnit: 'reqps',
|
yAxisUnit: 'reqps',
|
||||||
id: SERVICE_CHART_ID.dbCallsRPS,
|
id: SERVICE_CHART_ID.dbCallsRPS,
|
||||||
|
fillSpans: false,
|
||||||
}),
|
}),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
@ -89,7 +90,8 @@ function DBCall(): JSX.Element {
|
|||||||
title: GraphTitle.DATABASE_CALLS_AVG_DURATION,
|
title: GraphTitle.DATABASE_CALLS_AVG_DURATION,
|
||||||
panelTypes: PANEL_TYPES.TIME_SERIES,
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
yAxisUnit: 'ms',
|
yAxisUnit: 'ms',
|
||||||
id: SERVICE_CHART_ID.dbCallsAvgDuration,
|
id: GraphTitle.DATABASE_CALLS_AVG_DURATION,
|
||||||
|
fillSpans: true,
|
||||||
}),
|
}),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
@ -112,8 +114,6 @@ function DBCall(): JSX.Element {
|
|||||||
<Card data-testid="database_call_rps">
|
<Card data-testid="database_call_rps">
|
||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<Graph
|
<Graph
|
||||||
fillSpans={false}
|
|
||||||
name="database_call_rps"
|
|
||||||
widget={databaseCallsRPSWidget}
|
widget={databaseCallsRPSWidget}
|
||||||
onClickHandler={(xValue, yValue, mouseX, mouseY): void => {
|
onClickHandler={(xValue, yValue, mouseX, mouseY): void => {
|
||||||
onGraphClickHandler(setSelectedTimeStamp)(
|
onGraphClickHandler(setSelectedTimeStamp)(
|
||||||
@ -147,8 +147,6 @@ function DBCall(): JSX.Element {
|
|||||||
<Card data-testid="database_call_avg_duration">
|
<Card data-testid="database_call_avg_duration">
|
||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<Graph
|
<Graph
|
||||||
fillSpans
|
|
||||||
name="database_call_avg_duration"
|
|
||||||
widget={databaseCallsAverageDurationWidget}
|
widget={databaseCallsAverageDurationWidget}
|
||||||
headerMenuList={MENU_ITEMS}
|
headerMenuList={MENU_ITEMS}
|
||||||
onClickHandler={(xValue, yValue, mouseX, mouseY): void => {
|
onClickHandler={(xValue, yValue, mouseX, mouseY): void => {
|
||||||
|
@ -18,7 +18,7 @@ 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, MENU_ITEMS, SERVICE_CHART_ID } from '../constant';
|
import { GraphTitle, legend, MENU_ITEMS } from '../constant';
|
||||||
import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
|
import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
|
||||||
import { Card, GraphContainer, Row } from '../styles';
|
import { Card, GraphContainer, Row } from '../styles';
|
||||||
import { Button } from './styles';
|
import { Button } from './styles';
|
||||||
@ -60,7 +60,7 @@ function External(): JSX.Element {
|
|||||||
title: GraphTitle.EXTERNAL_CALL_ERROR_PERCENTAGE,
|
title: GraphTitle.EXTERNAL_CALL_ERROR_PERCENTAGE,
|
||||||
panelTypes: PANEL_TYPES.TIME_SERIES,
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
yAxisUnit: '%',
|
yAxisUnit: '%',
|
||||||
id: SERVICE_CHART_ID.externalCallErrorPercentage,
|
id: GraphTitle.EXTERNAL_CALL_ERROR_PERCENTAGE,
|
||||||
}),
|
}),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
@ -86,7 +86,8 @@ function External(): JSX.Element {
|
|||||||
title: GraphTitle.EXTERNAL_CALL_DURATION,
|
title: GraphTitle.EXTERNAL_CALL_DURATION,
|
||||||
panelTypes: PANEL_TYPES.TIME_SERIES,
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
yAxisUnit: 'ms',
|
yAxisUnit: 'ms',
|
||||||
id: SERVICE_CHART_ID.externalCallDuration,
|
id: GraphTitle.EXTERNAL_CALL_DURATION,
|
||||||
|
fillSpans: true,
|
||||||
}),
|
}),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
@ -108,7 +109,8 @@ function External(): JSX.Element {
|
|||||||
title: GraphTitle.EXTERNAL_CALL_RPS_BY_ADDRESS,
|
title: GraphTitle.EXTERNAL_CALL_RPS_BY_ADDRESS,
|
||||||
panelTypes: PANEL_TYPES.TIME_SERIES,
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
yAxisUnit: 'reqps',
|
yAxisUnit: 'reqps',
|
||||||
id: SERVICE_CHART_ID.externalCallRPSByAddress,
|
id: GraphTitle.EXTERNAL_CALL_RPS_BY_ADDRESS,
|
||||||
|
fillSpans: true,
|
||||||
}),
|
}),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
@ -130,7 +132,8 @@ function External(): JSX.Element {
|
|||||||
title: GraphTitle.EXTERNAL_CALL_DURATION_BY_ADDRESS,
|
title: GraphTitle.EXTERNAL_CALL_DURATION_BY_ADDRESS,
|
||||||
panelTypes: PANEL_TYPES.TIME_SERIES,
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
yAxisUnit: 'ms',
|
yAxisUnit: 'ms',
|
||||||
id: SERVICE_CHART_ID.externalCallDurationByAddress,
|
id: GraphTitle.EXTERNAL_CALL_DURATION_BY_ADDRESS,
|
||||||
|
fillSpans: true,
|
||||||
}),
|
}),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
@ -155,9 +158,7 @@ function External(): JSX.Element {
|
|||||||
<Card data-testid="external_call_error_percentage">
|
<Card data-testid="external_call_error_percentage">
|
||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<Graph
|
<Graph
|
||||||
fillSpans={false}
|
|
||||||
headerMenuList={MENU_ITEMS}
|
headerMenuList={MENU_ITEMS}
|
||||||
name="external_call_error_percentage"
|
|
||||||
widget={externalCallErrorWidget}
|
widget={externalCallErrorWidget}
|
||||||
onClickHandler={(xValue, yValue, mouseX, mouseY): void => {
|
onClickHandler={(xValue, yValue, mouseX, mouseY): void => {
|
||||||
onGraphClickHandler(setSelectedTimeStamp)(
|
onGraphClickHandler(setSelectedTimeStamp)(
|
||||||
@ -192,8 +193,6 @@ function External(): JSX.Element {
|
|||||||
<Card data-testid="external_call_duration">
|
<Card data-testid="external_call_duration">
|
||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<Graph
|
<Graph
|
||||||
fillSpans
|
|
||||||
name="external_call_duration"
|
|
||||||
headerMenuList={MENU_ITEMS}
|
headerMenuList={MENU_ITEMS}
|
||||||
widget={externalCallDurationWidget}
|
widget={externalCallDurationWidget}
|
||||||
onClickHandler={(xValue, yValue, mouseX, mouseY): void => {
|
onClickHandler={(xValue, yValue, mouseX, mouseY): void => {
|
||||||
@ -230,8 +229,6 @@ function External(): JSX.Element {
|
|||||||
<Card data-testid="external_call_rps_by_address">
|
<Card data-testid="external_call_rps_by_address">
|
||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<Graph
|
<Graph
|
||||||
fillSpans
|
|
||||||
name="external_call_rps_by_address"
|
|
||||||
widget={externalCallRPSWidget}
|
widget={externalCallRPSWidget}
|
||||||
headerMenuList={MENU_ITEMS}
|
headerMenuList={MENU_ITEMS}
|
||||||
onClickHandler={(xValue, yValue, mouseX, mouseY): Promise<void> =>
|
onClickHandler={(xValue, yValue, mouseX, mouseY): Promise<void> =>
|
||||||
@ -267,10 +264,8 @@ function External(): JSX.Element {
|
|||||||
<Card data-testid="external_call_duration_by_address">
|
<Card data-testid="external_call_duration_by_address">
|
||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<Graph
|
<Graph
|
||||||
name="external_call_duration_by_address"
|
|
||||||
widget={externalCallDurationAddressWidget}
|
widget={externalCallDurationAddressWidget}
|
||||||
headerMenuList={MENU_ITEMS}
|
headerMenuList={MENU_ITEMS}
|
||||||
fillSpans
|
|
||||||
onClickHandler={(xValue, yValue, mouseX, mouseY): void => {
|
onClickHandler={(xValue, yValue, mouseX, mouseY): void => {
|
||||||
onGraphClickHandler(setSelectedTimeStamp)(
|
onGraphClickHandler(setSelectedTimeStamp)(
|
||||||
xValue,
|
xValue,
|
||||||
|
@ -19,13 +19,10 @@ import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin';
|
|||||||
import { defaultTo } from 'lodash-es';
|
import { defaultTo } from 'lodash-es';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch } 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 { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
|
||||||
import { Tags } from 'types/reducer/trace';
|
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
import { GraphTitle, SERVICE_CHART_ID } from '../constant';
|
import { GraphTitle, SERVICE_CHART_ID } from '../constant';
|
||||||
@ -49,9 +46,6 @@ import {
|
|||||||
} from './util';
|
} from './util';
|
||||||
|
|
||||||
function Application(): JSX.Element {
|
function Application(): JSX.Element {
|
||||||
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
|
||||||
(state) => state.globalTime,
|
|
||||||
);
|
|
||||||
const { servicename: encodedServiceName } = useParams<IServiceName>();
|
const { servicename: encodedServiceName } = useParams<IServiceName>();
|
||||||
const servicename = decodeURIComponent(encodedServiceName);
|
const servicename = decodeURIComponent(encodedServiceName);
|
||||||
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
||||||
@ -59,10 +53,6 @@ function Application(): JSX.Element {
|
|||||||
const { queries } = useResourceAttribute();
|
const { queries } = useResourceAttribute();
|
||||||
const urlQuery = useUrlQuery();
|
const urlQuery = useUrlQuery();
|
||||||
|
|
||||||
const selectedTags = useMemo(
|
|
||||||
() => (convertRawQueriesToTraceSelectedTags(queries) as Tags[]) || [],
|
|
||||||
[queries],
|
|
||||||
);
|
|
||||||
const isSpanMetricEnabled = useFeatureFlag(FeatureKeys.USE_SPAN_METRICS)
|
const isSpanMetricEnabled = useFeatureFlag(FeatureKeys.USE_SPAN_METRICS)
|
||||||
?.active;
|
?.active;
|
||||||
|
|
||||||
@ -94,7 +84,7 @@ function Application(): JSX.Element {
|
|||||||
isLoading: topLevelOperationsIsLoading,
|
isLoading: topLevelOperationsIsLoading,
|
||||||
isError: topLevelOperationsIsError,
|
isError: topLevelOperationsIsError,
|
||||||
} = useQuery<ServiceDataProps>({
|
} = useQuery<ServiceDataProps>({
|
||||||
queryKey: [servicename, minTime, maxTime, selectedTags],
|
queryKey: [servicename],
|
||||||
queryFn: getTopLevelOperations,
|
queryFn: getTopLevelOperations,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -116,49 +106,41 @@ function Application(): JSX.Element {
|
|||||||
[servicename, topLevelOperations],
|
[servicename, topLevelOperations],
|
||||||
);
|
);
|
||||||
|
|
||||||
const operationPerSecWidget = useMemo(
|
const operationPerSecWidget = getWidgetQueryBuilder({
|
||||||
() =>
|
query: {
|
||||||
getWidgetQueryBuilder({
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
query: {
|
promql: [],
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
builder: operationPerSec({
|
||||||
promql: [],
|
servicename,
|
||||||
builder: operationPerSec({
|
tagFilterItems,
|
||||||
servicename,
|
topLevelOperations: topLevelOperationsRoute,
|
||||||
tagFilterItems,
|
|
||||||
topLevelOperations: topLevelOperationsRoute,
|
|
||||||
}),
|
|
||||||
clickhouse_sql: [],
|
|
||||||
id: uuid(),
|
|
||||||
},
|
|
||||||
title: GraphTitle.RATE_PER_OPS,
|
|
||||||
panelTypes: PANEL_TYPES.TIME_SERIES,
|
|
||||||
yAxisUnit: 'ops',
|
|
||||||
id: SERVICE_CHART_ID.rps,
|
|
||||||
}),
|
}),
|
||||||
[servicename, tagFilterItems, topLevelOperationsRoute],
|
clickhouse_sql: [],
|
||||||
);
|
id: uuid(),
|
||||||
|
},
|
||||||
|
title: GraphTitle.RATE_PER_OPS,
|
||||||
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
|
yAxisUnit: 'ops',
|
||||||
|
id: SERVICE_CHART_ID.rps,
|
||||||
|
});
|
||||||
|
|
||||||
const errorPercentageWidget = useMemo(
|
const errorPercentageWidget = getWidgetQueryBuilder({
|
||||||
() =>
|
query: {
|
||||||
getWidgetQueryBuilder({
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
query: {
|
promql: [],
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
builder: errorPercentage({
|
||||||
promql: [],
|
servicename,
|
||||||
builder: errorPercentage({
|
tagFilterItems,
|
||||||
servicename,
|
topLevelOperations: topLevelOperationsRoute,
|
||||||
tagFilterItems,
|
|
||||||
topLevelOperations: topLevelOperationsRoute,
|
|
||||||
}),
|
|
||||||
clickhouse_sql: [],
|
|
||||||
id: uuid(),
|
|
||||||
},
|
|
||||||
title: GraphTitle.ERROR_PERCENTAGE,
|
|
||||||
panelTypes: PANEL_TYPES.TIME_SERIES,
|
|
||||||
yAxisUnit: '%',
|
|
||||||
id: SERVICE_CHART_ID.errorPercentage,
|
|
||||||
}),
|
}),
|
||||||
[servicename, tagFilterItems, topLevelOperationsRoute],
|
clickhouse_sql: [],
|
||||||
);
|
id: uuid(),
|
||||||
|
},
|
||||||
|
title: GraphTitle.ERROR_PERCENTAGE,
|
||||||
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
|
yAxisUnit: '%',
|
||||||
|
id: SERVICE_CHART_ID.errorPercentage,
|
||||||
|
});
|
||||||
|
|
||||||
const onDragSelect = useCallback(
|
const onDragSelect = useCallback(
|
||||||
(start: number, end: number) => {
|
(start: number, end: number) => {
|
||||||
|
@ -89,8 +89,6 @@ function ApDexMetrics({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Graph
|
<Graph
|
||||||
name="apdex"
|
|
||||||
fillSpans={false}
|
|
||||||
widget={apDexMetricsWidget}
|
widget={apDexMetricsWidget}
|
||||||
onDragSelect={onDragSelect}
|
onDragSelect={onDragSelect}
|
||||||
onClickHandler={handleGraphClick('ApDex')}
|
onClickHandler={handleGraphClick('ApDex')}
|
||||||
|
@ -50,7 +50,6 @@ function ApDexTraces({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Graph
|
<Graph
|
||||||
name="apdex"
|
|
||||||
widget={apDexTracesWidget}
|
widget={apDexTracesWidget}
|
||||||
onDragSelect={onDragSelect}
|
onDragSelect={onDragSelect}
|
||||||
onClickHandler={handleGraphClick('ApDex')}
|
onClickHandler={handleGraphClick('ApDex')}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Skeleton } from 'antd';
|
||||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||||
import { FeatureKeys } from 'constants/features';
|
import { FeatureKeys } from 'constants/features';
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
@ -46,28 +47,24 @@ function ServiceOverview({
|
|||||||
[isSpanMetricEnable, queries],
|
[isSpanMetricEnable, queries],
|
||||||
);
|
);
|
||||||
|
|
||||||
const latencyWidget = useMemo(
|
const latencyWidget = getWidgetQueryBuilder({
|
||||||
() =>
|
query: {
|
||||||
getWidgetQueryBuilder({
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
query: {
|
promql: [],
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
builder: latency({
|
||||||
promql: [],
|
servicename,
|
||||||
builder: latency({
|
tagFilterItems,
|
||||||
servicename,
|
isSpanMetricEnable,
|
||||||
tagFilterItems,
|
topLevelOperationsRoute,
|
||||||
isSpanMetricEnable,
|
|
||||||
topLevelOperationsRoute,
|
|
||||||
}),
|
|
||||||
clickhouse_sql: [],
|
|
||||||
id: uuid(),
|
|
||||||
},
|
|
||||||
title: GraphTitle.LATENCY,
|
|
||||||
panelTypes: PANEL_TYPES.TIME_SERIES,
|
|
||||||
yAxisUnit: 'ns',
|
|
||||||
id: SERVICE_CHART_ID.latency,
|
|
||||||
}),
|
}),
|
||||||
[servicename, isSpanMetricEnable, topLevelOperationsRoute, tagFilterItems],
|
clickhouse_sql: [],
|
||||||
);
|
id: uuid(),
|
||||||
|
},
|
||||||
|
title: GraphTitle.LATENCY,
|
||||||
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
|
yAxisUnit: 'ns',
|
||||||
|
id: SERVICE_CHART_ID.latency,
|
||||||
|
});
|
||||||
|
|
||||||
const isQueryEnabled =
|
const isQueryEnabled =
|
||||||
!topLevelOperationsIsLoading && topLevelOperationsRoute.length > 0;
|
!topLevelOperationsIsLoading && topLevelOperationsRoute.length > 0;
|
||||||
@ -88,15 +85,23 @@ function ServiceOverview({
|
|||||||
</Button>
|
</Button>
|
||||||
<Card data-testid="service_latency">
|
<Card data-testid="service_latency">
|
||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<Graph
|
{topLevelOperationsIsLoading && (
|
||||||
name="service_latency"
|
<Skeleton
|
||||||
onDragSelect={onDragSelect}
|
style={{
|
||||||
widget={latencyWidget}
|
height: '100%',
|
||||||
onClickHandler={handleGraphClick('Service')}
|
padding: '16px',
|
||||||
isQueryEnabled={isQueryEnabled}
|
}}
|
||||||
fillSpans={false}
|
/>
|
||||||
version={ENTITY_VERSION_V4}
|
)}
|
||||||
/>
|
{!topLevelOperationsIsLoading && (
|
||||||
|
<Graph
|
||||||
|
onDragSelect={onDragSelect}
|
||||||
|
widget={latencyWidget}
|
||||||
|
onClickHandler={handleGraphClick('Service')}
|
||||||
|
isQueryEnabled={isQueryEnabled}
|
||||||
|
version={ENTITY_VERSION_V4}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</GraphContainer>
|
</GraphContainer>
|
||||||
</Card>
|
</Card>
|
||||||
</>
|
</>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Typography } from 'antd';
|
import { Skeleton, Typography } from 'antd';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||||
@ -27,15 +27,23 @@ function TopLevelOperation({
|
|||||||
</Typography>
|
</Typography>
|
||||||
) : (
|
) : (
|
||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<Graph
|
{topLevelOperationsIsLoading && (
|
||||||
fillSpans={false}
|
<Skeleton
|
||||||
name={name}
|
style={{
|
||||||
widget={widget}
|
height: '100%',
|
||||||
onClickHandler={handleGraphClick(opName)}
|
padding: '16px',
|
||||||
onDragSelect={onDragSelect}
|
}}
|
||||||
isQueryEnabled={!topLevelOperationsIsLoading}
|
/>
|
||||||
version={ENTITY_VERSION_V4}
|
)}
|
||||||
/>
|
{!topLevelOperationsIsLoading && (
|
||||||
|
<Graph
|
||||||
|
widget={widget}
|
||||||
|
onClickHandler={handleGraphClick(opName)}
|
||||||
|
onDragSelect={onDragSelect}
|
||||||
|
isQueryEnabled={!topLevelOperationsIsLoading}
|
||||||
|
version={ENTITY_VERSION_V4}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</GraphContainer>
|
</GraphContainer>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -13,7 +13,7 @@ export const Card = styled(CardComponent)`
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ant-card-body {
|
.ant-card-body {
|
||||||
height: calc(100% - 40px);
|
height: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -40,7 +40,7 @@ export const ColErrorContainer = styled(ColComponent)`
|
|||||||
|
|
||||||
export const GraphContainer = styled.div`
|
export const GraphContainer = styled.div`
|
||||||
min-height: calc(40vh - 40px);
|
min-height: calc(40vh - 40px);
|
||||||
height: calc(100% - 40px);
|
height: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const GraphTitle = styled(Typography)`
|
export const GraphTitle = styled(Typography)`
|
||||||
|
@ -10,6 +10,7 @@ export interface GetWidgetQueryBuilderProps {
|
|||||||
panelTypes: Widgets['panelTypes'];
|
panelTypes: Widgets['panelTypes'];
|
||||||
yAxisUnit?: Widgets['yAxisUnit'];
|
yAxisUnit?: Widgets['yAxisUnit'];
|
||||||
id?: Widgets['id'];
|
id?: Widgets['id'];
|
||||||
|
fillSpans?: Widgets['fillSpans'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NavigateToTraceProps {
|
export interface NavigateToTraceProps {
|
||||||
|
@ -2,14 +2,11 @@ import './QuerySection.styles.scss';
|
|||||||
|
|
||||||
import { Button, Tabs, Tooltip, Typography } from 'antd';
|
import { Button, Tabs, Tooltip, Typography } from 'antd';
|
||||||
import TextToolTip from 'components/TextToolTip';
|
import TextToolTip from 'components/TextToolTip';
|
||||||
import { DEFAULT_ENTITY_VERSION } from 'constants/app';
|
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import { QBShortcuts } from 'constants/shortcuts/QBShortcuts';
|
import { QBShortcuts } from 'constants/shortcuts/QBShortcuts';
|
||||||
import { WidgetGraphProps } from 'container/NewWidget/types';
|
|
||||||
import { QueryBuilder } from 'container/QueryBuilder';
|
import { QueryBuilder } from 'container/QueryBuilder';
|
||||||
import { QueryBuilderProps } from 'container/QueryBuilder/QueryBuilder.interfaces';
|
import { QueryBuilderProps } from 'container/QueryBuilder/QueryBuilder.interfaces';
|
||||||
import { useKeyboardHotkeys } from 'hooks/hotkeys/useKeyboardHotkeys';
|
import { useKeyboardHotkeys } from 'hooks/hotkeys/useKeyboardHotkeys';
|
||||||
import { useGetWidgetQueryRange } from 'hooks/queryBuilder/useGetWidgetQueryRange';
|
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||||
import { updateStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
import { updateStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
||||||
@ -22,9 +19,12 @@ import {
|
|||||||
getSelectedWidgetIndex,
|
getSelectedWidgetIndex,
|
||||||
} from 'providers/Dashboard/util';
|
} from 'providers/Dashboard/util';
|
||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useCallback, useEffect, useMemo } from 'react';
|
||||||
|
import { UseQueryResult } from 'react-query';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
|
import { SuccessResponse } from 'types/api';
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
import AppReducer from 'types/reducer/app';
|
import AppReducer from 'types/reducer/app';
|
||||||
@ -35,7 +35,7 @@ import PromQLQueryContainer from './QueryBuilder/promQL';
|
|||||||
|
|
||||||
function QuerySection({
|
function QuerySection({
|
||||||
selectedGraph,
|
selectedGraph,
|
||||||
selectedTime,
|
queryResponse,
|
||||||
}: QueryProps): JSX.Element {
|
}: QueryProps): JSX.Element {
|
||||||
const { currentQuery, redirectWithQueryBuilderData } = useQueryBuilder();
|
const { currentQuery, redirectWithQueryBuilderData } = useQueryBuilder();
|
||||||
const urlQuery = useUrlQuery();
|
const urlQuery = useUrlQuery();
|
||||||
@ -51,14 +51,6 @@ function QuerySection({
|
|||||||
|
|
||||||
const { selectedDashboard, setSelectedDashboard } = useDashboard();
|
const { selectedDashboard, setSelectedDashboard } = useDashboard();
|
||||||
|
|
||||||
const getWidgetQueryRange = useGetWidgetQueryRange(
|
|
||||||
{
|
|
||||||
graphType: selectedGraph,
|
|
||||||
selectedTime: selectedTime.enum,
|
|
||||||
},
|
|
||||||
selectedDashboard?.data?.version || DEFAULT_ENTITY_VERSION,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { widgets } = selectedDashboard?.data || {};
|
const { widgets } = selectedDashboard?.data || {};
|
||||||
|
|
||||||
const getWidget = useCallback(() => {
|
const getWidget = useCallback(() => {
|
||||||
@ -233,7 +225,7 @@ function QuerySection({
|
|||||||
<span style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
|
<span style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
|
||||||
<TextToolTip text="This will temporarily save the current query and graph state. This will persist across tab change" />
|
<TextToolTip text="This will temporarily save the current query and graph state. This will persist across tab change" />
|
||||||
<Button
|
<Button
|
||||||
loading={getWidgetQueryRange.isFetching}
|
loading={queryResponse.isFetching}
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={handleRunQuery}
|
onClick={handleRunQuery}
|
||||||
className="stage-run-query"
|
className="stage-run-query"
|
||||||
@ -251,7 +243,10 @@ function QuerySection({
|
|||||||
|
|
||||||
interface QueryProps {
|
interface QueryProps {
|
||||||
selectedGraph: PANEL_TYPES;
|
selectedGraph: PANEL_TYPES;
|
||||||
selectedTime: WidgetGraphProps['selectedTime'];
|
queryResponse: UseQueryResult<
|
||||||
|
SuccessResponse<MetricRangePayloadProps, unknown>,
|
||||||
|
Error
|
||||||
|
>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default QuerySection;
|
export default QuerySection;
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
import { Card, Typography } from 'antd';
|
import { Card, Typography } from 'antd';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import { DEFAULT_ENTITY_VERSION } from 'constants/app';
|
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import { WidgetGraphProps } from 'container/NewWidget/types';
|
import { WidgetGraphContainerProps } from 'container/NewWidget/types';
|
||||||
import { useGetWidgetQueryRange } from 'hooks/queryBuilder/useGetWidgetQueryRange';
|
// import useUrlQuery from 'hooks/useUrlQuery';
|
||||||
import useUrlQuery from 'hooks/useUrlQuery';
|
// import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
|
||||||
import { getGraphType } from 'utils/getGraphType';
|
|
||||||
import { getSortedSeriesData } from 'utils/getSortedSeriesData';
|
import { getSortedSeriesData } from 'utils/getSortedSeriesData';
|
||||||
|
|
||||||
import { NotFoundContainer } from './styles';
|
import { NotFoundContainer } from './styles';
|
||||||
@ -14,58 +11,36 @@ import WidgetGraph from './WidgetGraphs';
|
|||||||
|
|
||||||
function WidgetGraphContainer({
|
function WidgetGraphContainer({
|
||||||
selectedGraph,
|
selectedGraph,
|
||||||
yAxisUnit,
|
queryResponse,
|
||||||
selectedTime,
|
setRequestData,
|
||||||
thresholds,
|
selectedWidget,
|
||||||
fillSpans = false,
|
}: WidgetGraphContainerProps): JSX.Element {
|
||||||
softMax,
|
if (queryResponse.data && selectedGraph === PANEL_TYPES.BAR) {
|
||||||
softMin,
|
|
||||||
selectedLogFields,
|
|
||||||
selectedTracesFields,
|
|
||||||
}: WidgetGraphProps): JSX.Element {
|
|
||||||
const { selectedDashboard } = useDashboard();
|
|
||||||
|
|
||||||
const { widgets = [] } = selectedDashboard?.data || {};
|
|
||||||
|
|
||||||
const params = useUrlQuery();
|
|
||||||
|
|
||||||
const widgetId = params.get('widgetId');
|
|
||||||
|
|
||||||
const selectedWidget = widgets.find((e) => e.id === widgetId);
|
|
||||||
|
|
||||||
const getWidgetQueryRange = useGetWidgetQueryRange(
|
|
||||||
{
|
|
||||||
graphType: getGraphType(selectedGraph),
|
|
||||||
selectedTime: selectedTime.enum,
|
|
||||||
},
|
|
||||||
selectedDashboard?.data?.version || DEFAULT_ENTITY_VERSION,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (getWidgetQueryRange.data && selectedGraph === PANEL_TYPES.BAR) {
|
|
||||||
const sortedSeriesData = getSortedSeriesData(
|
const sortedSeriesData = getSortedSeriesData(
|
||||||
getWidgetQueryRange.data?.payload.data.result,
|
queryResponse.data?.payload.data.result,
|
||||||
);
|
);
|
||||||
getWidgetQueryRange.data.payload.data.result = sortedSeriesData;
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
queryResponse.data.payload.data.result = sortedSeriesData;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedWidget === undefined) {
|
if (selectedWidget === undefined) {
|
||||||
return <Card>Invalid widget</Card>;
|
return <Card>Invalid widget</Card>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getWidgetQueryRange.error) {
|
if (queryResponse?.error) {
|
||||||
return (
|
return (
|
||||||
<NotFoundContainer>
|
<NotFoundContainer>
|
||||||
<Typography>{getWidgetQueryRange.error.message}</Typography>
|
<Typography>{queryResponse.error.message}</Typography>
|
||||||
</NotFoundContainer>
|
</NotFoundContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (getWidgetQueryRange.isLoading) {
|
if (queryResponse.isLoading && selectedGraph !== PANEL_TYPES.LIST) {
|
||||||
return <Spinner size="large" tip="Loading..." />;
|
return <Spinner size="large" tip="Loading..." />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
selectedGraph !== PANEL_TYPES.LIST &&
|
selectedGraph !== PANEL_TYPES.LIST &&
|
||||||
getWidgetQueryRange.data?.payload.data.result.length === 0
|
queryResponse.data?.payload.data.result.length === 0
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<NotFoundContainer>
|
<NotFoundContainer>
|
||||||
@ -75,7 +50,7 @@ function WidgetGraphContainer({
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
selectedGraph === PANEL_TYPES.LIST &&
|
selectedGraph === PANEL_TYPES.LIST &&
|
||||||
getWidgetQueryRange.data?.payload.data.newResult.data.result.length === 0
|
queryResponse.data?.payload.data.newResult.data.result.length === 0
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<NotFoundContainer>
|
<NotFoundContainer>
|
||||||
@ -86,17 +61,9 @@ function WidgetGraphContainer({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<WidgetGraph
|
<WidgetGraph
|
||||||
yAxisUnit={yAxisUnit || ''}
|
|
||||||
getWidgetQueryRange={getWidgetQueryRange}
|
|
||||||
selectedWidget={selectedWidget}
|
selectedWidget={selectedWidget}
|
||||||
thresholds={thresholds}
|
queryResponse={queryResponse}
|
||||||
fillSpans={fillSpans}
|
setRequestData={setRequestData}
|
||||||
softMax={softMax}
|
|
||||||
softMin={softMin}
|
|
||||||
selectedLogFields={selectedLogFields}
|
|
||||||
selectedTracesFields={selectedTracesFields}
|
|
||||||
selectedTime={selectedTime}
|
|
||||||
selectedGraph={selectedGraph}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,98 +1,35 @@
|
|||||||
import { QueryParams } from 'constants/query';
|
import { QueryParams } from 'constants/query';
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import PanelWrapper from 'container/PanelWrapper/PanelWrapper';
|
||||||
import GridPanelSwitch from 'container/GridPanelSwitch';
|
|
||||||
import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types';
|
|
||||||
import { timePreferance } from 'container/NewWidget/RightContainer/timeItems';
|
|
||||||
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config';
|
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config';
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
|
||||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
|
||||||
import { useResizeObserver } from 'hooks/useDimensions';
|
|
||||||
import useUrlQuery from 'hooks/useUrlQuery';
|
import useUrlQuery from 'hooks/useUrlQuery';
|
||||||
|
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||||
import GetMinMax from 'lib/getMinMax';
|
import GetMinMax from 'lib/getMinMax';
|
||||||
import getTimeString from 'lib/getTimeString';
|
import getTimeString from 'lib/getTimeString';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions';
|
import {
|
||||||
import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData';
|
Dispatch,
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
SetStateAction,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
} from 'react';
|
||||||
import { UseQueryResult } from 'react-query';
|
import { UseQueryResult } from 'react-query';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { UpdateTimeInterval } from 'store/actions';
|
import { UpdateTimeInterval } from 'store/actions';
|
||||||
import { AppState } from 'store/reducers';
|
|
||||||
import { SuccessResponse } from 'types/api';
|
import { SuccessResponse } from 'types/api';
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
|
||||||
import { getTimeRange } from 'utils/getTimeRange';
|
|
||||||
|
|
||||||
function WidgetGraph({
|
function WidgetGraph({
|
||||||
getWidgetQueryRange,
|
|
||||||
selectedWidget,
|
selectedWidget,
|
||||||
yAxisUnit,
|
queryResponse,
|
||||||
thresholds,
|
setRequestData,
|
||||||
fillSpans,
|
|
||||||
softMax,
|
|
||||||
softMin,
|
|
||||||
selectedLogFields,
|
|
||||||
selectedTracesFields,
|
|
||||||
selectedTime,
|
|
||||||
selectedGraph,
|
|
||||||
}: WidgetGraphProps): JSX.Element {
|
}: WidgetGraphProps): JSX.Element {
|
||||||
const { stagedQuery, currentQuery } = useQueryBuilder();
|
|
||||||
|
|
||||||
const { minTime, maxTime, selectedTime: globalSelectedInterval } = useSelector<
|
|
||||||
AppState,
|
|
||||||
GlobalReducer
|
|
||||||
>((state) => state.globalTime);
|
|
||||||
|
|
||||||
const [minTimeScale, setMinTimeScale] = useState<number>();
|
|
||||||
const [maxTimeScale, setMaxTimeScale] = useState<number>();
|
|
||||||
const location = useLocation();
|
|
||||||
|
|
||||||
useEffect((): void => {
|
|
||||||
const { startTime, endTime } = getTimeRange(getWidgetQueryRange);
|
|
||||||
|
|
||||||
setMinTimeScale(startTime);
|
|
||||||
setMaxTimeScale(endTime);
|
|
||||||
}, [getWidgetQueryRange, maxTime, minTime, globalSelectedInterval]);
|
|
||||||
|
|
||||||
const graphRef = useRef<HTMLDivElement>(null);
|
const graphRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const containerDimensions = useResizeObserver(graphRef);
|
|
||||||
|
|
||||||
const chartData = getUPlotChartData(
|
|
||||||
getWidgetQueryRange?.data?.payload,
|
|
||||||
fillSpans,
|
|
||||||
);
|
|
||||||
|
|
||||||
const isDarkMode = useIsDarkMode();
|
|
||||||
|
|
||||||
const params = useUrlQuery();
|
|
||||||
|
|
||||||
const widgetId = params.get('widgetId');
|
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const urlQuery = useUrlQuery();
|
||||||
const onDragSelect = useCallback(
|
const location = useLocation();
|
||||||
(start: number, end: number): void => {
|
|
||||||
const startTimestamp = Math.trunc(start);
|
|
||||||
const endTimestamp = Math.trunc(end);
|
|
||||||
if (startTimestamp !== endTimestamp) {
|
|
||||||
dispatch(UpdateTimeInterval('custom', [startTimestamp, endTimestamp]));
|
|
||||||
}
|
|
||||||
|
|
||||||
const { maxTime, minTime } = GetMinMax('custom', [
|
|
||||||
startTimestamp,
|
|
||||||
endTimestamp,
|
|
||||||
]);
|
|
||||||
|
|
||||||
params.set(QueryParams.startTime, minTime.toString());
|
|
||||||
params.set(QueryParams.endTime, maxTime.toString());
|
|
||||||
const generatedUrl = `${location.pathname}?${params.toString()}`;
|
|
||||||
history.push(generatedUrl);
|
|
||||||
},
|
|
||||||
[dispatch, location.pathname, params],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleBackNavigation = (): void => {
|
const handleBackNavigation = (): void => {
|
||||||
const searchParams = new URLSearchParams(window.location.search);
|
const searchParams = new URLSearchParams(window.location.search);
|
||||||
@ -114,6 +51,28 @@ function WidgetGraph({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onDragSelect = useCallback(
|
||||||
|
(start: number, end: number): void => {
|
||||||
|
const startTimestamp = Math.trunc(start);
|
||||||
|
const endTimestamp = Math.trunc(end);
|
||||||
|
|
||||||
|
if (startTimestamp !== endTimestamp) {
|
||||||
|
dispatch(UpdateTimeInterval('custom', [startTimestamp, endTimestamp]));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { maxTime, minTime } = GetMinMax('custom', [
|
||||||
|
startTimestamp,
|
||||||
|
endTimestamp,
|
||||||
|
]);
|
||||||
|
|
||||||
|
urlQuery.set(QueryParams.startTime, minTime.toString());
|
||||||
|
urlQuery.set(QueryParams.endTime, maxTime.toString());
|
||||||
|
const generatedUrl = `${location.pathname}?${urlQuery.toString()}`;
|
||||||
|
history.push(generatedUrl);
|
||||||
|
},
|
||||||
|
[dispatch, location.pathname, urlQuery],
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.addEventListener('popstate', handleBackNavigation);
|
window.addEventListener('popstate', handleBackNavigation);
|
||||||
|
|
||||||
@ -123,79 +82,25 @@ function WidgetGraph({
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const options = useMemo(
|
|
||||||
() =>
|
|
||||||
getUPlotChartOptions({
|
|
||||||
id: widgetId || 'legend_widget',
|
|
||||||
yAxisUnit,
|
|
||||||
apiResponse: getWidgetQueryRange?.data?.payload,
|
|
||||||
dimensions: containerDimensions,
|
|
||||||
isDarkMode,
|
|
||||||
onDragSelect,
|
|
||||||
thresholds,
|
|
||||||
fillSpans,
|
|
||||||
minTimeScale,
|
|
||||||
maxTimeScale,
|
|
||||||
softMax,
|
|
||||||
softMin,
|
|
||||||
panelType: selectedGraph,
|
|
||||||
currentQuery,
|
|
||||||
}),
|
|
||||||
[
|
|
||||||
widgetId,
|
|
||||||
yAxisUnit,
|
|
||||||
getWidgetQueryRange?.data?.payload,
|
|
||||||
containerDimensions,
|
|
||||||
isDarkMode,
|
|
||||||
onDragSelect,
|
|
||||||
thresholds,
|
|
||||||
fillSpans,
|
|
||||||
minTimeScale,
|
|
||||||
maxTimeScale,
|
|
||||||
softMax,
|
|
||||||
softMin,
|
|
||||||
selectedGraph,
|
|
||||||
currentQuery,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={graphRef} style={{ height: '100%' }}>
|
<div ref={graphRef} style={{ height: '100%' }}>
|
||||||
<GridPanelSwitch
|
<PanelWrapper
|
||||||
data={chartData}
|
widget={selectedWidget}
|
||||||
options={options}
|
queryResponse={queryResponse}
|
||||||
panelType={selectedWidget.panelTypes}
|
setRequestData={setRequestData}
|
||||||
name={widgetId || 'legend_widget'}
|
onDragSelect={onDragSelect}
|
||||||
yAxisUnit={yAxisUnit}
|
|
||||||
panelData={
|
|
||||||
getWidgetQueryRange.data?.payload.data.newResult.data.result || []
|
|
||||||
}
|
|
||||||
query={stagedQuery || selectedWidget.query}
|
|
||||||
thresholds={thresholds}
|
|
||||||
selectedLogFields={selectedLogFields}
|
|
||||||
selectedTracesFields={selectedTracesFields}
|
|
||||||
dataSource={currentQuery.builder.queryData[0].dataSource}
|
|
||||||
selectedTime={selectedTime}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WidgetGraphProps {
|
interface WidgetGraphProps {
|
||||||
thresholds: ThresholdProps[];
|
|
||||||
yAxisUnit: string;
|
|
||||||
selectedWidget: Widgets;
|
selectedWidget: Widgets;
|
||||||
fillSpans: boolean;
|
queryResponse: UseQueryResult<
|
||||||
getWidgetQueryRange: UseQueryResult<
|
|
||||||
SuccessResponse<MetricRangePayloadProps, unknown>,
|
SuccessResponse<MetricRangePayloadProps, unknown>,
|
||||||
Error
|
Error
|
||||||
>;
|
>;
|
||||||
softMax: number | null;
|
setRequestData: Dispatch<SetStateAction<GetQueryResultsProps>>;
|
||||||
softMin: number | null;
|
|
||||||
selectedLogFields: Widgets['selectedLogFields'];
|
|
||||||
selectedTracesFields: Widgets['selectedTracesFields'];
|
|
||||||
selectedTime: timePreferance;
|
|
||||||
selectedGraph: PANEL_TYPES;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WidgetGraph;
|
export default WidgetGraph;
|
||||||
|
@ -1,47 +1,20 @@
|
|||||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||||
import { DEFAULT_ENTITY_VERSION } from 'constants/app';
|
|
||||||
import { Card } from 'container/GridCardLayout/styles';
|
import { Card } from 'container/GridCardLayout/styles';
|
||||||
import { useGetWidgetQueryRange } from 'hooks/queryBuilder/useGetWidgetQueryRange';
|
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
import useUrlQuery from 'hooks/useUrlQuery';
|
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { getGraphType } from 'utils/getGraphType';
|
|
||||||
|
|
||||||
import { WidgetGraphProps } from '../../types';
|
import { WidgetGraphContainerProps } from '../../types';
|
||||||
import PlotTag from './PlotTag';
|
import PlotTag from './PlotTag';
|
||||||
import { AlertIconContainer, Container } from './styles';
|
import { AlertIconContainer, Container } from './styles';
|
||||||
import WidgetGraphComponent from './WidgetGraphContainer';
|
import WidgetGraphComponent from './WidgetGraphContainer';
|
||||||
|
|
||||||
function WidgetGraph({
|
function WidgetGraph({
|
||||||
selectedGraph,
|
selectedGraph,
|
||||||
yAxisUnit,
|
queryResponse,
|
||||||
selectedTime,
|
setRequestData,
|
||||||
thresholds,
|
selectedWidget,
|
||||||
fillSpans,
|
}: WidgetGraphContainerProps): JSX.Element {
|
||||||
softMax,
|
|
||||||
softMin,
|
|
||||||
selectedLogFields,
|
|
||||||
selectedTracesFields,
|
|
||||||
}: WidgetGraphProps): JSX.Element {
|
|
||||||
const { currentQuery } = useQueryBuilder();
|
const { currentQuery } = useQueryBuilder();
|
||||||
const { selectedDashboard } = useDashboard();
|
|
||||||
|
|
||||||
const { widgets = [] } = selectedDashboard?.data || {};
|
|
||||||
|
|
||||||
const params = useUrlQuery();
|
|
||||||
|
|
||||||
const widgetId = params.get('widgetId');
|
|
||||||
|
|
||||||
const selectedWidget = widgets.find((e) => e.id === widgetId);
|
|
||||||
|
|
||||||
const getWidgetQueryRange = useGetWidgetQueryRange(
|
|
||||||
{
|
|
||||||
graphType: getGraphType(selectedGraph),
|
|
||||||
selectedTime: selectedTime.enum,
|
|
||||||
},
|
|
||||||
selectedDashboard?.data?.version || DEFAULT_ENTITY_VERSION,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (selectedWidget === undefined) {
|
if (selectedWidget === undefined) {
|
||||||
return <Card $panelType={selectedGraph}>Invalid widget</Card>;
|
return <Card $panelType={selectedGraph}>Invalid widget</Card>;
|
||||||
@ -50,22 +23,17 @@ function WidgetGraph({
|
|||||||
return (
|
return (
|
||||||
<Container $panelType={selectedGraph}>
|
<Container $panelType={selectedGraph}>
|
||||||
<PlotTag queryType={currentQuery.queryType} panelType={selectedGraph} />
|
<PlotTag queryType={currentQuery.queryType} panelType={selectedGraph} />
|
||||||
{getWidgetQueryRange.error && (
|
{queryResponse.error && (
|
||||||
<AlertIconContainer color="red" title={getWidgetQueryRange.error.message}>
|
<AlertIconContainer color="red" title={queryResponse.error.message}>
|
||||||
<InfoCircleOutlined />
|
<InfoCircleOutlined />
|
||||||
</AlertIconContainer>
|
</AlertIconContainer>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<WidgetGraphComponent
|
<WidgetGraphComponent
|
||||||
thresholds={thresholds}
|
|
||||||
selectedTime={selectedTime}
|
|
||||||
selectedGraph={selectedGraph}
|
selectedGraph={selectedGraph}
|
||||||
yAxisUnit={yAxisUnit}
|
queryResponse={queryResponse}
|
||||||
fillSpans={fillSpans}
|
setRequestData={setRequestData}
|
||||||
softMax={softMax}
|
selectedWidget={selectedWidget}
|
||||||
softMin={softMin}
|
|
||||||
selectedLogFields={selectedLogFields}
|
|
||||||
selectedTracesFields={selectedTracesFields}
|
|
||||||
/>
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { DEFAULT_ENTITY_VERSION } from 'constants/app';
|
||||||
import { memo } from 'react';
|
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
|
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||||
|
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||||
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
|
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
||||||
|
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||||
|
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||||
|
import { memo, useEffect, useState } from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
import { getGraphType } from 'utils/getGraphType';
|
||||||
|
|
||||||
import { WidgetGraphProps } from '../types';
|
import { WidgetGraphProps } from '../types';
|
||||||
import ExplorerColumnsRenderer from './ExplorerColumnsRenderer';
|
import ExplorerColumnsRenderer from './ExplorerColumnsRenderer';
|
||||||
@ -9,32 +20,81 @@ import WidgetGraph from './WidgetGraph';
|
|||||||
|
|
||||||
function LeftContainer({
|
function LeftContainer({
|
||||||
selectedGraph,
|
selectedGraph,
|
||||||
yAxisUnit,
|
|
||||||
selectedTime,
|
|
||||||
thresholds,
|
|
||||||
fillSpans,
|
|
||||||
softMax,
|
|
||||||
softMin,
|
|
||||||
selectedLogFields,
|
selectedLogFields,
|
||||||
setSelectedLogFields,
|
setSelectedLogFields,
|
||||||
selectedTracesFields,
|
selectedTracesFields,
|
||||||
setSelectedTracesFields,
|
setSelectedTracesFields,
|
||||||
|
selectedWidget,
|
||||||
}: WidgetGraphProps): JSX.Element {
|
}: WidgetGraphProps): JSX.Element {
|
||||||
|
const { stagedQuery, redirectWithQueryBuilderData } = useQueryBuilder();
|
||||||
|
const { selectedDashboard } = useDashboard();
|
||||||
|
|
||||||
|
const { selectedTime: globalSelectedInterval } = useSelector<
|
||||||
|
AppState,
|
||||||
|
GlobalReducer
|
||||||
|
>((state) => state.globalTime);
|
||||||
|
|
||||||
|
const [requestData, setRequestData] = useState<GetQueryResultsProps>(() => {
|
||||||
|
if (selectedWidget && selectedWidget.panelTypes !== PANEL_TYPES.LIST) {
|
||||||
|
return {
|
||||||
|
selectedTime: selectedWidget?.timePreferance,
|
||||||
|
graphType: getGraphType(selectedWidget.panelTypes),
|
||||||
|
query: stagedQuery || initialQueriesMap.metrics,
|
||||||
|
globalSelectedInterval,
|
||||||
|
variables: getDashboardVariables(selectedDashboard?.data.variables),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const updatedQuery = { ...(stagedQuery || initialQueriesMap.metrics) };
|
||||||
|
updatedQuery.builder.queryData[0].pageSize = 10;
|
||||||
|
redirectWithQueryBuilderData(updatedQuery);
|
||||||
|
return {
|
||||||
|
query: updatedQuery,
|
||||||
|
graphType: PANEL_TYPES.LIST,
|
||||||
|
selectedTime: 'GLOBAL_TIME',
|
||||||
|
globalSelectedInterval,
|
||||||
|
tableParams: {
|
||||||
|
pagination: {
|
||||||
|
offset: 0,
|
||||||
|
limit: updatedQuery.builder.queryData[0].limit || 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (stagedQuery) {
|
||||||
|
setRequestData((prev) => ({
|
||||||
|
...prev,
|
||||||
|
query: stagedQuery,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [stagedQuery]);
|
||||||
|
|
||||||
|
const queryResponse = useGetQueryRange(
|
||||||
|
requestData,
|
||||||
|
selectedDashboard?.data?.version || DEFAULT_ENTITY_VERSION,
|
||||||
|
{
|
||||||
|
enabled: !!stagedQuery,
|
||||||
|
retry: false,
|
||||||
|
queryKey: [
|
||||||
|
REACT_QUERY_KEY.GET_QUERY_RANGE,
|
||||||
|
globalSelectedInterval,
|
||||||
|
requestData,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<WidgetGraph
|
<WidgetGraph
|
||||||
thresholds={thresholds}
|
|
||||||
selectedTime={selectedTime}
|
|
||||||
selectedGraph={selectedGraph}
|
selectedGraph={selectedGraph}
|
||||||
yAxisUnit={yAxisUnit}
|
queryResponse={queryResponse}
|
||||||
fillSpans={fillSpans}
|
setRequestData={setRequestData}
|
||||||
softMax={softMax}
|
selectedWidget={selectedWidget}
|
||||||
softMin={softMin}
|
|
||||||
selectedLogFields={selectedLogFields}
|
|
||||||
selectedTracesFields={selectedTracesFields}
|
|
||||||
/>
|
/>
|
||||||
<QueryContainer>
|
<QueryContainer>
|
||||||
<QuerySection selectedTime={selectedTime} selectedGraph={selectedGraph} />
|
<QuerySection selectedGraph={selectedGraph} queryResponse={queryResponse} />
|
||||||
{selectedGraph === PANEL_TYPES.LIST && (
|
{selectedGraph === PANEL_TYPES.LIST && (
|
||||||
<ExplorerColumnsRenderer
|
<ExplorerColumnsRenderer
|
||||||
selectedLogFields={selectedLogFields}
|
selectedLogFields={selectedLogFields}
|
||||||
|
@ -81,7 +81,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
return widgets?.find((e) => e.id === widgetId);
|
return widgets?.find((e) => e.id === widgetId);
|
||||||
}, [query, widgets]);
|
}, [query, widgets]);
|
||||||
|
|
||||||
const selectedWidget = getWidget();
|
const [selectedWidget, setSelectedWidget] = useState(getWidget());
|
||||||
|
|
||||||
const [title, setTitle] = useState<string>(
|
const [title, setTitle] = useState<string>(
|
||||||
selectedWidget?.title?.toString() || '',
|
selectedWidget?.title?.toString() || '',
|
||||||
@ -129,6 +129,44 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
: selectedWidget?.softMax || 0,
|
: selectedWidget?.softMax || 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSelectedWidget((prev) => {
|
||||||
|
if (!prev) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
query: currentQuery,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
isStacked: stacked,
|
||||||
|
opacity,
|
||||||
|
nullZeroValues: selectedNullZeroValue,
|
||||||
|
yAxisUnit,
|
||||||
|
thresholds,
|
||||||
|
softMin,
|
||||||
|
softMax,
|
||||||
|
fillSpans: isFillSpans,
|
||||||
|
selectedLogFields,
|
||||||
|
selectedTracesFields,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, [
|
||||||
|
currentQuery,
|
||||||
|
description,
|
||||||
|
isFillSpans,
|
||||||
|
opacity,
|
||||||
|
selectedLogFields,
|
||||||
|
selectedNullZeroValue,
|
||||||
|
selectedTracesFields,
|
||||||
|
softMax,
|
||||||
|
softMin,
|
||||||
|
stacked,
|
||||||
|
thresholds,
|
||||||
|
title,
|
||||||
|
yAxisUnit,
|
||||||
|
]);
|
||||||
|
|
||||||
const closeModal = (): void => {
|
const closeModal = (): void => {
|
||||||
setSaveModal(false);
|
setSaveModal(false);
|
||||||
setDiscardModal(false);
|
setDiscardModal(false);
|
||||||
@ -194,21 +232,21 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
...preWidgets,
|
...preWidgets,
|
||||||
{
|
{
|
||||||
...(selectedWidget || ({} as Widgets)),
|
...(selectedWidget || ({} as Widgets)),
|
||||||
description,
|
description: selectedWidget?.description || '',
|
||||||
timePreferance: selectedTime.enum,
|
timePreferance: selectedTime.enum,
|
||||||
isStacked: stacked,
|
isStacked: selectedWidget?.isStacked || false,
|
||||||
opacity,
|
opacity: selectedWidget?.opacity || '1',
|
||||||
nullZeroValues: selectedNullZeroValue,
|
nullZeroValues: selectedWidget?.nullZeroValues || 'zero',
|
||||||
title,
|
title: selectedWidget?.title,
|
||||||
yAxisUnit,
|
yAxisUnit: selectedWidget?.yAxisUnit,
|
||||||
panelTypes: graphType,
|
panelTypes: graphType,
|
||||||
query: currentQuery,
|
query: currentQuery,
|
||||||
thresholds,
|
thresholds: selectedWidget?.thresholds,
|
||||||
softMin,
|
softMin: selectedWidget?.softMin || 0,
|
||||||
softMax,
|
softMax: selectedWidget?.softMax || 0,
|
||||||
fillSpans: isFillSpans,
|
fillSpans: selectedWidget?.fillSpans,
|
||||||
selectedLogFields,
|
selectedLogFields: selectedWidget?.selectedLogFields || [],
|
||||||
selectedTracesFields,
|
selectedTracesFields: selectedWidget?.selectedTracesFields || [],
|
||||||
},
|
},
|
||||||
...afterWidgets,
|
...afterWidgets,
|
||||||
],
|
],
|
||||||
@ -234,21 +272,9 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
selectedDashboard,
|
selectedDashboard,
|
||||||
preWidgets,
|
preWidgets,
|
||||||
selectedWidget,
|
selectedWidget,
|
||||||
description,
|
|
||||||
selectedTime.enum,
|
selectedTime.enum,
|
||||||
stacked,
|
|
||||||
opacity,
|
|
||||||
selectedNullZeroValue,
|
|
||||||
title,
|
|
||||||
yAxisUnit,
|
|
||||||
graphType,
|
graphType,
|
||||||
currentQuery,
|
currentQuery,
|
||||||
thresholds,
|
|
||||||
softMin,
|
|
||||||
softMax,
|
|
||||||
isFillSpans,
|
|
||||||
selectedLogFields,
|
|
||||||
selectedTracesFields,
|
|
||||||
afterWidgets,
|
afterWidgets,
|
||||||
updateDashboardMutation,
|
updateDashboardMutation,
|
||||||
setSelectedDashboard,
|
setSelectedDashboard,
|
||||||
@ -358,19 +384,16 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
|
|
||||||
<PanelContainer>
|
<PanelContainer>
|
||||||
<LeftContainerWrapper flex={5}>
|
<LeftContainerWrapper flex={5}>
|
||||||
<LeftContainer
|
{selectedWidget && (
|
||||||
selectedTime={selectedTime}
|
<LeftContainer
|
||||||
selectedGraph={graphType}
|
selectedGraph={graphType}
|
||||||
yAxisUnit={yAxisUnit}
|
selectedLogFields={selectedLogFields}
|
||||||
thresholds={thresholds}
|
setSelectedLogFields={setSelectedLogFields}
|
||||||
fillSpans={isFillSpans}
|
selectedTracesFields={selectedTracesFields}
|
||||||
softMax={softMax}
|
setSelectedTracesFields={setSelectedTracesFields}
|
||||||
softMin={softMin}
|
selectedWidget={selectedWidget}
|
||||||
selectedLogFields={selectedLogFields}
|
/>
|
||||||
setSelectedLogFields={setSelectedLogFields}
|
)}
|
||||||
selectedTracesFields={selectedTracesFields}
|
|
||||||
setSelectedTracesFields={setSelectedTracesFields}
|
|
||||||
/>
|
|
||||||
</LeftContainerWrapper>
|
</LeftContainerWrapper>
|
||||||
|
|
||||||
<RightContainerWrapper flex={1}>
|
<RightContainerWrapper flex={1}>
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
|
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||||
import { Dispatch, SetStateAction } from 'react';
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
|
import { UseQueryResult } from 'react-query';
|
||||||
|
import { SuccessResponse } from 'types/api';
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||||
import { ThresholdProps } from './RightContainer/Threshold/types';
|
|
||||||
import { timePreferance } from './RightContainer/timeItems';
|
|
||||||
|
|
||||||
export interface NewWidgetProps {
|
export interface NewWidgetProps {
|
||||||
selectedGraph: PANEL_TYPES;
|
selectedGraph: PANEL_TYPES;
|
||||||
@ -11,15 +12,23 @@ export interface NewWidgetProps {
|
|||||||
fillSpans: Widgets['fillSpans'];
|
fillSpans: Widgets['fillSpans'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WidgetGraphProps extends NewWidgetProps {
|
export interface WidgetGraphProps {
|
||||||
selectedTime: timePreferance;
|
|
||||||
thresholds: ThresholdProps[];
|
|
||||||
softMin: number | null;
|
|
||||||
softMax: number | null;
|
|
||||||
selectedLogFields: Widgets['selectedLogFields'];
|
selectedLogFields: Widgets['selectedLogFields'];
|
||||||
setSelectedLogFields?: Dispatch<SetStateAction<Widgets['selectedLogFields']>>;
|
setSelectedLogFields?: Dispatch<SetStateAction<Widgets['selectedLogFields']>>;
|
||||||
selectedTracesFields: Widgets['selectedTracesFields'];
|
selectedTracesFields: Widgets['selectedTracesFields'];
|
||||||
setSelectedTracesFields?: Dispatch<
|
setSelectedTracesFields?: Dispatch<
|
||||||
SetStateAction<Widgets['selectedTracesFields']>
|
SetStateAction<Widgets['selectedTracesFields']>
|
||||||
>;
|
>;
|
||||||
|
selectedWidget: Widgets;
|
||||||
|
selectedGraph: PANEL_TYPES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type WidgetGraphContainerProps = {
|
||||||
|
queryResponse: UseQueryResult<
|
||||||
|
SuccessResponse<MetricRangePayloadProps, unknown>,
|
||||||
|
Error
|
||||||
|
>;
|
||||||
|
setRequestData: Dispatch<SetStateAction<GetQueryResultsProps>>;
|
||||||
|
selectedGraph: PANEL_TYPES;
|
||||||
|
selectedWidget: Widgets;
|
||||||
|
};
|
||||||
|
37
frontend/src/container/PanelWrapper/ListPanelWrapper.tsx
Normal file
37
frontend/src/container/PanelWrapper/ListPanelWrapper.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import LogsPanelComponent from 'container/LogsPanelTable/LogsPanelComponent';
|
||||||
|
import TracesTableComponent from 'container/TracesTableComponent/TracesTableComponent';
|
||||||
|
import { DataSource } from 'types/common/queryBuilder';
|
||||||
|
|
||||||
|
import { PanelWrapperProps } from './panelWrapper.types';
|
||||||
|
|
||||||
|
function ListPanelWrapper({
|
||||||
|
widget,
|
||||||
|
queryResponse,
|
||||||
|
setRequestData,
|
||||||
|
}: PanelWrapperProps): JSX.Element {
|
||||||
|
const dataSource = widget.query.builder?.queryData[0]?.dataSource;
|
||||||
|
|
||||||
|
if (!setRequestData) {
|
||||||
|
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataSource === DataSource.LOGS) {
|
||||||
|
return (
|
||||||
|
<LogsPanelComponent
|
||||||
|
widget={widget}
|
||||||
|
queryResponse={queryResponse}
|
||||||
|
setRequestData={setRequestData}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<TracesTableComponent
|
||||||
|
widget={widget}
|
||||||
|
queryResponse={queryResponse}
|
||||||
|
setRequestData={setRequestData}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ListPanelWrapper;
|
40
frontend/src/container/PanelWrapper/PanelWrapper.tsx
Normal file
40
frontend/src/container/PanelWrapper/PanelWrapper.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
|
||||||
|
import { PanelTypeVsPanelWrapper } from './constants';
|
||||||
|
import { PanelWrapperProps } from './panelWrapper.types';
|
||||||
|
|
||||||
|
function PanelWrapper({
|
||||||
|
widget,
|
||||||
|
queryResponse,
|
||||||
|
setRequestData,
|
||||||
|
isFullViewMode,
|
||||||
|
setGraphVisibility,
|
||||||
|
graphVisibility,
|
||||||
|
onToggleModelHandler,
|
||||||
|
onClickHandler,
|
||||||
|
onDragSelect,
|
||||||
|
}: PanelWrapperProps): JSX.Element {
|
||||||
|
const Component = PanelTypeVsPanelWrapper[
|
||||||
|
widget.panelTypes
|
||||||
|
] as FC<PanelWrapperProps>;
|
||||||
|
|
||||||
|
if (!Component) {
|
||||||
|
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Component
|
||||||
|
widget={widget}
|
||||||
|
queryResponse={queryResponse}
|
||||||
|
setRequestData={setRequestData}
|
||||||
|
isFullViewMode={isFullViewMode}
|
||||||
|
setGraphVisibility={setGraphVisibility}
|
||||||
|
graphVisibility={graphVisibility}
|
||||||
|
onToggleModelHandler={onToggleModelHandler}
|
||||||
|
onClickHandler={onClickHandler}
|
||||||
|
onDragSelect={onDragSelect}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PanelWrapper;
|
24
frontend/src/container/PanelWrapper/TablePanelWrapper.tsx
Normal file
24
frontend/src/container/PanelWrapper/TablePanelWrapper.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import GridTableComponent from 'container/GridTableComponent';
|
||||||
|
import { GRID_TABLE_CONFIG } from 'container/GridTableComponent/config';
|
||||||
|
|
||||||
|
import { PanelWrapperProps } from './panelWrapper.types';
|
||||||
|
|
||||||
|
function TablePanelWrapper({
|
||||||
|
widget,
|
||||||
|
queryResponse,
|
||||||
|
}: PanelWrapperProps): JSX.Element {
|
||||||
|
const panelData =
|
||||||
|
queryResponse.data?.payload?.data.newResult.data.result || [];
|
||||||
|
const { thresholds } = widget;
|
||||||
|
return (
|
||||||
|
<GridTableComponent
|
||||||
|
data={panelData}
|
||||||
|
query={widget.query}
|
||||||
|
thresholds={thresholds}
|
||||||
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
|
{...GRID_TABLE_CONFIG}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TablePanelWrapper;
|
141
frontend/src/container/PanelWrapper/UplotPanelWrapper.tsx
Normal file
141
frontend/src/container/PanelWrapper/UplotPanelWrapper.tsx
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
import { ToggleGraphProps } from 'components/Graph/types';
|
||||||
|
import Uplot from 'components/Uplot';
|
||||||
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
|
import GraphManager from 'container/GridCardLayout/GridCard/FullView/GraphManager';
|
||||||
|
import { getLocalStorageGraphVisibilityState } from 'container/GridCardLayout/GridCard/utils';
|
||||||
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
|
import { useResizeObserver } from 'hooks/useDimensions';
|
||||||
|
import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions';
|
||||||
|
import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData';
|
||||||
|
import _noop from 'lodash-es/noop';
|
||||||
|
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||||
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { getSortedSeriesData } from 'utils/getSortedSeriesData';
|
||||||
|
import { getTimeRange } from 'utils/getTimeRange';
|
||||||
|
|
||||||
|
import { PanelWrapperProps } from './panelWrapper.types';
|
||||||
|
|
||||||
|
function UplotPanelWrapper({
|
||||||
|
queryResponse,
|
||||||
|
widget,
|
||||||
|
isFullViewMode,
|
||||||
|
setGraphVisibility,
|
||||||
|
graphVisibility,
|
||||||
|
onToggleModelHandler,
|
||||||
|
onClickHandler,
|
||||||
|
onDragSelect,
|
||||||
|
}: PanelWrapperProps): JSX.Element {
|
||||||
|
const { toScrollWidgetId, setToScrollWidgetId } = useDashboard();
|
||||||
|
const isDarkMode = useIsDarkMode();
|
||||||
|
const lineChartRef = useRef<ToggleGraphProps>();
|
||||||
|
const graphRef = useRef<HTMLDivElement>(null);
|
||||||
|
const [minTimeScale, setMinTimeScale] = useState<number>();
|
||||||
|
const [maxTimeScale, setMaxTimeScale] = useState<number>();
|
||||||
|
const { currentQuery } = useQueryBuilder();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (toScrollWidgetId === widget.id) {
|
||||||
|
graphRef.current?.scrollIntoView({
|
||||||
|
behavior: 'smooth',
|
||||||
|
block: 'center',
|
||||||
|
});
|
||||||
|
graphRef.current?.focus();
|
||||||
|
setToScrollWidgetId('');
|
||||||
|
}
|
||||||
|
}, [toScrollWidgetId, setToScrollWidgetId, widget.id]);
|
||||||
|
|
||||||
|
useEffect((): void => {
|
||||||
|
const { startTime, endTime } = getTimeRange(queryResponse);
|
||||||
|
|
||||||
|
setMinTimeScale(startTime);
|
||||||
|
setMaxTimeScale(endTime);
|
||||||
|
}, [queryResponse]);
|
||||||
|
|
||||||
|
const containerDimensions = useResizeObserver(graphRef);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const {
|
||||||
|
graphVisibilityStates: localStoredVisibilityState,
|
||||||
|
} = getLocalStorageGraphVisibilityState({
|
||||||
|
apiResponse: queryResponse.data?.payload.data.result || [],
|
||||||
|
name: widget.id,
|
||||||
|
});
|
||||||
|
if (setGraphVisibility) {
|
||||||
|
setGraphVisibility(localStoredVisibilityState);
|
||||||
|
}
|
||||||
|
}, [queryResponse.data?.payload.data.result, setGraphVisibility, widget.id]);
|
||||||
|
|
||||||
|
if (queryResponse.data && widget.panelTypes === PANEL_TYPES.BAR) {
|
||||||
|
const sortedSeriesData = getSortedSeriesData(
|
||||||
|
queryResponse.data?.payload.data.result,
|
||||||
|
);
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
queryResponse.data.payload.data.result = sortedSeriesData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const chartData = getUPlotChartData(
|
||||||
|
queryResponse?.data?.payload,
|
||||||
|
widget.fillSpans,
|
||||||
|
);
|
||||||
|
|
||||||
|
const options = useMemo(
|
||||||
|
() =>
|
||||||
|
getUPlotChartOptions({
|
||||||
|
id: widget?.id,
|
||||||
|
apiResponse: queryResponse.data?.payload,
|
||||||
|
dimensions: containerDimensions,
|
||||||
|
isDarkMode,
|
||||||
|
onDragSelect,
|
||||||
|
yAxisUnit: widget?.yAxisUnit,
|
||||||
|
onClickHandler: onClickHandler || _noop,
|
||||||
|
thresholds: widget.thresholds,
|
||||||
|
minTimeScale,
|
||||||
|
maxTimeScale,
|
||||||
|
softMax: widget.softMax === undefined ? null : widget.softMax,
|
||||||
|
softMin: widget.softMin === undefined ? null : widget.softMin,
|
||||||
|
graphsVisibilityStates: graphVisibility,
|
||||||
|
setGraphsVisibilityStates: setGraphVisibility,
|
||||||
|
panelType: widget.panelTypes,
|
||||||
|
currentQuery,
|
||||||
|
}),
|
||||||
|
[
|
||||||
|
widget?.id,
|
||||||
|
widget?.yAxisUnit,
|
||||||
|
widget.thresholds,
|
||||||
|
widget.softMax,
|
||||||
|
widget.softMin,
|
||||||
|
widget.panelTypes,
|
||||||
|
queryResponse.data?.payload,
|
||||||
|
containerDimensions,
|
||||||
|
isDarkMode,
|
||||||
|
onDragSelect,
|
||||||
|
onClickHandler,
|
||||||
|
minTimeScale,
|
||||||
|
maxTimeScale,
|
||||||
|
graphVisibility,
|
||||||
|
setGraphVisibility,
|
||||||
|
currentQuery,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ height: '100%', width: '100%' }} ref={graphRef}>
|
||||||
|
<Uplot options={options} data={chartData} ref={lineChartRef} />
|
||||||
|
{isFullViewMode && setGraphVisibility && (
|
||||||
|
<GraphManager
|
||||||
|
data={chartData}
|
||||||
|
name={widget.id}
|
||||||
|
options={options}
|
||||||
|
yAxisUnit={widget.yAxisUnit}
|
||||||
|
onToggleModelHandler={onToggleModelHandler}
|
||||||
|
setGraphsVisibilityStates={setGraphVisibility}
|
||||||
|
graphsVisibilityStates={graphVisibility}
|
||||||
|
lineChartRef={lineChartRef}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UplotPanelWrapper;
|
21
frontend/src/container/PanelWrapper/ValuePanelWrapper.tsx
Normal file
21
frontend/src/container/PanelWrapper/ValuePanelWrapper.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import GridValueComponent from 'container/GridValueComponent';
|
||||||
|
import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData';
|
||||||
|
|
||||||
|
import { PanelWrapperProps } from './panelWrapper.types';
|
||||||
|
|
||||||
|
function ValuePanelWrapper({
|
||||||
|
widget,
|
||||||
|
queryResponse,
|
||||||
|
}: PanelWrapperProps): JSX.Element {
|
||||||
|
const { yAxisUnit, thresholds } = widget;
|
||||||
|
const data = getUPlotChartData(queryResponse?.data?.payload);
|
||||||
|
return (
|
||||||
|
<GridValueComponent
|
||||||
|
data={data}
|
||||||
|
yAxisUnit={yAxisUnit}
|
||||||
|
thresholds={thresholds}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ValuePanelWrapper;
|
16
frontend/src/container/PanelWrapper/constants.ts
Normal file
16
frontend/src/container/PanelWrapper/constants.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
|
|
||||||
|
import ListPanelWrapper from './ListPanelWrapper';
|
||||||
|
import TablePanelWrapper from './TablePanelWrapper';
|
||||||
|
import UplotPanelWrapper from './UplotPanelWrapper';
|
||||||
|
import ValuePanelWrapper from './ValuePanelWrapper';
|
||||||
|
|
||||||
|
export const PanelTypeVsPanelWrapper = {
|
||||||
|
[PANEL_TYPES.TIME_SERIES]: UplotPanelWrapper,
|
||||||
|
[PANEL_TYPES.TABLE]: TablePanelWrapper,
|
||||||
|
[PANEL_TYPES.LIST]: ListPanelWrapper,
|
||||||
|
[PANEL_TYPES.VALUE]: ValuePanelWrapper,
|
||||||
|
[PANEL_TYPES.TRACE]: null,
|
||||||
|
[PANEL_TYPES.EMPTY_WIDGET]: null,
|
||||||
|
[PANEL_TYPES.BAR]: UplotPanelWrapper,
|
||||||
|
};
|
22
frontend/src/container/PanelWrapper/panelWrapper.types.ts
Normal file
22
frontend/src/container/PanelWrapper/panelWrapper.types.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { WidgetGraphComponentProps } from 'container/GridCardLayout/GridCard/types';
|
||||||
|
import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin';
|
||||||
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
|
import { UseQueryResult } from 'react-query';
|
||||||
|
import { SuccessResponse } from 'types/api';
|
||||||
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||||
|
|
||||||
|
export type PanelWrapperProps = {
|
||||||
|
queryResponse: UseQueryResult<
|
||||||
|
SuccessResponse<MetricRangePayloadProps, unknown>,
|
||||||
|
Error
|
||||||
|
>;
|
||||||
|
widget: Widgets;
|
||||||
|
setRequestData?: WidgetGraphComponentProps['setRequestData'];
|
||||||
|
isFullViewMode?: boolean;
|
||||||
|
onToggleModelHandler?: () => void;
|
||||||
|
graphVisibility?: boolean[];
|
||||||
|
setGraphVisibility?: Dispatch<SetStateAction<boolean[]>>;
|
||||||
|
onClickHandler?: OnClickPluginOpts['onClick'];
|
||||||
|
onDragSelect: (start: number, end: number) => void;
|
||||||
|
};
|
@ -1,12 +1,8 @@
|
|||||||
import './TracesTableComponent.styles.scss';
|
import './TracesTableComponent.styles.scss';
|
||||||
|
|
||||||
import { Table } from 'antd';
|
import { Table } from 'antd';
|
||||||
// import { ResizeTable } from 'components/ResizeTable';
|
|
||||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
|
||||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
|
||||||
import Controls from 'container/Controls';
|
import Controls from 'container/Controls';
|
||||||
import { timePreferance } from 'container/NewWidget/RightContainer/timeItems';
|
|
||||||
import { PER_PAGE_OPTIONS } from 'container/TracesExplorer/ListView/configs';
|
import { PER_PAGE_OPTIONS } from 'container/TracesExplorer/ListView/configs';
|
||||||
import { tableStyles } from 'container/TracesExplorer/ListView/styles';
|
import { tableStyles } from 'container/TracesExplorer/ListView/styles';
|
||||||
import {
|
import {
|
||||||
@ -14,76 +10,51 @@ import {
|
|||||||
getTraceLink,
|
getTraceLink,
|
||||||
transformDataWithDate,
|
transformDataWithDate,
|
||||||
} from 'container/TracesExplorer/ListView/utils';
|
} from 'container/TracesExplorer/ListView/utils';
|
||||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
|
||||||
import { Pagination } from 'hooks/queryPagination';
|
import { Pagination } from 'hooks/queryPagination';
|
||||||
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
import {
|
||||||
import { HTMLAttributes, useCallback, useMemo, useState } from 'react';
|
Dispatch,
|
||||||
import { useSelector } from 'react-redux';
|
HTMLAttributes,
|
||||||
import { AppState } from 'store/reducers';
|
SetStateAction,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
|
import { UseQueryResult } from 'react-query';
|
||||||
|
import { SuccessResponse } from 'types/api';
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
|
||||||
|
|
||||||
function TracesTableComponent({
|
function TracesTableComponent({
|
||||||
selectedTracesFields,
|
widget,
|
||||||
query,
|
queryResponse,
|
||||||
version,
|
setRequestData,
|
||||||
selectedTime,
|
|
||||||
}: TracesTableComponentProps): JSX.Element {
|
}: TracesTableComponentProps): JSX.Element {
|
||||||
const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector<
|
|
||||||
AppState,
|
|
||||||
GlobalReducer
|
|
||||||
>((state) => state.globalTime);
|
|
||||||
|
|
||||||
const [pagination, setPagination] = useState<Pagination>({
|
const [pagination, setPagination] = useState<Pagination>({
|
||||||
offset: 0,
|
offset: 0,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { selectedDashboard } = useDashboard();
|
useEffect(() => {
|
||||||
|
setRequestData((prev) => ({
|
||||||
const { data, isFetching, isError } = useGetQueryRange(
|
...prev,
|
||||||
{
|
|
||||||
query,
|
|
||||||
graphType: PANEL_TYPES.LIST,
|
|
||||||
selectedTime: selectedTime?.enum || 'GLOBAL_TIME',
|
|
||||||
globalSelectedInterval: globalSelectedTime,
|
|
||||||
params: {
|
|
||||||
dataSource: 'traces',
|
|
||||||
},
|
|
||||||
tableParams: {
|
tableParams: {
|
||||||
pagination,
|
pagination,
|
||||||
selectColumns: selectedTracesFields,
|
|
||||||
},
|
},
|
||||||
variables: getDashboardVariables(selectedDashboard?.data.variables),
|
}));
|
||||||
},
|
}, [pagination, setRequestData]);
|
||||||
version,
|
|
||||||
{
|
|
||||||
queryKey: [
|
|
||||||
REACT_QUERY_KEY.GET_QUERY_RANGE,
|
|
||||||
globalSelectedTime,
|
|
||||||
maxTime,
|
|
||||||
minTime,
|
|
||||||
query,
|
|
||||||
pagination,
|
|
||||||
selectedTracesFields?.length,
|
|
||||||
selectedTime?.enum,
|
|
||||||
selectedDashboard?.data.variables,
|
|
||||||
],
|
|
||||||
enabled: !!query && !!selectedTracesFields?.length,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const columns = getListColumns(selectedTracesFields || []);
|
const columns = getListColumns(widget.selectedTracesFields || []);
|
||||||
|
|
||||||
const dataLength =
|
const dataLength =
|
||||||
data?.payload?.data?.newResult?.data?.result[0]?.list?.length;
|
queryResponse.data?.payload?.data?.newResult?.data?.result[0]?.list?.length;
|
||||||
const totalCount = useMemo(() => dataLength || 0, [dataLength]);
|
const totalCount = useMemo(() => dataLength || 0, [dataLength]);
|
||||||
|
|
||||||
const queryTableDataResult = data?.payload.data.newResult.data.result;
|
const queryTableDataResult =
|
||||||
|
queryResponse.data?.payload.data.newResult.data.result;
|
||||||
const queryTableData = useMemo(() => queryTableDataResult || [], [
|
const queryTableData = useMemo(() => queryTableDataResult || [], [
|
||||||
queryTableDataResult,
|
queryTableDataResult,
|
||||||
]);
|
]);
|
||||||
@ -108,7 +79,7 @@ function TracesTableComponent({
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isError) {
|
if (queryResponse.isError) {
|
||||||
return <div>{SOMETHING_WENT_WRONG}</div>;
|
return <div>{SOMETHING_WENT_WRONG}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +90,7 @@ function TracesTableComponent({
|
|||||||
pagination={false}
|
pagination={false}
|
||||||
tableLayout="fixed"
|
tableLayout="fixed"
|
||||||
scroll={{ x: true }}
|
scroll={{ x: true }}
|
||||||
loading={isFetching}
|
loading={queryResponse.isFetching}
|
||||||
style={tableStyles}
|
style={tableStyles}
|
||||||
dataSource={transformedQueryTableData}
|
dataSource={transformedQueryTableData}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
@ -131,7 +102,7 @@ function TracesTableComponent({
|
|||||||
<Controls
|
<Controls
|
||||||
totalCount={totalCount}
|
totalCount={totalCount}
|
||||||
perPageOptions={PER_PAGE_OPTIONS}
|
perPageOptions={PER_PAGE_OPTIONS}
|
||||||
isLoading={isFetching}
|
isLoading={queryResponse.isFetching}
|
||||||
offset={pagination.offset}
|
offset={pagination.offset}
|
||||||
countPerPage={pagination.limit}
|
countPerPage={pagination.limit}
|
||||||
handleNavigatePrevious={(): void => {
|
handleNavigatePrevious={(): void => {
|
||||||
@ -160,14 +131,12 @@ function TracesTableComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type TracesTableComponentProps = {
|
export type TracesTableComponentProps = {
|
||||||
selectedTracesFields: Widgets['selectedTracesFields'];
|
queryResponse: UseQueryResult<
|
||||||
query: Query;
|
SuccessResponse<MetricRangePayloadProps, unknown>,
|
||||||
version: string;
|
Error
|
||||||
selectedTime?: timePreferance;
|
>;
|
||||||
};
|
widget: Widgets;
|
||||||
|
setRequestData: Dispatch<SetStateAction<GetQueryResultsProps>>;
|
||||||
TracesTableComponent.defaultProps = {
|
|
||||||
selectedTime: undefined,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TracesTableComponent;
|
export default TracesTableComponent;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user