Compare commits
5 Commits
fix/multi-
...
feat/gener
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
733d6ce78c | ||
|
|
d7d78d6ab4 | ||
|
|
fb73f23dce | ||
|
|
cb790ea3e5 | ||
|
|
e48784c09c |
@@ -524,7 +524,13 @@ function GeneralSettings({
|
||||
) {
|
||||
return (
|
||||
<Fragment key={category.name}>
|
||||
<Col xs={22} xl={11} key={category.name} style={{ margin: '0.5rem' }}>
|
||||
<Col
|
||||
xs={22}
|
||||
xl={11}
|
||||
key={category.name}
|
||||
style={{ margin: '0.5rem' }}
|
||||
data-testid={`${category.name.toLowerCase()}-card`}
|
||||
>
|
||||
<Card style={{ height: '100%' }}>
|
||||
<Typography.Title style={{ margin: 0 }} level={3}>
|
||||
{category.name}
|
||||
@@ -554,6 +560,7 @@ function GeneralSettings({
|
||||
type="primary"
|
||||
onClick={category.save.modalOpen}
|
||||
disabled={category.save.isDisabled}
|
||||
data-testid="retention-submit-button"
|
||||
>
|
||||
{category.save.saveButtonText}
|
||||
</Button>
|
||||
@@ -574,6 +581,7 @@ function GeneralSettings({
|
||||
centered
|
||||
open={category.save.modal}
|
||||
confirmLoading={category.save.apiLoading}
|
||||
data-testid={`${category.name.toLowerCase()}-modal`}
|
||||
>
|
||||
<Typography>
|
||||
{t('retention_confirmation_description', {
|
||||
@@ -597,14 +605,16 @@ function GeneralSettings({
|
||||
<Col xs={24} md={22} xl={20} xxl={18} style={{ margin: 'auto' }}>
|
||||
<ErrorTextContainer>
|
||||
{!isCloudUserVal && (
|
||||
<TextToolTip
|
||||
{...{
|
||||
text: `More details on how to set retention period`,
|
||||
url: 'https://signoz.io/docs/userguide/retention-period/',
|
||||
}}
|
||||
/>
|
||||
<div data-testid="help-icon">
|
||||
<TextToolTip
|
||||
{...{
|
||||
text: `More details on how to set retention period`,
|
||||
url: 'https://signoz.io/docs/userguide/retention-period/',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{errorText && <ErrorText>{errorText}</ErrorText>}
|
||||
{errorText && <ErrorText data-testid="error-text">{errorText}</ErrorText>}
|
||||
</ErrorTextContainer>
|
||||
|
||||
<Row justify="start">{renderConfig}</Row>
|
||||
@@ -615,7 +625,7 @@ function GeneralSettings({
|
||||
);
|
||||
}
|
||||
|
||||
interface GeneralSettingsProps {
|
||||
export interface GeneralSettingsProps {
|
||||
getAvailableDiskPayload: GetDisksPayload;
|
||||
metricsTtlValuesPayload: GetRetentionPeriodMetricsPayload;
|
||||
tracesTtlValuesPayload: GetRetentionPeriodTracesPayload;
|
||||
|
||||
@@ -95,9 +95,11 @@ function Retention({
|
||||
|
||||
return (
|
||||
<RetentionContainer>
|
||||
<Row justify="space-between">
|
||||
<Row justify="space-between" aria-label={text}>
|
||||
<Col span={12} style={{ display: 'flex' }}>
|
||||
<RetentionFieldLabel>{text}</RetentionFieldLabel>
|
||||
<RetentionFieldLabel data-testid="retention-field-label">
|
||||
{text}
|
||||
</RetentionFieldLabel>
|
||||
</Col>
|
||||
<Row justify="end">
|
||||
<RetentionFieldInputContainer>
|
||||
@@ -106,12 +108,14 @@ function Retention({
|
||||
disabled={isCloudUserVal}
|
||||
onChange={(e): void => onChangeHandler(e, setSelectedValue)}
|
||||
style={{ width: 75 }}
|
||||
data-testid="retention-field-input"
|
||||
/>
|
||||
<Select
|
||||
value={selectedTimeUnit}
|
||||
onChange={currentSelectedOption}
|
||||
disabled={isCloudUserVal}
|
||||
style={{ width: 100 }}
|
||||
data-testid="retention-field-dropdown"
|
||||
>
|
||||
{menuItems}
|
||||
</Select>
|
||||
|
||||
@@ -60,6 +60,7 @@ function StatusMessage({
|
||||
style={{
|
||||
color: messageColor,
|
||||
}}
|
||||
data-testid="status-message"
|
||||
>
|
||||
{statusMessage}
|
||||
</Col>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Typography } from 'antd';
|
||||
import getDisks from 'api/disks/getDisks';
|
||||
import getRetentionPeriodApi from 'api/settings/getRetention';
|
||||
import Spinner from 'components/Spinner';
|
||||
import GeneralSettingsContainer from 'container/GeneralSettings/GeneralSettings';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQueries } from 'react-query';
|
||||
import { useSelector } from 'react-redux';
|
||||
@@ -11,8 +12,6 @@ import { TTTLType } from 'types/api/settings/common';
|
||||
import { PayloadProps as GetRetentionPeriodAPIPayloadProps } from 'types/api/settings/getRetention';
|
||||
import AppReducer from 'types/reducer/app';
|
||||
|
||||
import GeneralSettingsContainer from './GeneralSettings';
|
||||
|
||||
type TRetentionAPIReturn<T extends TTTLType> = Promise<
|
||||
SuccessResponse<GetRetentionPeriodAPIPayloadProps<T>> | ErrorResponse
|
||||
>;
|
||||
|
||||
@@ -7,7 +7,7 @@ export default function GeneralSettingsCloud(): JSX.Element {
|
||||
return (
|
||||
<Card className="general-settings-container">
|
||||
<Info size={16} />
|
||||
<Typography.Text>
|
||||
<Typography.Text data-testid="cloud-user-info-card">
|
||||
Please <a href="mailto:cloud-support@signoz.io"> email us </a> or connect
|
||||
with us via intercom support to change the retention period.
|
||||
</Typography.Text>
|
||||
|
||||
@@ -97,4 +97,12 @@ export const handlers = [
|
||||
rest.post('http://localhost/api/v1/invite', (_, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(inviteUser)),
|
||||
),
|
||||
rest.post('http://localhost/api/v1/settings/ttl', (_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
message: 'move ttl has been successfully set up',
|
||||
}),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
180
frontend/src/pages/Settings/__tests__/GeneralSettings.test.tsx
Normal file
180
frontend/src/pages/Settings/__tests__/GeneralSettings.test.tsx
Normal file
@@ -0,0 +1,180 @@
|
||||
/* eslint-disable sonarjs/no-duplicate-string */
|
||||
import GeneralSettingsContainer from 'container/GeneralSettings/GeneralSettings';
|
||||
import {
|
||||
act,
|
||||
fireEvent,
|
||||
render,
|
||||
screen,
|
||||
waitFor,
|
||||
within,
|
||||
} from 'tests/test-utils';
|
||||
|
||||
import { generalSettingsProps } from './mock';
|
||||
|
||||
const tooltipText = /More details on how to set retention period/;
|
||||
|
||||
const types = [
|
||||
{
|
||||
testId: 'metrics-card',
|
||||
header: 'Metrics',
|
||||
modalTestId: 'metrics-modal',
|
||||
},
|
||||
{
|
||||
testId: 'traces-card',
|
||||
header: 'Traces',
|
||||
modalTestId: 'traces-modal',
|
||||
},
|
||||
{
|
||||
testId: 'logs-card',
|
||||
header: 'Logs',
|
||||
modalTestId: 'logs-modal',
|
||||
},
|
||||
];
|
||||
|
||||
describe('General Settings Page', () => {
|
||||
beforeEach(() => {
|
||||
render(
|
||||
<GeneralSettingsContainer
|
||||
metricsTtlValuesPayload={generalSettingsProps.metricsTtlValuesPayload}
|
||||
tracesTtlValuesPayload={generalSettingsProps.tracesTtlValuesPayload}
|
||||
logsTtlValuesPayload={generalSettingsProps.logsTtlValuesPayload}
|
||||
getAvailableDiskPayload={generalSettingsProps.getAvailableDiskPayload}
|
||||
metricsTtlValuesRefetch={generalSettingsProps.metricsTtlValuesRefetch}
|
||||
tracesTtlValuesRefetch={generalSettingsProps.tracesTtlValuesRefetch}
|
||||
logsTtlValuesRefetch={generalSettingsProps.logsTtlValuesRefetch}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
it('should properly display the help icon', async () => {
|
||||
const helpIcon = screen.getByLabelText('question-circle');
|
||||
|
||||
fireEvent.mouseOver(helpIcon);
|
||||
|
||||
await waitFor(() => {
|
||||
const tooltip = screen.getByText(tooltipText);
|
||||
expect(tooltip).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
types.forEach(({ testId, header, modalTestId }) => {
|
||||
describe(`${header} Card`, () => {
|
||||
it(`should be able to find "${header}" as the header `, () => {
|
||||
expect(
|
||||
screen.getByRole('heading', {
|
||||
name: header,
|
||||
}),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
it(`should check if ${header} body is properly displayed`, () => {
|
||||
const sectionCard = screen.getByTestId(testId);
|
||||
|
||||
const retentionFieldLabel = within(sectionCard).getByTestId(
|
||||
'retention-field-label',
|
||||
);
|
||||
expect(retentionFieldLabel).toBeInTheDocument();
|
||||
|
||||
const retentionFieldInput = within(sectionCard).getByTestId(
|
||||
'retention-field-input',
|
||||
);
|
||||
expect(retentionFieldInput).toBeInTheDocument();
|
||||
|
||||
const retentionFieldDropdown = within(sectionCard).getByTestId(
|
||||
'retention-field-dropdown',
|
||||
);
|
||||
expect(retentionFieldDropdown).toBeInTheDocument();
|
||||
const retentionSubmitButton = within(sectionCard).getByTestId(
|
||||
'retention-submit-button',
|
||||
);
|
||||
expect(retentionSubmitButton).toBeInTheDocument();
|
||||
});
|
||||
it('Should check if save button is disabled by default', () => {
|
||||
const sectionCard = screen.getByTestId(testId);
|
||||
const retentionSubmitButton = within(sectionCard).getByTestId(
|
||||
'retention-submit-button',
|
||||
);
|
||||
expect(retentionSubmitButton).toBeDisabled();
|
||||
});
|
||||
it('Should check if changing the value of the textbox enables the save button ', () => {
|
||||
const sectionCard = screen.getByTestId(testId);
|
||||
const retentionFieldInput = within(sectionCard).getByTestId(
|
||||
'retention-field-input',
|
||||
);
|
||||
|
||||
const retentionSubmitButton = within(sectionCard).getByTestId(
|
||||
'retention-submit-button',
|
||||
);
|
||||
expect(retentionSubmitButton).toBeDisabled();
|
||||
act(() => {
|
||||
fireEvent.change(retentionFieldInput, { target: { value: '2' } });
|
||||
});
|
||||
expect(retentionSubmitButton).toBeEnabled();
|
||||
});
|
||||
it('Should check if "retention_null_value_error" is displayed if the value is not set ', async () => {
|
||||
const sectionCard = screen.getByTestId(testId);
|
||||
const retentionFieldInput = within(sectionCard).getByTestId(
|
||||
'retention-field-input',
|
||||
);
|
||||
|
||||
act(() => {
|
||||
fireEvent.change(retentionFieldInput, { target: { value: 0 } });
|
||||
});
|
||||
|
||||
expect(
|
||||
await screen.findByText('retention_null_value_error'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
it('should display the modal when a value is provided and save is clicked', async () => {
|
||||
const sectionCard = screen.getByTestId(testId);
|
||||
|
||||
const retentionFieldInput = within(sectionCard).getByTestId(
|
||||
'retention-field-input',
|
||||
);
|
||||
|
||||
const retentionSubmitButton = within(sectionCard).getByTestId(
|
||||
'retention-submit-button',
|
||||
);
|
||||
act(() => {
|
||||
fireEvent.change(retentionFieldInput, { target: { value: 1 } });
|
||||
fireEvent.click(retentionSubmitButton);
|
||||
});
|
||||
|
||||
const sectionModal = screen.getByTestId(modalTestId);
|
||||
|
||||
expect(
|
||||
await within(sectionModal).findByText('retention_confirmation'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe(`${header} Modal`, () => {
|
||||
let sectionModal: HTMLElement;
|
||||
beforeEach(() => {
|
||||
const sectionCard = screen.getByTestId(testId);
|
||||
|
||||
const retentionFieldInput = within(sectionCard).getByTestId(
|
||||
'retention-field-input',
|
||||
);
|
||||
|
||||
const retentionSubmitButton = within(sectionCard).getByTestId(
|
||||
'retention-submit-button',
|
||||
);
|
||||
act(() => {
|
||||
fireEvent.change(retentionFieldInput, { target: { value: 1 } });
|
||||
fireEvent.click(retentionSubmitButton);
|
||||
});
|
||||
|
||||
sectionModal = screen.getByTestId(modalTestId);
|
||||
});
|
||||
|
||||
it('Should check if the modal is properly displayed', async () => {
|
||||
expect(
|
||||
within(sectionModal).getByText('retention_confirmation'),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
within(sectionModal).getByText('retention_confirmation_description'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
import GeneralSettingsContainer from 'container/GeneralSettings/GeneralSettings';
|
||||
import { render, screen, within } from 'tests/test-utils';
|
||||
|
||||
import { generalSettingsProps } from './mock';
|
||||
|
||||
jest.mock('utils/app', () => {
|
||||
const app = jest.requireActual('utils/app');
|
||||
return {
|
||||
...app,
|
||||
isCloudUser: jest.fn(() => true),
|
||||
};
|
||||
});
|
||||
|
||||
const types = [
|
||||
{
|
||||
testId: 'metrics-card',
|
||||
header: 'Metrics',
|
||||
},
|
||||
{
|
||||
testId: 'traces-card',
|
||||
header: 'Traces',
|
||||
},
|
||||
{
|
||||
testId: 'logs-card',
|
||||
header: 'Logs',
|
||||
},
|
||||
];
|
||||
|
||||
describe('Cloud User General Settings', () => {
|
||||
beforeEach(() => {
|
||||
render(
|
||||
<GeneralSettingsContainer
|
||||
metricsTtlValuesPayload={generalSettingsProps.metricsTtlValuesPayload}
|
||||
tracesTtlValuesPayload={generalSettingsProps.tracesTtlValuesPayload}
|
||||
logsTtlValuesPayload={generalSettingsProps.logsTtlValuesPayload}
|
||||
getAvailableDiskPayload={generalSettingsProps.getAvailableDiskPayload}
|
||||
metricsTtlValuesRefetch={generalSettingsProps.metricsTtlValuesRefetch}
|
||||
tracesTtlValuesRefetch={generalSettingsProps.tracesTtlValuesRefetch}
|
||||
logsTtlValuesRefetch={generalSettingsProps.logsTtlValuesRefetch}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
it('should display the cloud user info card', () => {
|
||||
const cloudUserCard = screen.getByTestId('cloud-user-info-card');
|
||||
expect(cloudUserCard).toBeInTheDocument();
|
||||
});
|
||||
types.forEach(({ testId, header }) => {
|
||||
it(`should check if value textbox and duration dropdown are disabled in the body of ${header}`, () => {
|
||||
const sectionCard = screen.getByTestId(testId);
|
||||
|
||||
const retentionFieldInput = within(sectionCard).getByTestId(
|
||||
'retention-field-input',
|
||||
);
|
||||
expect(retentionFieldInput).toBeDisabled();
|
||||
|
||||
const retentionFieldDropdown = within(sectionCard).getByTestId(
|
||||
'retention-field-dropdown',
|
||||
);
|
||||
expect(retentionFieldDropdown).toHaveClass('ant-select-disabled');
|
||||
});
|
||||
});
|
||||
});
|
||||
63
frontend/src/pages/Settings/__tests__/mock.ts
Normal file
63
frontend/src/pages/Settings/__tests__/mock.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
/* eslint-disable sonarjs/no-duplicate-string */
|
||||
import { QueryObserverResult } from 'react-query';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import {
|
||||
PayloadPropsLogs,
|
||||
PayloadPropsMetrics,
|
||||
PayloadPropsTraces,
|
||||
TStatus,
|
||||
} from 'types/api/settings/getRetention';
|
||||
|
||||
export const generalSettingsProps = {
|
||||
metricsTtlValuesPayload: {
|
||||
metrics_ttl_duration_hrs: 720,
|
||||
metrics_move_ttl_duration_hrs: -1,
|
||||
expected_metrics_ttl_duration_hrs: 720,
|
||||
expected_metrics_move_ttl_duration_hrs: -1,
|
||||
status: 'success' as TStatus,
|
||||
},
|
||||
tracesTtlValuesPayload: {
|
||||
traces_ttl_duration_hrs: 360,
|
||||
traces_move_ttl_duration_hrs: -1,
|
||||
expected_traces_ttl_duration_hrs: 24,
|
||||
expected_traces_move_ttl_duration_hrs: -1,
|
||||
status: '' as TStatus,
|
||||
},
|
||||
logsTtlValuesPayload: {
|
||||
logs_ttl_duration_hrs: 360,
|
||||
logs_move_ttl_duration_hrs: -1,
|
||||
expected_logs_ttl_duration_hrs: 360,
|
||||
expected_logs_move_ttl_duration_hrs: -1,
|
||||
status: 'success' as TStatus,
|
||||
},
|
||||
getAvailableDiskPayload: [
|
||||
{
|
||||
name: 'default',
|
||||
type: 'local',
|
||||
},
|
||||
],
|
||||
metricsTtlValuesRefetch(): Promise<
|
||||
QueryObserverResult<
|
||||
ErrorResponse | SuccessResponse<PayloadPropsMetrics, unknown>,
|
||||
unknown
|
||||
>
|
||||
> {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
tracesTtlValuesRefetch(): Promise<
|
||||
QueryObserverResult<
|
||||
ErrorResponse | SuccessResponse<PayloadPropsTraces, unknown>,
|
||||
unknown
|
||||
>
|
||||
> {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
logsTtlValuesRefetch(): Promise<
|
||||
QueryObserverResult<
|
||||
ErrorResponse | SuccessResponse<PayloadPropsLogs, unknown>,
|
||||
unknown
|
||||
>
|
||||
> {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user