mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-23 18:36:16 +00:00
* fix: save rules/dashboard is now enabled for metrics irrespective of feature flag disabled * chore: check is updated for alerts * chore: alert condition is updated * chore: condition for alert is updated * fix: edit condition is fixed * fix: isTraceOrLogsQueryBuilder condition for editing a panel * fix: error message is shown to the user --------- Co-authored-by: makeavish <makeavish786@gmail.com>
296 lines
7.7 KiB
TypeScript
296 lines
7.7 KiB
TypeScript
import { LockFilled } from '@ant-design/icons';
|
|
import { Button, Modal, Tooltip, Typography } from 'antd';
|
|
import { FeatureKeys } from 'constants/features';
|
|
import ROUTES from 'constants/routes';
|
|
import { ITEMS } from 'container/NewDashboard/ComponentsSlider/menuItems';
|
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
|
import { MESSAGE, useIsFeatureDisabled } from 'hooks/useFeatureFlag';
|
|
import { useNotifications } from 'hooks/useNotifications';
|
|
import history from 'lib/history';
|
|
import { DashboardWidgetPageParams } from 'pages/DashboardWidget';
|
|
import { useCallback, useMemo, useState } from 'react';
|
|
import { connect, useDispatch, useSelector } from 'react-redux';
|
|
import { generatePath, useLocation, useParams } from 'react-router-dom';
|
|
import { bindActionCreators, Dispatch } from 'redux';
|
|
import { ThunkDispatch } from 'redux-thunk';
|
|
import {
|
|
SaveDashboard,
|
|
SaveDashboardProps,
|
|
} from 'store/actions/dashboard/saveDashboard';
|
|
import { AppState } from 'store/reducers';
|
|
import AppActions from 'types/actions';
|
|
import { FLUSH_DASHBOARD } from 'types/actions/dashboard';
|
|
import { EQueryType } from 'types/common/dashboard';
|
|
import { DataSource } from 'types/common/queryBuilder';
|
|
import AppReducer from 'types/reducer/app';
|
|
import DashboardReducer from 'types/reducer/dashboards';
|
|
|
|
import LeftContainer from './LeftContainer';
|
|
import QueryTypeTag from './LeftContainer/QueryTypeTag';
|
|
import RightContainer from './RightContainer';
|
|
import TimeItems, { timePreferance } from './RightContainer/timeItems';
|
|
import {
|
|
ButtonContainer,
|
|
Container,
|
|
LeftContainerWrapper,
|
|
PanelContainer,
|
|
RightContainerWrapper,
|
|
} from './styles';
|
|
import { NewWidgetProps } from './types';
|
|
|
|
function NewWidget({ selectedGraph, saveSettingOfPanel }: Props): JSX.Element {
|
|
const dispatch = useDispatch();
|
|
const { dashboards } = useSelector<AppState, DashboardReducer>(
|
|
(state) => state.dashboards,
|
|
);
|
|
|
|
const { currentQuery } = useQueryBuilder();
|
|
|
|
const { featureResponse } = useSelector<AppState, AppReducer>(
|
|
(state) => state.app,
|
|
);
|
|
|
|
const [selectedDashboard] = dashboards;
|
|
|
|
const { widgets } = selectedDashboard.data;
|
|
|
|
const { search } = useLocation();
|
|
|
|
const query = useMemo(() => new URLSearchParams(search), [search]);
|
|
|
|
const { dashboardId } = useParams<DashboardWidgetPageParams>();
|
|
|
|
const getWidget = useCallback(() => {
|
|
const widgetId = query.get('widgetId');
|
|
return widgets?.find((e) => e.id === widgetId);
|
|
}, [query, widgets]);
|
|
|
|
const selectedWidget = getWidget();
|
|
|
|
const [title, setTitle] = useState<string>(selectedWidget?.title || '');
|
|
const [description, setDescription] = useState<string>(
|
|
selectedWidget?.description || '',
|
|
);
|
|
const [yAxisUnit, setYAxisUnit] = useState<string>(
|
|
selectedWidget?.yAxisUnit || 'none',
|
|
);
|
|
|
|
const [stacked, setStacked] = useState<boolean>(
|
|
selectedWidget?.isStacked || false,
|
|
);
|
|
const [opacity, setOpacity] = useState<string>(selectedWidget?.opacity || '1');
|
|
const [selectedNullZeroValue, setSelectedNullZeroValue] = useState<string>(
|
|
selectedWidget?.nullZeroValues || 'zero',
|
|
);
|
|
const [saveModal, setSaveModal] = useState(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 { notifications } = useNotifications();
|
|
|
|
const onClickSaveHandler = useCallback(() => {
|
|
// update the global state
|
|
featureResponse
|
|
.refetch()
|
|
.then(() => {
|
|
saveSettingOfPanel({
|
|
uuid: selectedDashboard.uuid,
|
|
description,
|
|
isStacked: stacked,
|
|
nullZeroValues: selectedNullZeroValue,
|
|
opacity,
|
|
timePreferance: selectedTime.enum,
|
|
title,
|
|
yAxisUnit,
|
|
widgetId: query.get('widgetId') || '',
|
|
dashboardId,
|
|
graphType,
|
|
});
|
|
})
|
|
.catch(() => {
|
|
notifications.error({
|
|
message: 'Something went wrong',
|
|
});
|
|
});
|
|
}, [
|
|
featureResponse,
|
|
saveSettingOfPanel,
|
|
selectedDashboard.uuid,
|
|
description,
|
|
stacked,
|
|
selectedNullZeroValue,
|
|
opacity,
|
|
selectedTime.enum,
|
|
title,
|
|
yAxisUnit,
|
|
query,
|
|
dashboardId,
|
|
graphType,
|
|
notifications,
|
|
]);
|
|
|
|
const onClickDiscardHandler = useCallback(() => {
|
|
dispatch({
|
|
type: FLUSH_DASHBOARD,
|
|
});
|
|
history.push(generatePath(ROUTES.DASHBOARD, { dashboardId }));
|
|
}, [dashboardId, dispatch]);
|
|
|
|
const setGraphHandler = (type: ITEMS): void => {
|
|
const params = new URLSearchParams(search);
|
|
params.set('graphType', type);
|
|
history.push({ search: params.toString() });
|
|
setGraphType(type);
|
|
};
|
|
|
|
const onSaveDashboard = useCallback((): void => {
|
|
setSaveModal(true);
|
|
}, []);
|
|
|
|
const isQueryBuilderActive = useIsFeatureDisabled(
|
|
FeatureKeys.QUERY_BUILDER_PANELS,
|
|
);
|
|
|
|
const isNewTraceLogsAvailable = useMemo(
|
|
() =>
|
|
isQueryBuilderActive &&
|
|
currentQuery.queryType === EQueryType.QUERY_BUILDER &&
|
|
currentQuery.builder.queryData.find(
|
|
(query) => query.dataSource !== DataSource.METRICS,
|
|
) !== undefined,
|
|
[
|
|
currentQuery.builder.queryData,
|
|
currentQuery.queryType,
|
|
isQueryBuilderActive,
|
|
],
|
|
);
|
|
|
|
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,
|
|
]);
|
|
|
|
return (
|
|
<Container>
|
|
<ButtonContainer>
|
|
{isSaveDisabled && (
|
|
<Tooltip title={MESSAGE.PANEL}>
|
|
<Button
|
|
icon={<LockFilled />}
|
|
type="primary"
|
|
disabled={isSaveDisabled}
|
|
onClick={onSaveDashboard}
|
|
>
|
|
Save
|
|
</Button>
|
|
</Tooltip>
|
|
)}
|
|
|
|
{!isSaveDisabled && (
|
|
<Button type="primary" disabled={isSaveDisabled} onClick={onSaveDashboard}>
|
|
Save
|
|
</Button>
|
|
)}
|
|
<Button onClick={onClickDiscardHandler}>Discard</Button>
|
|
</ButtonContainer>
|
|
|
|
<PanelContainer>
|
|
<LeftContainerWrapper flex={5}>
|
|
<LeftContainer
|
|
selectedTime={selectedTime}
|
|
selectedGraph={graphType}
|
|
yAxisUnit={yAxisUnit}
|
|
/>
|
|
</LeftContainerWrapper>
|
|
|
|
<RightContainerWrapper flex={1}>
|
|
<RightContainer
|
|
setGraphHandler={setGraphHandler}
|
|
{...{
|
|
title,
|
|
setTitle,
|
|
description,
|
|
setDescription,
|
|
stacked,
|
|
setStacked,
|
|
opacity,
|
|
yAxisUnit,
|
|
setOpacity,
|
|
selectedNullZeroValue,
|
|
setSelectedNullZeroValue,
|
|
selectedGraph: graphType,
|
|
setSelectedTime,
|
|
selectedTime,
|
|
setYAxisUnit,
|
|
}}
|
|
/>
|
|
</RightContainerWrapper>
|
|
</PanelContainer>
|
|
<Modal
|
|
title="Save Changes"
|
|
focusTriggerAfterClose
|
|
forceRender
|
|
destroyOnClose
|
|
closable
|
|
onCancel={(): void => setSaveModal(false)}
|
|
onOk={onClickSaveHandler}
|
|
centered
|
|
open={saveModal}
|
|
width={600}
|
|
>
|
|
<Typography>
|
|
Your graph built with <QueryTypeTag queryType={currentQuery.queryType} />{' '}
|
|
query will be saved. Press OK to confirm.
|
|
</Typography>
|
|
</Modal>
|
|
</Container>
|
|
);
|
|
}
|
|
|
|
interface DispatchProps {
|
|
saveSettingOfPanel: (
|
|
props: SaveDashboardProps,
|
|
) => (dispatch: Dispatch<AppActions>) => void;
|
|
}
|
|
|
|
const mapDispatchToProps = (
|
|
dispatch: ThunkDispatch<unknown, unknown, AppActions>,
|
|
): DispatchProps => ({
|
|
saveSettingOfPanel: bindActionCreators(SaveDashboard, dispatch),
|
|
});
|
|
|
|
type Props = DispatchProps & NewWidgetProps;
|
|
|
|
export default connect(null, mapDispatchToProps)(NewWidget);
|