mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 18:59:10 +08:00
chore: TTL and S3 config related changes (#1201)
* fix: 🐛 convert TTL APIs to async * chore: add archive support * chore: update TTL async APIs according to new design * chore: 🔥 clean removeTTL API * fix: metrics s3 config * feat: ttl async with polling (#1195) * feat: ttl state message change and time unit language changes (#1197) * test: ✅ update tests for async TTL api * feat: ttl message info icon (#1202) * feat: ttl pr review changes * chore: refractoring Co-authored-by: makeavish <makeavish786@gmail.com> Co-authored-by: Pranshu Chittora <pranshu@signoz.io> Co-authored-by: palash-signoz <palash@signoz.io> Co-authored-by: Pranay Prateek <pranay@signoz.io>
This commit is contained in:
parent
f92e4798ce
commit
642c6c5920
21
frontend/public/locales/en-GB/generalSettings.json
Normal file
21
frontend/public/locales/en-GB/generalSettings.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"total_retention_period": "Total Retention Period",
|
||||||
|
"move_to_s3": "Move to S3\n(should be lower than total retention period)",
|
||||||
|
"status_message": {
|
||||||
|
"success": "Your last call to change retention period to {{total_retention}} {{s3_part}} was successful.",
|
||||||
|
"failed": "Your last call to change retention period to {{total_retention}} {{s3_part}} failed. Please try again.",
|
||||||
|
"pending": "Your last call to change retention period to {{total_retention}} {{s3_part}} is pending. This may take some time.",
|
||||||
|
"s3_part": "and S3 to {{s3_retention}}"
|
||||||
|
},
|
||||||
|
"retention_save_button": {
|
||||||
|
"pending": "Updating {{name}} retention period",
|
||||||
|
"success": "Save"
|
||||||
|
},
|
||||||
|
"retention_request_race_condition": "Your request to change retention period has failed, as another request is still in process.",
|
||||||
|
"retention_error_message": "There was an issue in changing the retention period for {{name}}. Please try again or reach out to support@signoz.io",
|
||||||
|
"retention_failed_message": "There was an issue in changing the retention period. Please try again or reach out to support@signoz.io",
|
||||||
|
"retention_comparison_error": "Total retention period for {{name}} can’t be lower or equal to the period after which data is moved to s3.",
|
||||||
|
"retention_null_value_error": "Retention Period for {{name}} is not set yet. Please set by choosing below",
|
||||||
|
"retention_confirmation": "Are you sure you want to change the retention period?",
|
||||||
|
"retention_confirmation_description": "This will change the amount of storage needed for saving {{name}}."
|
||||||
|
}
|
@ -13,16 +13,5 @@
|
|||||||
"general": "General",
|
"general": "General",
|
||||||
"alert_channels": "Alert Channels",
|
"alert_channels": "Alert Channels",
|
||||||
"all_errors": "All Exceptions"
|
"all_errors": "All Exceptions"
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"total_retention_period": "Total Retention Period",
|
|
||||||
"move_to_s3": "Move to S3\n(should be lower than total retention period)",
|
|
||||||
"retention_success_message": "Congrats. The retention periods for {{name}} has been updated successfully.",
|
|
||||||
"retention_error_message": "There was an issue in changing the retention period for {{name}}. Please try again or reach out to support@signoz.io",
|
|
||||||
"retention_failed_message": "There was an issue in changing the retention period. Please try again or reach out to support@signoz.io",
|
|
||||||
"retention_comparison_error": "Total retention period for {{name}} can’t be lower or equal to the period after which data is moved to s3.",
|
|
||||||
"retention_null_value_error": "Retention Period for {{name}} is not set yet. Please set by choosing below",
|
|
||||||
"retention_confirmation": "Are you sure you want to change the retention period?",
|
|
||||||
"retention_confirmation_description": "This will change the amount of storage needed for saving metrics & traces."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
21
frontend/public/locales/en/generalSettings.json
Normal file
21
frontend/public/locales/en/generalSettings.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"total_retention_period": "Total Retention Period",
|
||||||
|
"move_to_s3": "Move to S3\n(should be lower than total retention period)",
|
||||||
|
"status_message": {
|
||||||
|
"success": "Your last call to change retention period to {{total_retention}} {{s3_part}} was successful.",
|
||||||
|
"failed": "Your last call to change retention period to {{total_retention}} {{s3_part}} failed. Please try again.",
|
||||||
|
"pending": "Your last call to change retention period to {{total_retention}} {{s3_part}} is pending. This may take some time.",
|
||||||
|
"s3_part": "and S3 to {{s3_retention}}"
|
||||||
|
},
|
||||||
|
"retention_save_button": {
|
||||||
|
"pending": "Updating {{name}} retention period",
|
||||||
|
"success": "Save"
|
||||||
|
},
|
||||||
|
"retention_request_race_condition": "Your request to change retention period has failed, as another request is still in process.",
|
||||||
|
"retention_error_message": "There was an issue in changing the retention period for {{name}}. Please try again or reach out to support@signoz.io",
|
||||||
|
"retention_failed_message": "There was an issue in changing the retention period. Please try again or reach out to support@signoz.io",
|
||||||
|
"retention_comparison_error": "Total retention period for {{name}} can’t be lower or equal to the period after which data is moved to s3.",
|
||||||
|
"retention_null_value_error": "Retention Period for {{name}} is not set yet. Please set by choosing below",
|
||||||
|
"retention_confirmation": "Are you sure you want to change the retention period?",
|
||||||
|
"retention_confirmation_description": "This will change the amount of storage needed for saving {{name}}."
|
||||||
|
}
|
@ -13,16 +13,5 @@
|
|||||||
"general": "General",
|
"general": "General",
|
||||||
"alert_channels": "Alert Channels",
|
"alert_channels": "Alert Channels",
|
||||||
"all_errors": "All Exceptions"
|
"all_errors": "All Exceptions"
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"total_retention_period": "Total Retention Period",
|
|
||||||
"move_to_s3": "Move to S3\n(should be lower than total retention period)",
|
|
||||||
"retention_success_message": "Congrats. The retention periods for {{name}} has been updated successfully.",
|
|
||||||
"retention_error_message": "There was an issue in changing the retention period for {{name}}. Please try again or reach out to support@signoz.io",
|
|
||||||
"retention_failed_message": "There was an issue in changing the retention period. Please try again or reach out to support@signoz.io",
|
|
||||||
"retention_comparison_error": "Total retention period for {{name}} can’t be lower or equal to the period after which data is moved to s3.",
|
|
||||||
"retention_null_value_error": "Retention Period for {{name}} is not set yet. Please set by choosing below",
|
|
||||||
"retention_confirmation": "Are you sure you want to change the retention period?",
|
|
||||||
"retention_confirmation_description": "This will change the amount of storage needed for saving metrics & traces."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,15 @@ import axios from 'api';
|
|||||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||||
import { PayloadProps } from 'types/api/settings/getRetention';
|
import { PayloadProps, Props } from 'types/api/settings/getRetention';
|
||||||
|
|
||||||
const getRetention = async (): Promise<
|
const getRetention = async <T extends Props>(
|
||||||
SuccessResponse<PayloadProps> | ErrorResponse
|
props: T,
|
||||||
> => {
|
): Promise<SuccessResponse<PayloadProps<T>> | ErrorResponse> => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get<PayloadProps>(`/settings/ttl`);
|
const response = await axios.get<PayloadProps<T>>(
|
||||||
|
`/settings/ttl?type=${props}`,
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
|
@ -1,35 +1,67 @@
|
|||||||
import { Button, Col, Modal, notification, Row, Typography } from 'antd';
|
import { LoadingOutlined } from '@ant-design/icons';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Col,
|
||||||
|
Divider,
|
||||||
|
Modal,
|
||||||
|
notification,
|
||||||
|
Row,
|
||||||
|
Spin,
|
||||||
|
Typography,
|
||||||
|
} from 'antd';
|
||||||
import setRetentionApi from 'api/settings/setRetention';
|
import setRetentionApi from 'api/settings/setRetention';
|
||||||
import TextToolTip from 'components/TextToolTip';
|
import TextToolTip from 'components/TextToolTip';
|
||||||
import useComponentPermission from 'hooks/useComponentPermission';
|
import useComponentPermission from 'hooks/useComponentPermission';
|
||||||
import find from 'lodash-es/find';
|
import find from 'lodash-es/find';
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { UseQueryResult } from 'react-query';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
import { useInterval } from 'react-use';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
|
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||||
import {
|
import {
|
||||||
IDiskType,
|
IDiskType,
|
||||||
PayloadProps as GetDisksPayload,
|
PayloadProps as GetDisksPayload,
|
||||||
} from 'types/api/disks/getDisks';
|
} from 'types/api/disks/getDisks';
|
||||||
import { PayloadProps as GetRetentionPayload } from 'types/api/settings/getRetention';
|
import { TTTLType } from 'types/api/settings/common';
|
||||||
|
import {
|
||||||
|
PayloadPropsMetrics as GetRetentionPeriodMetricsPayload,
|
||||||
|
PayloadPropsTraces as GetRetentionPeriodTracesPayload,
|
||||||
|
} from 'types/api/settings/getRetention';
|
||||||
import AppReducer from 'types/reducer/app';
|
import AppReducer from 'types/reducer/app';
|
||||||
|
|
||||||
import Retention from './Retention';
|
import Retention from './Retention';
|
||||||
import { ButtonContainer, ErrorText, ErrorTextContainer } from './styles';
|
import StatusMessage from './StatusMessage';
|
||||||
|
import { ActionItemsContainer, ErrorText, ErrorTextContainer } from './styles';
|
||||||
|
|
||||||
type NumberOrNull = number | null;
|
type NumberOrNull = number | null;
|
||||||
|
|
||||||
function GeneralSettings({
|
function GeneralSettings({
|
||||||
ttlValuesPayload,
|
metricsTtlValuesPayload,
|
||||||
|
tracesTtlValuesPayload,
|
||||||
getAvailableDiskPayload,
|
getAvailableDiskPayload,
|
||||||
|
metricsTtlValuesRefetch,
|
||||||
|
tracesTtlValuesRefetch,
|
||||||
}: GeneralSettingsProps): JSX.Element {
|
}: GeneralSettingsProps): JSX.Element {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation(['generalSettings']);
|
||||||
const [modal, setModal] = useState<boolean>(false);
|
const [modalMetrics, setModalMetrics] = useState<boolean>(false);
|
||||||
const [postApiLoading, setPostApiLoading] = useState<boolean>(false);
|
const [postApiLoadingMetrics, setPostApiLoadingMetrics] = useState<boolean>(
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
const [postApiLoadingTraces, setPostApiLoadingTraces] = useState<boolean>(
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
const [modalTraces, setModalTraces] = useState<boolean>(false);
|
||||||
const [availableDisks] = useState<IDiskType[]>(getAvailableDiskPayload);
|
const [availableDisks] = useState<IDiskType[]>(getAvailableDiskPayload);
|
||||||
|
|
||||||
const [currentTTLValues, setCurrentTTLValues] = useState(ttlValuesPayload);
|
const [metricsCurrentTTLValues, setMetricsCurrentTTLValues] = useState(
|
||||||
|
metricsTtlValuesPayload,
|
||||||
|
);
|
||||||
|
const [tracesCurrentTTLValues, setTracesCurrentTTLValues] = useState(
|
||||||
|
tracesTtlValuesPayload,
|
||||||
|
);
|
||||||
|
|
||||||
const { role } = useSelector<AppState, AppReducer>((state) => state.app);
|
const { role } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||||
|
|
||||||
const [setRetentionPermission] = useComponentPermission(
|
const [setRetentionPermission] = useComponentPermission(
|
||||||
@ -55,195 +87,93 @@ function GeneralSettings({
|
|||||||
] = useState<NumberOrNull>(null);
|
] = useState<NumberOrNull>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentTTLValues) {
|
if (metricsCurrentTTLValues) {
|
||||||
setMetricsTotalRetentionPeriod(currentTTLValues.metrics_ttl_duration_hrs);
|
setMetricsTotalRetentionPeriod(
|
||||||
setMetricsS3RetentionPeriod(
|
metricsCurrentTTLValues.metrics_ttl_duration_hrs,
|
||||||
currentTTLValues.metrics_move_ttl_duration_hrs
|
|
||||||
? currentTTLValues.metrics_move_ttl_duration_hrs
|
|
||||||
: null,
|
|
||||||
);
|
);
|
||||||
setTracesTotalRetentionPeriod(currentTTLValues.traces_ttl_duration_hrs);
|
setMetricsS3RetentionPeriod(
|
||||||
setTracesS3RetentionPeriod(
|
metricsCurrentTTLValues.metrics_move_ttl_duration_hrs
|
||||||
currentTTLValues.traces_move_ttl_duration_hrs
|
? metricsCurrentTTLValues.metrics_move_ttl_duration_hrs
|
||||||
? currentTTLValues.traces_move_ttl_duration_hrs
|
|
||||||
: null,
|
: null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, [currentTTLValues]);
|
}, [metricsCurrentTTLValues]);
|
||||||
|
|
||||||
const onModalToggleHandler = (): void => {
|
useEffect(() => {
|
||||||
setModal((modal) => !modal);
|
if (tracesCurrentTTLValues) {
|
||||||
|
setTracesTotalRetentionPeriod(
|
||||||
|
tracesCurrentTTLValues.traces_ttl_duration_hrs,
|
||||||
|
);
|
||||||
|
setTracesS3RetentionPeriod(
|
||||||
|
tracesCurrentTTLValues.traces_move_ttl_duration_hrs
|
||||||
|
? tracesCurrentTTLValues.traces_move_ttl_duration_hrs
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [tracesCurrentTTLValues]);
|
||||||
|
|
||||||
|
useInterval(
|
||||||
|
async (): Promise<void> => {
|
||||||
|
if (metricsTtlValuesPayload.status === 'pending') {
|
||||||
|
metricsTtlValuesRefetch();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
metricsTtlValuesPayload.status === 'pending' ? 1000 : null,
|
||||||
|
);
|
||||||
|
|
||||||
|
useInterval(
|
||||||
|
async (): Promise<void> => {
|
||||||
|
if (tracesTtlValuesPayload.status === 'pending') {
|
||||||
|
tracesTtlValuesRefetch();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tracesTtlValuesPayload.status === 'pending' ? 1000 : null,
|
||||||
|
);
|
||||||
|
|
||||||
|
const onModalToggleHandler = (type: TTTLType): void => {
|
||||||
|
if (type === 'metrics') setModalMetrics((modal) => !modal);
|
||||||
|
if (type === 'traces') setModalTraces((modal) => !modal);
|
||||||
|
};
|
||||||
|
const onPostApiLoadingHandler = (type: TTTLType): void => {
|
||||||
|
if (type === 'metrics') setPostApiLoadingMetrics((modal) => !modal);
|
||||||
|
if (type === 'traces') setPostApiLoadingTraces((modal) => !modal);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClickSaveHandler = useCallback(() => {
|
const onClickSaveHandler = useCallback(
|
||||||
if (!setRetentionPermission) {
|
(type: TTTLType) => {
|
||||||
notification.error({
|
if (!setRetentionPermission) {
|
||||||
message: `Sorry you don't have permission to make these changes`,
|
notification.error({
|
||||||
});
|
message: `Sorry you don't have permission to make these changes`,
|
||||||
return;
|
});
|
||||||
}
|
return;
|
||||||
onModalToggleHandler();
|
}
|
||||||
}, [setRetentionPermission]);
|
onModalToggleHandler(type);
|
||||||
|
},
|
||||||
|
[setRetentionPermission],
|
||||||
|
);
|
||||||
|
|
||||||
const s3Enabled = useMemo(
|
const s3Enabled = useMemo(
|
||||||
() => !!find(availableDisks, (disks: IDiskType) => disks?.type === 's3'),
|
() => !!find(availableDisks, (disks: IDiskType) => disks?.type === 's3'),
|
||||||
[availableDisks],
|
[availableDisks],
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderConfig = [
|
const [isMetricsSaveDisabled, isTracesSaveDisabled, errorText] = useMemo((): [
|
||||||
{
|
boolean,
|
||||||
name: 'Metrics',
|
boolean,
|
||||||
retentionFields: [
|
string,
|
||||||
{
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
name: t('settings.total_retention_period'),
|
] => {
|
||||||
value: metricsTotalRetentionPeriod,
|
|
||||||
setValue: setMetricsTotalRetentionPeriod,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: t('settings.move_to_s3'),
|
|
||||||
value: metricsS3RetentionPeriod,
|
|
||||||
setValue: setMetricsS3RetentionPeriod,
|
|
||||||
hide: !s3Enabled,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Traces',
|
|
||||||
retentionFields: [
|
|
||||||
{
|
|
||||||
name: t('settings.total_retention_period'),
|
|
||||||
value: tracesTotalRetentionPeriod,
|
|
||||||
setValue: setTracesTotalRetentionPeriod,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: t('settings.move_to_s3'),
|
|
||||||
value: tracesS3RetentionPeriod,
|
|
||||||
setValue: setTracesS3RetentionPeriod,
|
|
||||||
hide: !s3Enabled,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
].map((category): JSX.Element | null => {
|
|
||||||
if (
|
|
||||||
Array.isArray(category.retentionFields) &&
|
|
||||||
category.retentionFields.length > 0
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
<Col flex="40%" style={{ minWidth: 475 }} key={category.name}>
|
|
||||||
<Typography.Title level={3}>{category.name}</Typography.Title>
|
|
||||||
|
|
||||||
{category.retentionFields.map((retentionField) => (
|
|
||||||
<Retention
|
|
||||||
key={retentionField.name}
|
|
||||||
text={retentionField.name}
|
|
||||||
retentionValue={retentionField.value}
|
|
||||||
setRetentionValue={retentionField.setValue}
|
|
||||||
hide={!!retentionField.hide}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Col>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
||||||
const onOkHandler = async (): Promise<void> => {
|
|
||||||
try {
|
|
||||||
setPostApiLoading(true);
|
|
||||||
const apiCalls = [];
|
|
||||||
|
|
||||||
if (
|
|
||||||
!(
|
|
||||||
currentTTLValues?.metrics_move_ttl_duration_hrs ===
|
|
||||||
metricsS3RetentionPeriod &&
|
|
||||||
currentTTLValues.metrics_ttl_duration_hrs === metricsTotalRetentionPeriod
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
apiCalls.push(() =>
|
|
||||||
setRetentionApi({
|
|
||||||
type: 'metrics',
|
|
||||||
totalDuration: `${metricsTotalRetentionPeriod || -1}h`,
|
|
||||||
coldStorage: s3Enabled ? 's3' : null,
|
|
||||||
toColdDuration: `${metricsS3RetentionPeriod || -1}h`,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
apiCalls.push(() => Promise.resolve(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!(
|
|
||||||
currentTTLValues?.traces_move_ttl_duration_hrs ===
|
|
||||||
tracesS3RetentionPeriod &&
|
|
||||||
currentTTLValues.traces_ttl_duration_hrs === tracesTotalRetentionPeriod
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
apiCalls.push(() =>
|
|
||||||
setRetentionApi({
|
|
||||||
type: 'traces',
|
|
||||||
totalDuration: `${tracesTotalRetentionPeriod || -1}h`,
|
|
||||||
coldStorage: s3Enabled ? 's3' : null,
|
|
||||||
toColdDuration: `${tracesS3RetentionPeriod || -1}h`,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
apiCalls.push(() => Promise.resolve(null));
|
|
||||||
}
|
|
||||||
const apiCallSequence = ['metrics', 'traces'];
|
|
||||||
const apiResponses = await Promise.all(apiCalls.map((api) => api()));
|
|
||||||
|
|
||||||
apiResponses.forEach((apiResponse, idx) => {
|
|
||||||
const name = apiCallSequence[idx];
|
|
||||||
if (apiResponse) {
|
|
||||||
if (apiResponse.statusCode === 200) {
|
|
||||||
notification.success({
|
|
||||||
message: 'Success!',
|
|
||||||
placement: 'topRight',
|
|
||||||
|
|
||||||
description: t('settings.retention_success_message', { name }),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'Error',
|
|
||||||
description: t('settings.retention_error_message', { name }),
|
|
||||||
placement: 'topRight',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
onModalToggleHandler();
|
|
||||||
setPostApiLoading(false);
|
|
||||||
} catch (error) {
|
|
||||||
notification.error({
|
|
||||||
message: 'Error',
|
|
||||||
description: t('settings.retention_failed_message'),
|
|
||||||
placement: 'topRight',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Updates the currentTTL Values in order to avoid pushing the same values.
|
|
||||||
setCurrentTTLValues({
|
|
||||||
metrics_ttl_duration_hrs: metricsTotalRetentionPeriod || -1,
|
|
||||||
metrics_move_ttl_duration_hrs: metricsS3RetentionPeriod || -1,
|
|
||||||
traces_ttl_duration_hrs: tracesTotalRetentionPeriod || -1,
|
|
||||||
traces_move_ttl_duration_hrs: tracesS3RetentionPeriod || -1,
|
|
||||||
});
|
|
||||||
|
|
||||||
setModal(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
||||||
const [isDisabled, errorText] = useMemo((): [boolean, string] => {
|
|
||||||
// Various methods to return dynamic error message text.
|
// Various methods to return dynamic error message text.
|
||||||
const messages = {
|
const messages = {
|
||||||
compareError: (name: string | number): string =>
|
compareError: (name: string | number): string =>
|
||||||
t('settings.retention_comparison_error', { name }),
|
t('retention_comparison_error', { name }),
|
||||||
nullValueError: (name: string | number): string =>
|
nullValueError: (name: string | number): string =>
|
||||||
t('settings.retention_null_value_error', { name }),
|
t('retention_null_value_error', { name }),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Defaults to button not disabled and empty error message text.
|
// Defaults to button not disabled and empty error message text.
|
||||||
let isDisabled = false;
|
let isMetricsSaveDisabled = false;
|
||||||
|
let isTracesSaveDisabled = false;
|
||||||
let errorText = '';
|
let errorText = '';
|
||||||
|
|
||||||
if (s3Enabled) {
|
if (s3Enabled) {
|
||||||
@ -251,19 +181,20 @@ function GeneralSettings({
|
|||||||
(metricsTotalRetentionPeriod || metricsS3RetentionPeriod) &&
|
(metricsTotalRetentionPeriod || metricsS3RetentionPeriod) &&
|
||||||
Number(metricsTotalRetentionPeriod) <= Number(metricsS3RetentionPeriod)
|
Number(metricsTotalRetentionPeriod) <= Number(metricsS3RetentionPeriod)
|
||||||
) {
|
) {
|
||||||
isDisabled = true;
|
isMetricsSaveDisabled = true;
|
||||||
errorText = messages.compareError('metrics');
|
errorText = messages.compareError('metrics');
|
||||||
} else if (
|
} else if (
|
||||||
(tracesTotalRetentionPeriod || tracesS3RetentionPeriod) &&
|
(tracesTotalRetentionPeriod || tracesS3RetentionPeriod) &&
|
||||||
Number(tracesTotalRetentionPeriod) <= Number(tracesS3RetentionPeriod)
|
Number(tracesTotalRetentionPeriod) <= Number(tracesS3RetentionPeriod)
|
||||||
) {
|
) {
|
||||||
isDisabled = true;
|
isTracesSaveDisabled = true;
|
||||||
errorText = messages.compareError('traces');
|
errorText = messages.compareError('traces');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!metricsTotalRetentionPeriod || !tracesTotalRetentionPeriod) {
|
if (!metricsTotalRetentionPeriod || !tracesTotalRetentionPeriod) {
|
||||||
isDisabled = true;
|
isMetricsSaveDisabled = true;
|
||||||
|
isTracesSaveDisabled = true;
|
||||||
if (!metricsTotalRetentionPeriod && !tracesTotalRetentionPeriod) {
|
if (!metricsTotalRetentionPeriod && !tracesTotalRetentionPeriod) {
|
||||||
errorText = messages.nullValueError('metrics and traces');
|
errorText = messages.nullValueError('metrics and traces');
|
||||||
} else if (!metricsTotalRetentionPeriod) {
|
} else if (!metricsTotalRetentionPeriod) {
|
||||||
@ -273,25 +204,240 @@ function GeneralSettings({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
currentTTLValues?.metrics_ttl_duration_hrs === metricsTotalRetentionPeriod &&
|
metricsCurrentTTLValues?.metrics_ttl_duration_hrs ===
|
||||||
currentTTLValues.metrics_move_ttl_duration_hrs ===
|
metricsTotalRetentionPeriod &&
|
||||||
metricsS3RetentionPeriod &&
|
metricsCurrentTTLValues.metrics_move_ttl_duration_hrs ===
|
||||||
currentTTLValues.traces_ttl_duration_hrs === tracesTotalRetentionPeriod &&
|
metricsS3RetentionPeriod
|
||||||
currentTTLValues.traces_move_ttl_duration_hrs === tracesS3RetentionPeriod
|
)
|
||||||
) {
|
isMetricsSaveDisabled = true;
|
||||||
isDisabled = true;
|
|
||||||
}
|
if (
|
||||||
return [isDisabled, errorText];
|
tracesCurrentTTLValues.traces_ttl_duration_hrs ===
|
||||||
|
tracesTotalRetentionPeriod &&
|
||||||
|
tracesCurrentTTLValues.traces_move_ttl_duration_hrs ===
|
||||||
|
tracesS3RetentionPeriod
|
||||||
|
)
|
||||||
|
isTracesSaveDisabled = true;
|
||||||
|
|
||||||
|
return [isMetricsSaveDisabled, isTracesSaveDisabled, errorText];
|
||||||
}, [
|
}, [
|
||||||
currentTTLValues,
|
metricsCurrentTTLValues.metrics_move_ttl_duration_hrs,
|
||||||
|
metricsCurrentTTLValues?.metrics_ttl_duration_hrs,
|
||||||
metricsS3RetentionPeriod,
|
metricsS3RetentionPeriod,
|
||||||
metricsTotalRetentionPeriod,
|
metricsTotalRetentionPeriod,
|
||||||
s3Enabled,
|
s3Enabled,
|
||||||
t,
|
t,
|
||||||
|
tracesCurrentTTLValues.traces_move_ttl_duration_hrs,
|
||||||
|
tracesCurrentTTLValues.traces_ttl_duration_hrs,
|
||||||
tracesS3RetentionPeriod,
|
tracesS3RetentionPeriod,
|
||||||
tracesTotalRetentionPeriod,
|
tracesTotalRetentionPeriod,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
|
const onOkHandler = async (type: TTTLType): Promise<void> => {
|
||||||
|
try {
|
||||||
|
onPostApiLoadingHandler(type);
|
||||||
|
const setTTLResponse = await setRetentionApi({
|
||||||
|
type,
|
||||||
|
totalDuration: `${
|
||||||
|
(type === 'metrics'
|
||||||
|
? metricsTotalRetentionPeriod
|
||||||
|
: tracesTotalRetentionPeriod) || -1
|
||||||
|
}h`,
|
||||||
|
coldStorage: s3Enabled ? 's3' : null,
|
||||||
|
toColdDuration: `${
|
||||||
|
(type === 'metrics'
|
||||||
|
? metricsS3RetentionPeriod
|
||||||
|
: tracesS3RetentionPeriod) || -1
|
||||||
|
}h`,
|
||||||
|
});
|
||||||
|
let hasSetTTLFailed = false;
|
||||||
|
if (setTTLResponse.statusCode === 409) {
|
||||||
|
hasSetTTLFailed = true;
|
||||||
|
notification.error({
|
||||||
|
message: 'Error',
|
||||||
|
description: t('retention_request_race_condition'),
|
||||||
|
placement: 'topRight',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'metrics') {
|
||||||
|
metricsTtlValuesRefetch();
|
||||||
|
|
||||||
|
if (!hasSetTTLFailed)
|
||||||
|
// Updates the currentTTL Values in order to avoid pushing the same values.
|
||||||
|
setMetricsCurrentTTLValues({
|
||||||
|
metrics_ttl_duration_hrs: metricsTotalRetentionPeriod || -1,
|
||||||
|
metrics_move_ttl_duration_hrs: metricsS3RetentionPeriod || -1,
|
||||||
|
status: '',
|
||||||
|
});
|
||||||
|
} else if (type === 'traces') {
|
||||||
|
tracesTtlValuesRefetch();
|
||||||
|
|
||||||
|
if (!hasSetTTLFailed)
|
||||||
|
// Updates the currentTTL Values in order to avoid pushing the same values.
|
||||||
|
setTracesCurrentTTLValues({
|
||||||
|
traces_ttl_duration_hrs: tracesTotalRetentionPeriod || -1,
|
||||||
|
traces_move_ttl_duration_hrs: tracesS3RetentionPeriod || -1,
|
||||||
|
status: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notification.error({
|
||||||
|
message: 'Error',
|
||||||
|
description: t('retention_failed_message'),
|
||||||
|
placement: 'topRight',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onPostApiLoadingHandler(type);
|
||||||
|
onModalToggleHandler(type);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderConfig = [
|
||||||
|
{
|
||||||
|
name: 'Metrics',
|
||||||
|
retentionFields: [
|
||||||
|
{
|
||||||
|
name: t('total_retention_period'),
|
||||||
|
value: metricsTotalRetentionPeriod,
|
||||||
|
setValue: setMetricsTotalRetentionPeriod,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: t('move_to_s3'),
|
||||||
|
value: metricsS3RetentionPeriod,
|
||||||
|
setValue: setMetricsS3RetentionPeriod,
|
||||||
|
hide: !s3Enabled,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
save: {
|
||||||
|
modal: modalMetrics,
|
||||||
|
modalOpen: (): void => onClickSaveHandler('metrics'),
|
||||||
|
apiLoading: postApiLoadingMetrics,
|
||||||
|
saveButtonText:
|
||||||
|
metricsTtlValuesPayload.status === 'pending' ? (
|
||||||
|
<span>
|
||||||
|
<Spin spinning size="small" indicator={<LoadingOutlined spin />} />{' '}
|
||||||
|
{t('retention_save_button.pending', { name: 'metrics' })}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span>{t('retention_save_button.success')}</span>
|
||||||
|
),
|
||||||
|
isDisabled:
|
||||||
|
metricsTtlValuesPayload.status === 'pending' || isMetricsSaveDisabled,
|
||||||
|
},
|
||||||
|
statusComponent: (
|
||||||
|
<StatusMessage
|
||||||
|
total_retention={metricsTtlValuesPayload.expected_metrics_ttl_duration_hrs}
|
||||||
|
status={metricsTtlValuesPayload.status}
|
||||||
|
s3_retention={
|
||||||
|
metricsTtlValuesPayload.expected_metrics_move_ttl_duration_hrs
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Traces',
|
||||||
|
retentionFields: [
|
||||||
|
{
|
||||||
|
name: t('total_retention_period'),
|
||||||
|
value: tracesTotalRetentionPeriod,
|
||||||
|
setValue: setTracesTotalRetentionPeriod,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: t('move_to_s3'),
|
||||||
|
value: tracesS3RetentionPeriod,
|
||||||
|
setValue: setTracesS3RetentionPeriod,
|
||||||
|
hide: !s3Enabled,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
save: {
|
||||||
|
modal: modalTraces,
|
||||||
|
modalOpen: (): void => onClickSaveHandler('traces'),
|
||||||
|
apiLoading: postApiLoadingTraces,
|
||||||
|
saveButtonText:
|
||||||
|
tracesTtlValuesPayload.status === 'pending' ? (
|
||||||
|
<span>
|
||||||
|
<Spin spinning size="small" indicator={<LoadingOutlined spin />} />{' '}
|
||||||
|
{t('retention_save_button.pending', { name: 'traces' })}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span>{t('retention_save_button.success')}</span>
|
||||||
|
),
|
||||||
|
isDisabled:
|
||||||
|
tracesTtlValuesPayload.status === 'pending' || isTracesSaveDisabled,
|
||||||
|
},
|
||||||
|
statusComponent: (
|
||||||
|
<StatusMessage
|
||||||
|
total_retention={tracesTtlValuesPayload.expected_traces_ttl_duration_hrs}
|
||||||
|
status={tracesTtlValuesPayload.status}
|
||||||
|
s3_retention={tracesTtlValuesPayload.expected_traces_move_ttl_duration_hrs}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
].map((category, idx, renderArr): JSX.Element | null => {
|
||||||
|
if (
|
||||||
|
Array.isArray(category.retentionFields) &&
|
||||||
|
category.retentionFields.length > 0
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<React.Fragment key={category.name}>
|
||||||
|
<Col xs={22} xl={11} key={category.name}>
|
||||||
|
<Typography.Title level={3}>{category.name}</Typography.Title>
|
||||||
|
|
||||||
|
{category.retentionFields.map((retentionField) => (
|
||||||
|
<Retention
|
||||||
|
key={retentionField.name}
|
||||||
|
text={retentionField.name}
|
||||||
|
retentionValue={retentionField.value}
|
||||||
|
setRetentionValue={retentionField.setValue}
|
||||||
|
hide={!!retentionField.hide}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<ActionItemsContainer>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={category.save.modalOpen}
|
||||||
|
disabled={category.save.isDisabled}
|
||||||
|
>
|
||||||
|
{category.save.saveButtonText}
|
||||||
|
</Button>
|
||||||
|
{category.statusComponent}
|
||||||
|
</ActionItemsContainer>
|
||||||
|
<Modal
|
||||||
|
title={t('retention_confirmation')}
|
||||||
|
focusTriggerAfterClose
|
||||||
|
forceRender
|
||||||
|
destroyOnClose
|
||||||
|
closable
|
||||||
|
onCancel={(): void =>
|
||||||
|
onModalToggleHandler(category.name.toLowerCase() as TTTLType)
|
||||||
|
}
|
||||||
|
onOk={(): Promise<void> =>
|
||||||
|
onOkHandler(category.name.toLowerCase() as TTTLType)
|
||||||
|
}
|
||||||
|
centered
|
||||||
|
visible={category.save.modal}
|
||||||
|
confirmLoading={category.save.apiLoading}
|
||||||
|
>
|
||||||
|
<Typography>
|
||||||
|
{t('retention_confirmation_description', {
|
||||||
|
name: category.name.toLowerCase(),
|
||||||
|
})}
|
||||||
|
</Typography>
|
||||||
|
</Modal>
|
||||||
|
</Col>
|
||||||
|
{idx < renderArr.length && (
|
||||||
|
<Col xs={0} xl={1} style={{ textAlign: 'center' }}>
|
||||||
|
<Divider type="vertical" dashed style={{ height: '100%' }} />
|
||||||
|
</Col>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col xs={24} md={22} xl={20} xxl={18} style={{ margin: 'auto' }}>
|
<Col xs={24} md={22} xl={20} xxl={18} style={{ margin: 'auto' }}>
|
||||||
{Element}
|
{Element}
|
||||||
@ -306,34 +452,20 @@ function GeneralSettings({
|
|||||||
</ErrorTextContainer>
|
</ErrorTextContainer>
|
||||||
|
|
||||||
<Row justify="space-around">{renderConfig}</Row>
|
<Row justify="space-around">{renderConfig}</Row>
|
||||||
|
|
||||||
<Modal
|
|
||||||
title={t('settings.retention_confirmation')}
|
|
||||||
focusTriggerAfterClose
|
|
||||||
forceRender
|
|
||||||
destroyOnClose
|
|
||||||
closable
|
|
||||||
onCancel={onModalToggleHandler}
|
|
||||||
onOk={onOkHandler}
|
|
||||||
centered
|
|
||||||
visible={modal}
|
|
||||||
confirmLoading={postApiLoading}
|
|
||||||
>
|
|
||||||
<Typography>{t('settings.retention_confirmation_description')}</Typography>
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<ButtonContainer>
|
|
||||||
<Button onClick={onClickSaveHandler} disabled={isDisabled} type="primary">
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</ButtonContainer>
|
|
||||||
</Col>
|
</Col>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GeneralSettingsProps {
|
interface GeneralSettingsProps {
|
||||||
ttlValuesPayload: GetRetentionPayload;
|
|
||||||
getAvailableDiskPayload: GetDisksPayload;
|
getAvailableDiskPayload: GetDisksPayload;
|
||||||
|
metricsTtlValuesPayload: GetRetentionPeriodMetricsPayload;
|
||||||
|
tracesTtlValuesPayload: GetRetentionPeriodTracesPayload;
|
||||||
|
metricsTtlValuesRefetch: UseQueryResult<
|
||||||
|
ErrorResponse | SuccessResponse<GetRetentionPeriodMetricsPayload>
|
||||||
|
>['refetch'];
|
||||||
|
tracesTtlValuesRefetch: UseQueryResult<
|
||||||
|
ErrorResponse | SuccessResponse<GetRetentionPeriodTracesPayload>
|
||||||
|
>['refetch'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default GeneralSettings;
|
export default GeneralSettings;
|
||||||
|
69
frontend/src/container/GeneralSettings/StatusMessage.tsx
Normal file
69
frontend/src/container/GeneralSettings/StatusMessage.tsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { green, orange, volcano } from '@ant-design/colors';
|
||||||
|
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||||
|
import { Card, Col, Row } from 'antd';
|
||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { TStatus } from 'types/api/settings/getRetention';
|
||||||
|
|
||||||
|
import { convertHoursValueToRelevantUnitString } from './utils';
|
||||||
|
|
||||||
|
function StatusMessage({
|
||||||
|
total_retention,
|
||||||
|
s3_retention,
|
||||||
|
status,
|
||||||
|
}: StatusMessageProps): JSX.Element | null {
|
||||||
|
const { t } = useTranslation(['generalSettings']);
|
||||||
|
|
||||||
|
const messageColor = useMemo((): string => {
|
||||||
|
if (status === 'success') return green[6];
|
||||||
|
if (status === 'pending') return orange[6];
|
||||||
|
if (status === 'failed') return volcano[6];
|
||||||
|
return 'inherit';
|
||||||
|
}, [status]);
|
||||||
|
if (!status) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const s3Part =
|
||||||
|
s3_retention && s3_retention !== -1
|
||||||
|
? t('status_message.s3_part', {
|
||||||
|
s3_retention: convertHoursValueToRelevantUnitString(s3_retention),
|
||||||
|
})
|
||||||
|
: '';
|
||||||
|
const statusMessage =
|
||||||
|
total_retention && total_retention !== -1
|
||||||
|
? t(`status_message.${status}`, {
|
||||||
|
total_retention: convertHoursValueToRelevantUnitString(total_retention),
|
||||||
|
s3_part: s3Part,
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return statusMessage ? (
|
||||||
|
<Card
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Row style={{ gap: '1rem', alignItems: 'center', justifyContent: 'center' }}>
|
||||||
|
<Col xs={1}>
|
||||||
|
<InfoCircleOutlined style={{ fontSize: '1.5rem' }} />
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col
|
||||||
|
xs={22}
|
||||||
|
style={{
|
||||||
|
color: messageColor,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{statusMessage}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Card>
|
||||||
|
) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StatusMessageProps {
|
||||||
|
status: TStatus;
|
||||||
|
total_retention: number | undefined;
|
||||||
|
s3_retention: number | undefined;
|
||||||
|
}
|
||||||
|
export default StatusMessage;
|
@ -5,15 +5,33 @@ import Spinner from 'components/Spinner';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useQueries } from 'react-query';
|
import { useQueries } from 'react-query';
|
||||||
|
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||||
|
import { TTTLType } from 'types/api/settings/common';
|
||||||
|
import { PayloadProps as GetRetentionPeriodAPIPayloadProps } from 'types/api/settings/getRetention';
|
||||||
|
|
||||||
import GeneralSettingsContainer from './GeneralSettings';
|
import GeneralSettingsContainer from './GeneralSettings';
|
||||||
|
|
||||||
|
type TRetentionAPIReturn<T extends TTTLType> = Promise<
|
||||||
|
SuccessResponse<GetRetentionPeriodAPIPayloadProps<T>> | ErrorResponse
|
||||||
|
>;
|
||||||
|
|
||||||
function GeneralSettings(): JSX.Element {
|
function GeneralSettings(): JSX.Element {
|
||||||
const { t } = useTranslation('common');
|
const { t } = useTranslation('common');
|
||||||
const [getRetentionPeriodApiResponse, getDisksResponse] = useQueries([
|
|
||||||
|
const [
|
||||||
|
getRetentionPeriodMetricsApiResponse,
|
||||||
|
getRetentionPeriodTracesApiResponse,
|
||||||
|
getDisksResponse,
|
||||||
|
] = useQueries([
|
||||||
{
|
{
|
||||||
queryFn: getRetentionPeriodApi,
|
queryFn: (): TRetentionAPIReturn<'metrics'> =>
|
||||||
queryKey: 'getRetentionPeriodApi',
|
getRetentionPeriodApi('metrics'),
|
||||||
|
queryKey: 'getRetentionPeriodApiMetrics',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
queryFn: (): TRetentionAPIReturn<'traces'> =>
|
||||||
|
getRetentionPeriodApi('traces'),
|
||||||
|
queryKey: 'getRetentionPeriodApiTraces',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
queryFn: getDisks,
|
queryFn: getDisks,
|
||||||
@ -21,21 +39,38 @@ function GeneralSettings(): JSX.Element {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (getRetentionPeriodApiResponse.isError || getDisksResponse.isError) {
|
// Error State - When RetentionPeriodMetricsApi or getDiskApi gets errored out.
|
||||||
|
if (getRetentionPeriodMetricsApiResponse.isError || getDisksResponse.isError) {
|
||||||
return (
|
return (
|
||||||
<Typography>
|
<Typography>
|
||||||
{getRetentionPeriodApiResponse.data?.error ||
|
{getRetentionPeriodMetricsApiResponse.data?.error ||
|
||||||
getDisksResponse.data?.error ||
|
getDisksResponse.data?.error ||
|
||||||
t('something_went_wrong')}
|
t('something_went_wrong')}
|
||||||
</Typography>
|
</Typography>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error State - When RetentionPeriodTracesApi or getDiskApi gets errored out.
|
||||||
|
if (getRetentionPeriodTracesApiResponse.isError || getDisksResponse.isError) {
|
||||||
|
return (
|
||||||
|
<Typography>
|
||||||
|
{getRetentionPeriodTracesApiResponse.data?.error ||
|
||||||
|
getDisksResponse.data?.error ||
|
||||||
|
t('something_went_wrong')}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loading State - When Metrics, Traces and Disk API are in progress and the promise has not been resolved/reject.
|
||||||
if (
|
if (
|
||||||
getRetentionPeriodApiResponse.isLoading ||
|
getRetentionPeriodMetricsApiResponse.isLoading ||
|
||||||
getDisksResponse.isLoading ||
|
getDisksResponse.isLoading ||
|
||||||
!getDisksResponse.data?.payload ||
|
!getDisksResponse.data?.payload ||
|
||||||
!getRetentionPeriodApiResponse.data?.payload
|
!getRetentionPeriodMetricsApiResponse.data?.payload ||
|
||||||
|
getRetentionPeriodTracesApiResponse.isLoading ||
|
||||||
|
getDisksResponse.isLoading ||
|
||||||
|
!getDisksResponse.data?.payload ||
|
||||||
|
!getRetentionPeriodTracesApiResponse.data?.payload
|
||||||
) {
|
) {
|
||||||
return <Spinner tip="Loading.." height="70vh" />;
|
return <Spinner tip="Loading.." height="70vh" />;
|
||||||
}
|
}
|
||||||
@ -44,7 +79,10 @@ function GeneralSettings(): JSX.Element {
|
|||||||
<GeneralSettingsContainer
|
<GeneralSettingsContainer
|
||||||
{...{
|
{...{
|
||||||
getAvailableDiskPayload: getDisksResponse.data?.payload,
|
getAvailableDiskPayload: getDisksResponse.data?.payload,
|
||||||
ttlValuesPayload: getRetentionPeriodApiResponse.data?.payload,
|
metricsTtlValuesPayload: getRetentionPeriodMetricsApiResponse.data?.payload,
|
||||||
|
metricsTtlValuesRefetch: getRetentionPeriodMetricsApiResponse.refetch,
|
||||||
|
tracesTtlValuesPayload: getRetentionPeriodTracesApiResponse.data?.payload,
|
||||||
|
tracesTtlValuesRefetch: getRetentionPeriodTracesApiResponse.refetch,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -90,3 +90,11 @@ export const RetentionFieldLabel = styled(TypographyComponent)`
|
|||||||
export const RetentionFieldInputContainer = styled.div`
|
export const RetentionFieldInputContainer = styled.div`
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const ActionItemsContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 10%;
|
||||||
|
`;
|
||||||
|
@ -23,9 +23,13 @@ export const TimeUnits: ITimeUnit[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
interface ITimeUnitConversion {
|
||||||
|
value: number;
|
||||||
|
timeUnitValue: SettingPeriod;
|
||||||
|
}
|
||||||
export const convertHoursValueToRelevantUnit = (
|
export const convertHoursValueToRelevantUnit = (
|
||||||
value: number,
|
value: number,
|
||||||
): { value: number; timeUnitValue: SettingPeriod } => {
|
): ITimeUnitConversion => {
|
||||||
if (value)
|
if (value)
|
||||||
for (let idx = TimeUnits.length - 1; idx >= 0; idx -= 1) {
|
for (let idx = TimeUnits.length - 1; idx >= 0; idx -= 1) {
|
||||||
const timeUnit = TimeUnits[idx];
|
const timeUnit = TimeUnits[idx];
|
||||||
@ -40,3 +44,13 @@ export const convertHoursValueToRelevantUnit = (
|
|||||||
}
|
}
|
||||||
return { value, timeUnitValue: TimeUnits[0].value };
|
return { value, timeUnitValue: TimeUnits[0].value };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const convertHoursValueToRelevantUnitString = (
|
||||||
|
value: number,
|
||||||
|
): string => {
|
||||||
|
if (!value) return '';
|
||||||
|
const convertedTimeUnit = convertHoursValueToRelevantUnit(value);
|
||||||
|
return `${convertedTimeUnit.value} ${convertedTimeUnit.timeUnitValue}${
|
||||||
|
convertedTimeUnit.value >= 2 ? 's' : ''
|
||||||
|
}`;
|
||||||
|
};
|
||||||
|
1
frontend/src/types/api/settings/common.ts
Normal file
1
frontend/src/types/api/settings/common.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export type TTTLType = 'metrics' | 'traces';
|
@ -1,6 +1,25 @@
|
|||||||
export interface PayloadProps {
|
import { TTTLType } from './common';
|
||||||
|
|
||||||
|
export type TStatus = '' | 'pending' | 'failed' | 'success';
|
||||||
|
export interface PayloadPropsMetrics {
|
||||||
metrics_ttl_duration_hrs: number;
|
metrics_ttl_duration_hrs: number;
|
||||||
metrics_move_ttl_duration_hrs?: number;
|
metrics_move_ttl_duration_hrs?: number;
|
||||||
|
status: TStatus;
|
||||||
|
expected_metrics_move_ttl_duration_hrs?: number;
|
||||||
|
expected_metrics_ttl_duration_hrs?: number;
|
||||||
|
}
|
||||||
|
export interface PayloadPropsTraces {
|
||||||
traces_ttl_duration_hrs: number;
|
traces_ttl_duration_hrs: number;
|
||||||
traces_move_ttl_duration_hrs?: number;
|
traces_move_ttl_duration_hrs?: number;
|
||||||
|
status: TStatus;
|
||||||
|
expected_traces_move_ttl_duration_hrs?: number;
|
||||||
|
expected_traces_ttl_duration_hrs?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type Props = TTTLType;
|
||||||
|
|
||||||
|
export type PayloadProps<T> = T extends 'metrics'
|
||||||
|
? PayloadPropsMetrics
|
||||||
|
: T extends 'traces'
|
||||||
|
? PayloadPropsTraces
|
||||||
|
: never;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
import { TTTLType } from './common';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
type: 'metrics' | 'traces';
|
type: TTTLType;
|
||||||
totalDuration: string;
|
totalDuration: string;
|
||||||
coldStorage?: 's3' | null;
|
coldStorage?: 's3' | null;
|
||||||
toColdDuration?: string;
|
toColdDuration?: string;
|
||||||
|
@ -10,6 +10,8 @@ export type Unauthorized = 401;
|
|||||||
|
|
||||||
export type NotFound = 404;
|
export type NotFound = 404;
|
||||||
|
|
||||||
|
export type Conflict = 409;
|
||||||
|
|
||||||
export type ServerError = 500;
|
export type ServerError = 500;
|
||||||
|
|
||||||
export type SuccessStatusCode = Created | Success;
|
export type SuccessStatusCode = Created | Success;
|
||||||
@ -20,6 +22,7 @@ export type ErrorStatusCode =
|
|||||||
| Unauthorized
|
| Unauthorized
|
||||||
| NotFound
|
| NotFound
|
||||||
| ServerError
|
| ServerError
|
||||||
| BadRequest;
|
| BadRequest
|
||||||
|
| Conflict;
|
||||||
|
|
||||||
export type StatusCode = SuccessStatusCode | ErrorStatusCode;
|
export type StatusCode = SuccessStatusCode | ErrorStatusCode;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user