Unverified Commit 51081565 authored by pal-sig's avatar pal-sig Committed by GitHub
Browse files

Feat(FE): retention UI (#353)

* feat: get set retention api is updated

* feat: Settings retention UI is updated
parent 53d52254
Showing with 461 additions and 30 deletions
+461 -30
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps } from 'types/api/settings/getRetention';
const getRetention = async (): Promise<
SuccessResponse<PayloadProps> | ErrorResponse
> => {
try {
const response = await axios.get<PayloadProps>(`/settings/ttl`);
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default getRetention;
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/settings/setRetention';
const setRetention = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.post<PayloadProps>(
`/settings/ttl?duration=${props.duration}&type=${props.type}`,
);
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default setRetention;
import { DownOutlined } from '@ant-design/icons';
import { Button, Menu } from 'antd';
import { MenuInfo } from 'rc-menu/lib/interface';
import React from 'react';
import { SettingPeroid } from '.';
import {
Dropdown,
Input,
RetentionContainer,
TextContainer,
Typography,
} from './styles';
const Retention = ({
retentionValue,
setRentionValue,
selectedRetentionPeroid,
setSelectedRetentionPeroid,
text,
}: RetentionProps): JSX.Element => {
const options: Option[] = [
{
key: 'hr',
value: 'Hrs',
},
{
key: 'day',
value: 'Days',
},
{
key: 'month',
value: 'Months',
},
];
const onClickHandler = (
e: MenuInfo,
func: React.Dispatch<React.SetStateAction<SettingPeroid>>,
): void => {
const selected = e.key as SettingPeroid;
func(selected);
};
const menu = (
<Menu onClick={(e): void => onClickHandler(e, setSelectedRetentionPeroid)}>
{options.map((option) => (
<Menu.Item key={option.key}>{option.value}</Menu.Item>
))}
</Menu>
);
const currentSelectedOption = (option: SettingPeroid): string | undefined => {
return options.find((e) => e.key === option)?.value;
};
const onChangeHandler = (
e: React.ChangeEvent<HTMLInputElement>,
func: React.Dispatch<React.SetStateAction<number>>,
): void => {
const value = e.target.value;
if (value.length > 0) {
const parsedValue = Math.abs(parseInt(value, 10));
func(parsedValue);
}
if (value.length === 0) {
func(0);
}
};
return (
<RetentionContainer>
<TextContainer>
<Typography>{text}</Typography>
</TextContainer>
<Input
value={retentionValue}
onChange={(e): void => onChangeHandler(e, setRentionValue)}
/>
<Dropdown overlay={menu}>
<Button>
{currentSelectedOption(selectedRetentionPeroid)} <DownOutlined />
</Button>
</Dropdown>
</RetentionContainer>
);
};
interface Option {
key: SettingPeroid;
value: string;
}
interface RetentionProps {
retentionValue: number;
text: string;
setRentionValue: React.Dispatch<React.SetStateAction<number>>;
selectedRetentionPeroid: SettingPeroid;
setSelectedRetentionPeroid: React.Dispatch<
React.SetStateAction<SettingPeroid>
>;
}
export default Retention;
import { Button, Modal, notification, Typography } from 'antd';
import getRetentionperoidApi from 'api/settings/getRetention';
import setRetentionApi from 'api/settings/setRetention';
import Spinner from 'components/Spinner';
import useFetch from 'hooks/useFetch';
import convertIntoHr from 'lib/convertIntoHr';
import getSettingsPeroid from 'lib/getSettingsPeroid';
import React, { useCallback, useEffect, useState } from 'react';
import { PayloadProps } from 'types/api/settings/getRetention';
import Retention from './Retention';
import { ButtonContainer, Container } from './styles';
const GeneralSettings = (): JSX.Element => {
const [
selectedMetricsPeroid,
setSelectedMetricsPeroid,
] = useState<SettingPeroid>('month');
const [notifications, Element] = notification.useNotification();
const [retentionPeroidMetrics, setRetentionPeroidMetrics] = useState<number>(
0,
);
const [modal, setModal] = useState<boolean>(false);
const [postApiLoading, setPostApiLoading] = useState<boolean>(false);
const [selectedTracePeroid, setSelectedTracePeroid] = useState<SettingPeroid>(
'hr',
);
const [retentionPeroidTrace, setRetentionPeroidTrace] = useState<number>(0);
const onClickSaveHandler = useCallback(() => {
onModalToggleHandler();
}, []);
const { payload, loading, error, errorMessage } = useFetch<
PayloadProps,
undefined
>(getRetentionperoidApi, undefined);
const onModalToggleHandler = (): void => {
setModal((modal) => !modal);
};
useEffect(() => {
if (!loading && payload !== undefined) {
const { metrics_ttl_duration_hrs, traces_ttl_duration_hrs } = payload;
const traceValue = getSettingsPeroid(traces_ttl_duration_hrs);
const metricsValue = getSettingsPeroid(metrics_ttl_duration_hrs);
setRetentionPeroidTrace(traceValue.value);
setSelectedTracePeroid(traceValue.peroid);
setRetentionPeroidMetrics(metricsValue.value);
setSelectedMetricsPeroid(metricsValue.peroid);
}
}, [setSelectedMetricsPeroid, loading, payload]);
const onOkHandler = async (): Promise<void> => {
try {
setPostApiLoading(true);
const [tracesResponse, metricsResponse] = await Promise.all([
setRetentionApi({
duration: `${convertIntoHr(retentionPeroidTrace, selectedTracePeroid)}h`,
type: 'traces',
}),
setRetentionApi({
duration: `${convertIntoHr(
retentionPeroidMetrics,
selectedMetricsPeroid,
)}h`,
type: 'metrics',
}),
]);
if (
tracesResponse.statusCode === 200 &&
metricsResponse.statusCode === 200
) {
notifications.success({
message: 'Success!',
placement: 'topRight',
description: 'Congrats. The retention periods were updated correctly.',
});
onModalToggleHandler();
} else {
notifications.error({
message: 'Error',
description:
'There was an issue in changing the retention period. Please try again or reach out to support@signoz.io',
placement: 'topRight',
});
}
setPostApiLoading(false);
} catch (error) {
notifications.error({
message: 'Error',
description:
'There was an issue in changing the retention period. Please try again or reach out to support@signoz.io',
placement: 'topRight',
});
}
};
if (error) {
return <Typography>{errorMessage}</Typography>;
}
if (loading || payload === undefined) {
return <Spinner tip="Loading.." height="70vh" />;
}
return (
<Container>
{Element}
<Retention
text={'Retention Period for Metrics'}
selectedRetentionPeroid={selectedMetricsPeroid}
setRentionValue={setRetentionPeroidMetrics}
retentionValue={retentionPeroidMetrics}
setSelectedRetentionPeroid={setSelectedMetricsPeroid}
/>
<Retention
text={'Retention Period for Traces'}
selectedRetentionPeroid={selectedTracePeroid}
setRentionValue={setRetentionPeroidTrace}
retentionValue={retentionPeroidTrace}
setSelectedRetentionPeroid={setSelectedTracePeroid}
/>
<Modal
title="Are you sure you want to change the retention period?"
focusTriggerAfterClose
forceRender
destroyOnClose
closable
onCancel={onModalToggleHandler}
onOk={onOkHandler}
centered
visible={modal}
confirmLoading={postApiLoading}
>
<Typography>
This will change the amount of storage needed for saving metrics & traces.
</Typography>
</Modal>
<ButtonContainer>
<Button onClick={onClickSaveHandler} type="primary">
Save
</Button>
</ButtonContainer>
</Container>
);
};
export type SettingPeroid = 'hr' | 'day' | 'month';
export default GeneralSettings;
import {
Dropdown as DropDownComponent,
Input as InputComponent,
Typography as TypographyComponent,
} from 'antd';
import styled from 'styled-components';
export const RetentionContainer = styled.div`
width: 50%;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
`;
export const Input = styled(InputComponent)`
&&& {
height: 2rem;
max-width: 150px;
}
`;
export const Typography = styled(TypographyComponent)`
&&& {
display: flex;
align-items: center;
}
`;
export const ButtonContainer = styled.div`
&&& {
display: flex;
justify-content: flex-end;
width: 50%;
align-items: center;
margin-top: 3rem;
}
`;
export const Container = styled.div`
&&& {
display: flex;
flex-direction: column;
}
`;
export const Dropdown = styled(DropDownComponent)`
&&& {
display: flex;
justify-content: center;
align-items: center;
max-width: 150px;
min-width: 150px;
}
`;
export const TextContainer = styled.div`
&&& {
min-width: 100px;
}
`;
import { SettingPeroid } from 'container/GeneralSettings';
const converIntoHr = (value: number, peroid: SettingPeroid): number => {
if (peroid === 'day') {
return value * 24;
}
if (peroid === 'hr') {
return value;
}
return value * 720;
};
export default converIntoHr;
import { SettingPeroid } from 'container/GeneralSettings';
const getSettingsPeroid = (hr: number): PayloadProps => {
if (hr <= 0) {
return {
peroid: 'hr',
value: 0,
};
}
if (hr < 24) {
return {
peroid: 'hr',
value: hr,
};
}
if (hr < 720) {
return {
peroid: 'day',
value: hr / 24,
};
}
return {
peroid: 'month',
value: hr / 720,
};
};
interface PayloadProps {
value: number;
peroid: SettingPeroid;
}
export default getSettingsPeroid;
import { Form, Input, Space } from 'antd';
import { Alert } from 'antd';
import React, { useEffect } from 'react';
import { Tabs } from 'antd';
import React from 'react';
const SettingsPage = (): JSX.Element => {
const [form] = Form.useForm();
useEffect(() => {
form.setFieldsValue({
retention_period: '3 days',
});
}, [form]);
const { TabPane } = Tabs;
import GeneralSettings from 'container/GeneralSettings';
const SettingsPage = (): JSX.Element => {
return (
<>
<Form name="basic" initialValues={{ remember: true }} form={form}>
<Form.Item
label="Retention Period"
name="retention_period"
rules={[{ required: false }]}
style={{ maxWidth: '40%' }}
>
<Input disabled={true} />
</Form.Item>
</Form>
<Space>
<Alert
message="Mail us at support@signoz.io to get instructions on how to change your retention period"
type="info"
/>
</Space>
</>
<Tabs defaultActiveKey="1">
<TabPane tab="General" key="1">
<GeneralSettings />
</TabPane>
{/* <TabPane tab="Alert Channels" key="2">
Alerts
</TabPane>
<TabPane tab="Users" key="3">
Users
</TabPane> */}
</Tabs>
);
};
......
export interface PayloadProps {
metrics_ttl_duration_hrs: number;
traces_ttl_duration_hrs: number;
}
export interface Props {
type: 'metrics' | 'traces';
duration: string;
}
export interface PayloadProps {
success: 'message';
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment