mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-10-21 03:31:11 +08:00

* fix: restructure code to handle loading state for panel type change * fix: add inline comments
701 lines
20 KiB
TypeScript
701 lines
20 KiB
TypeScript
/* eslint-disable sonarjs/cognitive-complexity */
|
|
import './NewWidget.styles.scss';
|
|
|
|
import { WarningOutlined } from '@ant-design/icons';
|
|
import { Button, Flex, Modal, Space, Tooltip, Typography } from 'antd';
|
|
import FacingIssueBtn from 'components/facingIssueBtn/FacingIssueBtn';
|
|
import { chartHelpMessage } from 'components/facingIssueBtn/util';
|
|
import { FeatureKeys } from 'constants/features';
|
|
import { QueryParams } from 'constants/query';
|
|
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
|
import ROUTES from 'constants/routes';
|
|
import { DashboardShortcuts } from 'constants/shortcuts/DashboardShortcuts';
|
|
import { DEFAULT_BUCKET_COUNT } from 'container/PanelWrapper/constants';
|
|
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
|
import { useKeyboardHotkeys } from 'hooks/hotkeys/useKeyboardHotkeys';
|
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
|
import useAxiosError from 'hooks/useAxiosError';
|
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
|
import { MESSAGE, useIsFeatureDisabled } from 'hooks/useFeatureFlag';
|
|
import useUrlQuery from 'hooks/useUrlQuery';
|
|
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
|
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
|
import history from 'lib/history';
|
|
import { defaultTo, isUndefined } from 'lodash-es';
|
|
import { Check, X } from 'lucide-react';
|
|
import { DashboardWidgetPageParams } from 'pages/DashboardWidget';
|
|
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
|
import {
|
|
getNextWidgets,
|
|
getPreviousWidgets,
|
|
getSelectedWidgetIndex,
|
|
} from 'providers/Dashboard/util';
|
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useSelector } from 'react-redux';
|
|
import { generatePath, useParams } from 'react-router-dom';
|
|
import { AppState } from 'store/reducers';
|
|
import { ColumnUnit, Dashboard, Widgets } from 'types/api/dashboard/getAll';
|
|
import { IField } from 'types/api/logs/fields';
|
|
import { EQueryType } from 'types/common/dashboard';
|
|
import { DataSource } from 'types/common/queryBuilder';
|
|
import AppReducer from 'types/reducer/app';
|
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
|
import { getGraphType, getGraphTypeForFormat } from 'utils/getGraphType';
|
|
|
|
import LeftContainer from './LeftContainer';
|
|
import QueryTypeTag from './LeftContainer/QueryTypeTag';
|
|
import RightContainer from './RightContainer';
|
|
import { ThresholdProps } from './RightContainer/Threshold/types';
|
|
import TimeItems, { timePreferance } from './RightContainer/timeItems';
|
|
import {
|
|
Container,
|
|
LeftContainerWrapper,
|
|
PanelContainer,
|
|
RightContainerWrapper,
|
|
} from './styles';
|
|
import { NewWidgetProps } from './types';
|
|
import {
|
|
getDefaultWidgetData,
|
|
getIsQueryModified,
|
|
handleQueryChange,
|
|
} from './utils';
|
|
|
|
function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|
const {
|
|
selectedDashboard,
|
|
setSelectedDashboard,
|
|
setToScrollWidgetId,
|
|
} = useDashboard();
|
|
|
|
const { t } = useTranslation(['dashboard']);
|
|
|
|
const { registerShortcut, deregisterShortcut } = useKeyboardHotkeys();
|
|
|
|
const {
|
|
currentQuery,
|
|
stagedQuery,
|
|
redirectWithQueryBuilderData,
|
|
supersetQuery,
|
|
} = useQueryBuilder();
|
|
|
|
const isQueryModified = useMemo(
|
|
() => getIsQueryModified(currentQuery, stagedQuery),
|
|
[currentQuery, stagedQuery],
|
|
);
|
|
|
|
const { featureResponse } = useSelector<AppState, AppReducer>(
|
|
(state) => state.app,
|
|
);
|
|
const { selectedTime: globalSelectedInterval } = useSelector<
|
|
AppState,
|
|
GlobalReducer
|
|
>((state) => state.globalTime);
|
|
|
|
const { widgets = [] } = selectedDashboard?.data || {};
|
|
|
|
const query = useUrlQuery();
|
|
|
|
const { dashboardId } = useParams<DashboardWidgetPageParams>();
|
|
|
|
const [isNewDashboard, setIsNewDashboard] = useState<boolean>(false);
|
|
|
|
useEffect(() => {
|
|
const widgetId = query.get('widgetId');
|
|
const selectedWidget = widgets?.find((e) => e.id === widgetId);
|
|
const isWidgetNotPresent = isUndefined(selectedWidget);
|
|
if (isWidgetNotPresent) {
|
|
setIsNewDashboard(true);
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, []);
|
|
|
|
const getWidget = useCallback(() => {
|
|
const widgetId = query.get('widgetId');
|
|
const selectedWidget = widgets?.find((e) => e.id === widgetId);
|
|
return defaultTo(
|
|
selectedWidget,
|
|
getDefaultWidgetData(widgetId || '', selectedGraph),
|
|
) as Widgets;
|
|
}, [query, selectedGraph, widgets]);
|
|
|
|
const [selectedWidget, setSelectedWidget] = useState(getWidget());
|
|
|
|
const [title, setTitle] = useState<string>(
|
|
selectedWidget?.title?.toString() || '',
|
|
);
|
|
const [description, setDescription] = useState<string>(
|
|
selectedWidget?.description || '',
|
|
);
|
|
const [yAxisUnit, setYAxisUnit] = useState<string>(
|
|
selectedWidget?.yAxisUnit || 'none',
|
|
);
|
|
|
|
const [stacked, setStacked] = useState<boolean>(
|
|
selectedWidget?.isStacked || false,
|
|
);
|
|
|
|
const [stackedBarChart, setStackedBarChart] = useState<boolean>(
|
|
selectedWidget?.stackedBarChart || false,
|
|
);
|
|
const [opacity, setOpacity] = useState<string>(selectedWidget?.opacity || '1');
|
|
const [thresholds, setThresholds] = useState<ThresholdProps[]>(
|
|
selectedWidget?.thresholds || [],
|
|
);
|
|
const [selectedNullZeroValue, setSelectedNullZeroValue] = useState<string>(
|
|
selectedWidget?.nullZeroValues || 'zero',
|
|
);
|
|
const [isFillSpans, setIsFillSpans] = useState<boolean>(
|
|
selectedWidget?.fillSpans || false,
|
|
);
|
|
const [saveModal, setSaveModal] = useState(false);
|
|
const [discardModal, setDiscardModal] = useState(false);
|
|
|
|
const [bucketWidth, setBucketWidth] = useState<number>(
|
|
selectedWidget?.bucketWidth || 0,
|
|
);
|
|
|
|
const [bucketCount, setBucketCount] = useState<number>(
|
|
selectedWidget?.bucketCount || DEFAULT_BUCKET_COUNT,
|
|
);
|
|
|
|
const [combineHistogram, setCombineHistogram] = useState<boolean>(
|
|
selectedWidget?.mergeAllActiveQueries || false,
|
|
);
|
|
|
|
const [softMin, setSoftMin] = useState<number | null>(
|
|
selectedWidget?.softMin === null || selectedWidget?.softMin === undefined
|
|
? null
|
|
: selectedWidget?.softMin || 0,
|
|
);
|
|
|
|
const [selectedLogFields, setSelectedLogFields] = useState<IField[] | null>(
|
|
selectedWidget?.selectedLogFields || null,
|
|
);
|
|
|
|
const [selectedTracesFields, setSelectedTracesFields] = useState(
|
|
selectedWidget?.selectedTracesFields || null,
|
|
);
|
|
|
|
const [softMax, setSoftMax] = useState<number | null>(
|
|
selectedWidget?.softMax === null || selectedWidget?.softMax === undefined
|
|
? null
|
|
: selectedWidget?.softMax || 0,
|
|
);
|
|
|
|
const [columnUnits, setColumnUnits] = useState<ColumnUnit>(
|
|
selectedWidget?.columnUnits || {},
|
|
);
|
|
|
|
useEffect(() => {
|
|
setSelectedWidget((prev) => {
|
|
if (!prev) {
|
|
return prev;
|
|
}
|
|
return {
|
|
...prev,
|
|
query: currentQuery,
|
|
title,
|
|
description,
|
|
isStacked: stacked,
|
|
opacity,
|
|
nullZeroValues: selectedNullZeroValue,
|
|
yAxisUnit,
|
|
thresholds,
|
|
softMin,
|
|
softMax,
|
|
fillSpans: isFillSpans,
|
|
columnUnits,
|
|
bucketCount,
|
|
stackedBarChart,
|
|
bucketWidth,
|
|
mergeAllActiveQueries: combineHistogram,
|
|
selectedLogFields,
|
|
selectedTracesFields,
|
|
};
|
|
});
|
|
}, [
|
|
columnUnits,
|
|
currentQuery,
|
|
description,
|
|
isFillSpans,
|
|
opacity,
|
|
selectedLogFields,
|
|
selectedNullZeroValue,
|
|
selectedTracesFields,
|
|
softMax,
|
|
softMin,
|
|
stacked,
|
|
thresholds,
|
|
title,
|
|
yAxisUnit,
|
|
bucketWidth,
|
|
bucketCount,
|
|
combineHistogram,
|
|
stackedBarChart,
|
|
]);
|
|
|
|
const closeModal = (): void => {
|
|
setSaveModal(false);
|
|
setDiscardModal(false);
|
|
};
|
|
|
|
const [graphType, setGraphType] = useState(selectedGraph);
|
|
|
|
const getSelectedTime = useCallback(
|
|
() =>
|
|
TimeItems.find(
|
|
(e) => e.enum === (selectedWidget?.timePreferance || 'GLOBAL_TIME'),
|
|
),
|
|
[selectedWidget],
|
|
);
|
|
|
|
const [selectedTime, setSelectedTime] = useState<timePreferance>({
|
|
name: getSelectedTime()?.name || '',
|
|
enum: selectedWidget?.timePreferance || 'GLOBAL_TIME',
|
|
});
|
|
|
|
const updateDashboardMutation = useUpdateDashboard();
|
|
|
|
const { afterWidgets, preWidgets } = useMemo(() => {
|
|
if (!selectedDashboard) {
|
|
return {
|
|
selectedWidget: {} as Widgets,
|
|
preWidgets: [],
|
|
afterWidgets: [],
|
|
};
|
|
}
|
|
|
|
const widgetId = query.get('widgetId');
|
|
|
|
const selectedWidgetIndex = getSelectedWidgetIndex(
|
|
selectedDashboard,
|
|
widgetId,
|
|
);
|
|
|
|
const preWidgets = getPreviousWidgets(selectedDashboard, selectedWidgetIndex);
|
|
|
|
const afterWidgets = getNextWidgets(selectedDashboard, selectedWidgetIndex);
|
|
|
|
const selectedWidget = (selectedDashboard.data.widgets || [])[
|
|
selectedWidgetIndex || 0
|
|
];
|
|
|
|
return { selectedWidget, preWidgets, afterWidgets };
|
|
}, [selectedDashboard, query]);
|
|
|
|
const handleError = useAxiosError();
|
|
|
|
// this loading state is to take care of mismatch in the responses for table and other panels
|
|
// hence while changing the query contains the older value and the processing logic fails
|
|
const [isLoadingPanelData, setIsLoadingPanelData] = useState<boolean>(false);
|
|
|
|
// request data should be handled by the parent and the child components should consume the same
|
|
// this has been moved here from the left container
|
|
const [requestData, setRequestData] = useState<GetQueryResultsProps>(() => {
|
|
if (selectedWidget && selectedGraph !== PANEL_TYPES.LIST) {
|
|
return {
|
|
selectedTime: selectedWidget?.timePreferance,
|
|
graphType: getGraphType(selectedGraph || selectedWidget.panelTypes),
|
|
query: stagedQuery || initialQueriesMap.metrics,
|
|
globalSelectedInterval,
|
|
formatForWeb:
|
|
getGraphTypeForFormat(selectedGraph || selectedWidget.panelTypes) ===
|
|
PANEL_TYPES.TABLE,
|
|
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: selectedTime.enum || 'GLOBAL_TIME',
|
|
globalSelectedInterval,
|
|
tableParams: {
|
|
pagination: {
|
|
offset: 0,
|
|
limit: updatedQuery.builder.queryData[0].limit || 0,
|
|
},
|
|
},
|
|
};
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (stagedQuery) {
|
|
setIsLoadingPanelData(false);
|
|
setRequestData((prev) => ({
|
|
...prev,
|
|
selectedTime: selectedTime.enum || prev.selectedTime,
|
|
globalSelectedInterval,
|
|
graphType: getGraphType(selectedGraph || selectedWidget.panelTypes),
|
|
query: stagedQuery,
|
|
fillGaps: selectedWidget.fillSpans || false,
|
|
formatForWeb:
|
|
getGraphTypeForFormat(selectedGraph || selectedWidget.panelTypes) ===
|
|
PANEL_TYPES.TABLE,
|
|
}));
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [
|
|
stagedQuery,
|
|
selectedTime,
|
|
selectedWidget.fillSpans,
|
|
globalSelectedInterval,
|
|
]);
|
|
|
|
const onClickSaveHandler = useCallback(() => {
|
|
if (!selectedDashboard) {
|
|
return;
|
|
}
|
|
|
|
const widgetId = query.get('widgetId');
|
|
let updatedLayout = selectedDashboard.data.layout || [];
|
|
if (isNewDashboard) {
|
|
updatedLayout = [
|
|
{
|
|
i: widgetId || '',
|
|
w: 6,
|
|
x: 0,
|
|
h: 6,
|
|
y: 0,
|
|
},
|
|
...updatedLayout,
|
|
];
|
|
}
|
|
const dashboard: Dashboard = {
|
|
...selectedDashboard,
|
|
uuid: selectedDashboard.uuid,
|
|
data: {
|
|
...selectedDashboard.data,
|
|
widgets: isNewDashboard
|
|
? [
|
|
...afterWidgets,
|
|
{
|
|
...(selectedWidget || ({} as Widgets)),
|
|
description: selectedWidget?.description || '',
|
|
timePreferance: selectedTime.enum,
|
|
isStacked: selectedWidget?.isStacked || false,
|
|
opacity: selectedWidget?.opacity || '1',
|
|
nullZeroValues: selectedWidget?.nullZeroValues || 'zero',
|
|
title: selectedWidget?.title,
|
|
stackedBarChart: selectedWidget?.stackedBarChart || false,
|
|
yAxisUnit: selectedWidget?.yAxisUnit,
|
|
panelTypes: graphType,
|
|
query: currentQuery,
|
|
thresholds: selectedWidget?.thresholds,
|
|
columnUnits: selectedWidget?.columnUnits,
|
|
softMin: selectedWidget?.softMin || 0,
|
|
softMax: selectedWidget?.softMax || 0,
|
|
fillSpans: selectedWidget?.fillSpans,
|
|
bucketWidth: selectedWidget?.bucketWidth || 0,
|
|
bucketCount: selectedWidget?.bucketCount || 0,
|
|
mergeAllActiveQueries: selectedWidget?.mergeAllActiveQueries || false,
|
|
selectedLogFields: selectedWidget?.selectedLogFields || [],
|
|
selectedTracesFields: selectedWidget?.selectedTracesFields || [],
|
|
},
|
|
]
|
|
: [
|
|
...preWidgets,
|
|
{
|
|
...(selectedWidget || ({} as Widgets)),
|
|
description: selectedWidget?.description || '',
|
|
timePreferance: selectedTime.enum,
|
|
isStacked: selectedWidget?.isStacked || false,
|
|
opacity: selectedWidget?.opacity || '1',
|
|
nullZeroValues: selectedWidget?.nullZeroValues || 'zero',
|
|
title: selectedWidget?.title,
|
|
stackedBarChart: selectedWidget?.stackedBarChart || false,
|
|
yAxisUnit: selectedWidget?.yAxisUnit,
|
|
panelTypes: graphType,
|
|
query: currentQuery,
|
|
thresholds: selectedWidget?.thresholds,
|
|
columnUnits: selectedWidget?.columnUnits,
|
|
softMin: selectedWidget?.softMin || 0,
|
|
softMax: selectedWidget?.softMax || 0,
|
|
fillSpans: selectedWidget?.fillSpans,
|
|
bucketWidth: selectedWidget?.bucketWidth || 0,
|
|
bucketCount: selectedWidget?.bucketCount || 0,
|
|
mergeAllActiveQueries: selectedWidget?.mergeAllActiveQueries || false,
|
|
selectedLogFields: selectedWidget?.selectedLogFields || [],
|
|
selectedTracesFields: selectedWidget?.selectedTracesFields || [],
|
|
},
|
|
...afterWidgets,
|
|
],
|
|
layout: [...updatedLayout],
|
|
},
|
|
};
|
|
|
|
updateDashboardMutation.mutateAsync(dashboard, {
|
|
onSuccess: () => {
|
|
setSelectedDashboard(dashboard);
|
|
setToScrollWidgetId(selectedWidget?.id || '');
|
|
featureResponse.refetch();
|
|
history.push({
|
|
pathname: generatePath(ROUTES.DASHBOARD, { dashboardId }),
|
|
});
|
|
},
|
|
onError: handleError,
|
|
});
|
|
}, [
|
|
selectedDashboard,
|
|
query,
|
|
isNewDashboard,
|
|
preWidgets,
|
|
selectedWidget,
|
|
selectedTime.enum,
|
|
graphType,
|
|
currentQuery,
|
|
afterWidgets,
|
|
updateDashboardMutation,
|
|
handleError,
|
|
setSelectedDashboard,
|
|
setToScrollWidgetId,
|
|
featureResponse,
|
|
dashboardId,
|
|
]);
|
|
|
|
const onClickDiscardHandler = useCallback(() => {
|
|
if (isQueryModified) {
|
|
setDiscardModal(true);
|
|
return;
|
|
}
|
|
history.push(generatePath(ROUTES.DASHBOARD, { dashboardId }));
|
|
}, [dashboardId, isQueryModified]);
|
|
|
|
const discardChanges = useCallback(() => {
|
|
history.push(generatePath(ROUTES.DASHBOARD, { dashboardId }));
|
|
}, [dashboardId]);
|
|
|
|
const setGraphHandler = (type: PANEL_TYPES): void => {
|
|
setIsLoadingPanelData(true);
|
|
const updatedQuery = handleQueryChange(type as any, supersetQuery);
|
|
setGraphType(type);
|
|
redirectWithQueryBuilderData(
|
|
updatedQuery,
|
|
{ [QueryParams.graphType]: type },
|
|
undefined,
|
|
true,
|
|
);
|
|
};
|
|
|
|
const onSaveDashboard = useCallback((): void => {
|
|
setSaveModal(true);
|
|
}, []);
|
|
|
|
const isQueryBuilderActive = useIsFeatureDisabled(
|
|
FeatureKeys.QUERY_BUILDER_PANELS,
|
|
);
|
|
|
|
const isNewTraceLogsAvailable =
|
|
isQueryBuilderActive &&
|
|
currentQuery.queryType === EQueryType.QUERY_BUILDER &&
|
|
currentQuery.builder.queryData.find(
|
|
(query) => query.dataSource !== DataSource.METRICS,
|
|
) !== undefined;
|
|
|
|
const isSaveDisabled = useMemo(() => {
|
|
// new created dashboard
|
|
if (selectedWidget?.id === 'empty') {
|
|
return isNewTraceLogsAvailable;
|
|
}
|
|
|
|
const isTraceOrLogsQueryBuilder =
|
|
currentQuery.builder.queryData.find(
|
|
(query) =>
|
|
query.dataSource === DataSource.TRACES ||
|
|
query.dataSource === DataSource.LOGS,
|
|
) !== undefined;
|
|
|
|
if (isTraceOrLogsQueryBuilder) {
|
|
return false;
|
|
}
|
|
|
|
return isNewTraceLogsAvailable;
|
|
}, [
|
|
currentQuery.builder.queryData,
|
|
selectedWidget?.id,
|
|
isNewTraceLogsAvailable,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
registerShortcut(DashboardShortcuts.SaveChanges, onSaveDashboard);
|
|
registerShortcut(DashboardShortcuts.DiscardChanges, onClickDiscardHandler);
|
|
|
|
return (): void => {
|
|
deregisterShortcut(DashboardShortcuts.SaveChanges);
|
|
deregisterShortcut(DashboardShortcuts.DiscardChanges);
|
|
};
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [onSaveDashboard]);
|
|
|
|
return (
|
|
<Container>
|
|
<div className="edit-header">
|
|
<div className="left-header">
|
|
<X size={14} onClick={onClickDiscardHandler} className="discard-icon" />
|
|
<Flex align="center" gap={24}>
|
|
<Typography.Text className="configure-panel">
|
|
Configure panel
|
|
</Typography.Text>
|
|
<FacingIssueBtn
|
|
attributes={{
|
|
uuid: selectedDashboard?.uuid,
|
|
title: selectedDashboard?.data.title,
|
|
screen: 'Dashboard widget',
|
|
panelType: graphType,
|
|
widgetId: query.get('widgetId'),
|
|
queryType: currentQuery.queryType,
|
|
}}
|
|
eventName="Dashboard: Facing Issues in dashboard"
|
|
message={chartHelpMessage(selectedDashboard, graphType)}
|
|
buttonText="Facing issues with dashboards?"
|
|
onHoverText="Click here to get help with dashboard widget"
|
|
/>
|
|
</Flex>
|
|
</div>
|
|
{isSaveDisabled && (
|
|
<Tooltip title={MESSAGE.PANEL}>
|
|
<Button
|
|
type="primary"
|
|
data-testid="new-widget-save"
|
|
loading={updateDashboardMutation.isLoading}
|
|
disabled={isSaveDisabled}
|
|
onClick={onSaveDashboard}
|
|
className="save-btn"
|
|
>
|
|
Save Changes
|
|
</Button>
|
|
</Tooltip>
|
|
)}
|
|
{!isSaveDisabled && (
|
|
<Button
|
|
type="primary"
|
|
data-testid="new-widget-save"
|
|
loading={updateDashboardMutation.isLoading}
|
|
disabled={isSaveDisabled}
|
|
onClick={onSaveDashboard}
|
|
icon={<Check size={14} />}
|
|
className="save-btn"
|
|
>
|
|
Save Changes
|
|
</Button>
|
|
)}
|
|
</div>
|
|
|
|
<PanelContainer>
|
|
<LeftContainerWrapper isDarkMode={useIsDarkMode()}>
|
|
{selectedWidget && (
|
|
<LeftContainer
|
|
selectedGraph={graphType}
|
|
selectedLogFields={selectedLogFields}
|
|
setSelectedLogFields={setSelectedLogFields}
|
|
selectedTracesFields={selectedTracesFields}
|
|
setSelectedTracesFields={setSelectedTracesFields}
|
|
selectedWidget={selectedWidget}
|
|
selectedTime={selectedTime}
|
|
requestData={requestData}
|
|
setRequestData={setRequestData}
|
|
isLoadingPanelData={isLoadingPanelData}
|
|
/>
|
|
)}
|
|
</LeftContainerWrapper>
|
|
|
|
<RightContainerWrapper>
|
|
<RightContainer
|
|
setGraphHandler={setGraphHandler}
|
|
title={title}
|
|
setTitle={setTitle}
|
|
description={description}
|
|
setDescription={setDescription}
|
|
stacked={stacked}
|
|
setStacked={setStacked}
|
|
stackedBarChart={stackedBarChart}
|
|
setStackedBarChart={setStackedBarChart}
|
|
opacity={opacity}
|
|
yAxisUnit={yAxisUnit}
|
|
columnUnits={columnUnits}
|
|
setColumnUnits={setColumnUnits}
|
|
bucketCount={bucketCount}
|
|
bucketWidth={bucketWidth}
|
|
combineHistogram={combineHistogram}
|
|
setCombineHistogram={setCombineHistogram}
|
|
setBucketWidth={setBucketWidth}
|
|
setBucketCount={setBucketCount}
|
|
setOpacity={setOpacity}
|
|
selectedNullZeroValue={selectedNullZeroValue}
|
|
setSelectedNullZeroValue={setSelectedNullZeroValue}
|
|
selectedGraph={graphType}
|
|
setSelectedTime={setSelectedTime}
|
|
selectedTime={selectedTime}
|
|
setYAxisUnit={setYAxisUnit}
|
|
thresholds={thresholds}
|
|
setThresholds={setThresholds}
|
|
selectedWidget={selectedWidget}
|
|
isFillSpans={isFillSpans}
|
|
setIsFillSpans={setIsFillSpans}
|
|
softMin={softMin}
|
|
setSoftMin={setSoftMin}
|
|
softMax={softMax}
|
|
setSoftMax={setSoftMax}
|
|
/>
|
|
</RightContainerWrapper>
|
|
</PanelContainer>
|
|
<Modal
|
|
title={
|
|
isQueryModified ? (
|
|
<Space>
|
|
<WarningOutlined style={{ fontSize: '16px', color: '#fdd600' }} />
|
|
Unsaved Changes
|
|
</Space>
|
|
) : (
|
|
'Save Widget'
|
|
)
|
|
}
|
|
focusTriggerAfterClose
|
|
forceRender
|
|
destroyOnClose
|
|
closable
|
|
onCancel={closeModal}
|
|
onOk={onClickSaveHandler}
|
|
confirmLoading={updateDashboardMutation.isLoading}
|
|
centered
|
|
open={saveModal}
|
|
width={600}
|
|
>
|
|
{!isQueryModified ? (
|
|
<Typography>
|
|
{t('your_graph_build_with')}{' '}
|
|
<QueryTypeTag queryType={currentQuery.queryType} />{' '}
|
|
{t('dashboard_ok_confirm')}
|
|
</Typography>
|
|
) : (
|
|
<Typography>{t('dashboard_unsave_changes')} </Typography>
|
|
)}
|
|
</Modal>
|
|
<Modal
|
|
title={
|
|
<Space>
|
|
<WarningOutlined style={{ fontSize: '16px', color: '#fdd600' }} />
|
|
Unsaved Changes
|
|
</Space>
|
|
}
|
|
focusTriggerAfterClose
|
|
forceRender
|
|
destroyOnClose
|
|
closable
|
|
onCancel={closeModal}
|
|
onOk={discardChanges}
|
|
centered
|
|
open={discardModal}
|
|
width={600}
|
|
>
|
|
<Typography>{t('dashboard_unsave_changes')}</Typography>
|
|
</Modal>
|
|
</Container>
|
|
);
|
|
}
|
|
|
|
export default NewWidget;
|