- Fixes No originally selected custom parameters in topic's edit tab #1534 - Adds test case for CustomParams to verify fix - Updates CustomParamsField to use predefined value - Renames INDEX_PREFIX to TOPIC_CUSTOM_PARAMS_PREFIX and moves it to constants file - Removes unused configs from Topic/Edit component - Rewrites DangerZone styled's - Rewrites DangerZone tests - Adds margin to DangerZone to match TopicForm width - Adds simple Topic/Edit test - Changes sonar-project.properties file's sonar.exclusions to correctly ignore paths Signed-off-by: Roman Zabaluev <rzabaluev@provectus.com> Co-authored-by: Roman Zabaluev <rzabaluev@provectus.com>
This commit is contained in:
parent
cf45ee0198
commit
ced74ac550
18 changed files with 789 additions and 499 deletions
2
.github/workflows/backend.yml
vendored
2
.github/workflows/backend.yml
vendored
|
@ -19,7 +19,7 @@ jobs:
|
||||||
- name: compose app
|
- name: compose app
|
||||||
id: step_five
|
id: step_five
|
||||||
run: |
|
run: |
|
||||||
docker-compose -f ./docker/kafka-ui.yaml up -d
|
docker-compose -f ./documentation/compose/kafka-ui.yaml up -d
|
||||||
- name: Set up JDK 1.13
|
- name: Set up JDK 1.13
|
||||||
uses: actions/setup-java@v1
|
uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
|
|
2
.github/workflows/e2e-checks.yaml
vendored
2
.github/workflows/e2e-checks.yaml
vendored
|
@ -39,7 +39,7 @@ jobs:
|
||||||
id: compose_app
|
id: compose_app
|
||||||
# use the following command until #819 will be fixed
|
# use the following command until #819 will be fixed
|
||||||
run: |
|
run: |
|
||||||
docker-compose -f ./docker/kafka-ui-connectors.yaml up -d
|
docker-compose -f ./documentation/compose/kafka-ui-connectors.yaml up -d
|
||||||
- name: e2e run
|
- name: e2e run
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
|
||||||
|
|
|
@ -2,7 +2,7 @@ sonar.projectKey=provectus_kafka-ui_frontend
|
||||||
sonar.organization=provectus
|
sonar.organization=provectus
|
||||||
|
|
||||||
sonar.sources=.
|
sonar.sources=.
|
||||||
sonar.exclusions="**/__test?__/**,src/setupWorker.ts,src/setupTests.ts,**/fixtures.ts,src/lib/testHelpers.tsx"
|
sonar.exclusions=**/__test?__/**,src/setupWorker.ts,src/setupTests.ts,**/fixtures.ts,src/lib/testHelpers.tsx
|
||||||
|
|
||||||
sonar.typescript.lcov.reportPaths=./coverage/lcov.info
|
sonar.typescript.lcov.reportPaths=./coverage/lcov.info
|
||||||
sonar.testExecutionReportPaths=./test-report.xml
|
sonar.testExecutionReportPaths=./test-report.xml
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const DangerZoneWrapperStyled = styled.div`
|
export const Wrapper = styled.div`
|
||||||
margin-top: 16px;
|
margin: 16px;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
border: 1px solid ${({ theme }) => theme.dangerZone.borderColor};
|
border: 1px solid ${({ theme }) => theme.dangerZone.borderColor};
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
& > div {
|
& > div {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -15,13 +14,13 @@ export const DangerZoneWrapperStyled = styled.div`
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const DangerZoneTitleStyled = styled.h1`
|
export const Title = styled.h1`
|
||||||
color: ${({ theme }) => theme.dangerZone.color};
|
color: ${({ theme }) => theme.dangerZone.color};
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
padding-bottom: 16px;
|
padding-bottom: 16px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const DagerZoneFormStyled = styled.form`
|
export const Form = styled.form`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
|
|
@ -7,11 +7,7 @@ import { InputLabel } from 'components/common/Input/InputLabel.styled';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
|
|
||||||
import {
|
import * as S from './DangerZone.styled';
|
||||||
DagerZoneFormStyled,
|
|
||||||
DangerZoneTitleStyled,
|
|
||||||
DangerZoneWrapperStyled,
|
|
||||||
} from './DangerZone.styled';
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
clusterName: string;
|
clusterName: string;
|
||||||
|
@ -109,12 +105,13 @@ const DangerZone: React.FC<Props> = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<DangerZoneWrapperStyled>
|
<S.Wrapper>
|
||||||
<DangerZoneTitleStyled>Danger Zone</DangerZoneTitleStyled>
|
<S.Title>Danger Zone</S.Title>
|
||||||
<div>
|
<div>
|
||||||
<FormProvider {...partitionsMethods}>
|
<FormProvider {...partitionsMethods}>
|
||||||
<DagerZoneFormStyled
|
<S.Form
|
||||||
onSubmit={partitionsMethods.handleSubmit(validatePartitions)}
|
onSubmit={partitionsMethods.handleSubmit(validatePartitions)}
|
||||||
|
aria-label="Edit number of partitions"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<InputLabel htmlFor="partitions">
|
<InputLabel htmlFor="partitions">
|
||||||
|
@ -137,12 +134,11 @@ const DangerZone: React.FC<Props> = ({
|
||||||
buttonSize="M"
|
buttonSize="M"
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!partitionsMethods.formState.isDirty}
|
disabled={!partitionsMethods.formState.isDirty}
|
||||||
data-testid="partitionsSubmit"
|
|
||||||
>
|
>
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</DagerZoneFormStyled>
|
</S.Form>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
<FormError>
|
<FormError>
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
|
@ -160,10 +156,11 @@ const DangerZone: React.FC<Props> = ({
|
||||||
</ConfirmationModal>
|
</ConfirmationModal>
|
||||||
|
|
||||||
<FormProvider {...replicationFactorMethods}>
|
<FormProvider {...replicationFactorMethods}>
|
||||||
<DagerZoneFormStyled
|
<S.Form
|
||||||
onSubmit={replicationFactorMethods.handleSubmit(
|
onSubmit={replicationFactorMethods.handleSubmit(
|
||||||
validateReplicationFactor
|
validateReplicationFactor
|
||||||
)}
|
)}
|
||||||
|
aria-label="Edit replication factor"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<InputLabel htmlFor="replicationFactor">
|
<InputLabel htmlFor="replicationFactor">
|
||||||
|
@ -185,12 +182,11 @@ const DangerZone: React.FC<Props> = ({
|
||||||
buttonSize="M"
|
buttonSize="M"
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!replicationFactorMethods.formState.isDirty}
|
disabled={!replicationFactorMethods.formState.isDirty}
|
||||||
data-testid="replicationFactorSubmit"
|
|
||||||
>
|
>
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</DagerZoneFormStyled>
|
</S.Form>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
|
|
||||||
<FormError>
|
<FormError>
|
||||||
|
@ -207,7 +203,7 @@ const DangerZone: React.FC<Props> = ({
|
||||||
Are you sure you want to update the replication factor?
|
Are you sure you want to update the replication factor?
|
||||||
</ConfirmationModal>
|
</ConfirmationModal>
|
||||||
</div>
|
</div>
|
||||||
</DangerZoneWrapperStyled>
|
</S.Wrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,21 +7,19 @@ import {
|
||||||
TopicWithDetailedInfo,
|
TopicWithDetailedInfo,
|
||||||
TopicFormData,
|
TopicFormData,
|
||||||
} from 'redux/interfaces';
|
} from 'redux/interfaces';
|
||||||
import { TopicConfig } from 'generated-sources';
|
|
||||||
import { useForm, FormProvider } from 'react-hook-form';
|
import { useForm, FormProvider } from 'react-hook-form';
|
||||||
import { camelCase } from 'lodash';
|
|
||||||
import TopicForm from 'components/Topics/shared/Form/TopicForm';
|
import TopicForm from 'components/Topics/shared/Form/TopicForm';
|
||||||
import { clusterTopicPath } from 'lib/paths';
|
import { clusterTopicPath } from 'lib/paths';
|
||||||
import { useHistory } from 'react-router';
|
import { useHistory } from 'react-router';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
import { topicFormValidationSchema } from 'lib/yupExtended';
|
import { topicFormValidationSchema } from 'lib/yupExtended';
|
||||||
import { TOPIC_CUSTOM_PARAMS } from 'lib/constants';
|
import { TOPIC_CUSTOM_PARAMS_PREFIX, TOPIC_CUSTOM_PARAMS } from 'lib/constants';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import PageHeading from 'components/common/PageHeading/PageHeading';
|
import PageHeading from 'components/common/PageHeading/PageHeading';
|
||||||
|
|
||||||
import DangerZoneContainer from './DangerZone/DangerZoneContainer';
|
import DangerZoneContainer from './DangerZone/DangerZoneContainer';
|
||||||
|
|
||||||
interface Props {
|
export interface Props {
|
||||||
clusterName: ClusterName;
|
clusterName: ClusterName;
|
||||||
topicName: TopicName;
|
topicName: TopicName;
|
||||||
topic?: TopicWithDetailedInfo;
|
topic?: TopicWithDetailedInfo;
|
||||||
|
@ -64,27 +62,18 @@ const topicParams = (topic: TopicWithDetailedInfo | undefined) => {
|
||||||
|
|
||||||
const { name, replicationFactor } = topic;
|
const { name, replicationFactor } = topic;
|
||||||
|
|
||||||
const configs = topic.config?.reduce(
|
|
||||||
(result: { [key: string]: TopicConfig['value'] }, param) => ({
|
|
||||||
...result,
|
|
||||||
[camelCase(param.name)]: param.value || param.defaultValue,
|
|
||||||
}),
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...DEFAULTS,
|
...DEFAULTS,
|
||||||
name,
|
name,
|
||||||
partitions: topic.partitionCount || DEFAULTS.partitions,
|
partitions: topic.partitionCount || DEFAULTS.partitions,
|
||||||
replicationFactor,
|
replicationFactor,
|
||||||
customParams: topic.config
|
[TOPIC_CUSTOM_PARAMS_PREFIX]: topic.config
|
||||||
?.filter(
|
?.filter(
|
||||||
(el) =>
|
(el) =>
|
||||||
el.value !== el.defaultValue &&
|
el.value !== el.defaultValue &&
|
||||||
Object.keys(TOPIC_CUSTOM_PARAMS).includes(el.name)
|
Object.keys(TOPIC_CUSTOM_PARAMS).includes(el.name)
|
||||||
)
|
)
|
||||||
.map((el) => ({ name: el.name, value: el.value })),
|
.map((el) => ({ name: el.name, value: el.value })),
|
||||||
...configs,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,8 +88,10 @@ const Edit: React.FC<Props> = ({
|
||||||
fetchTopicConfig,
|
fetchTopicConfig,
|
||||||
updateTopic,
|
updateTopic,
|
||||||
}) => {
|
}) => {
|
||||||
const defaultValues = topicParams(topic);
|
const defaultValues = React.useMemo(
|
||||||
|
() => topicParams(topic),
|
||||||
|
[topicParams, topic]
|
||||||
|
);
|
||||||
const methods = useForm<TopicFormData>({
|
const methods = useForm<TopicFormData>({
|
||||||
defaultValues,
|
defaultValues,
|
||||||
resolver: yupResolver(topicFormValidationSchema),
|
resolver: yupResolver(topicFormValidationSchema),
|
||||||
|
@ -147,17 +138,14 @@ const Edit: React.FC<Props> = ({
|
||||||
<PageHeading text={`Edit ${topicName}`} />
|
<PageHeading text={`Edit ${topicName}`} />
|
||||||
<EditWrapperStyled>
|
<EditWrapperStyled>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<FormProvider {...methods}>
|
||||||
<FormProvider {...methods}>
|
<TopicForm
|
||||||
<TopicForm
|
topicName={topicName}
|
||||||
topicName={topicName}
|
isSubmitting={isSubmitting}
|
||||||
config={config}
|
isEditing
|
||||||
isSubmitting={isSubmitting}
|
onSubmit={methods.handleSubmit(onSubmit)}
|
||||||
isEditing
|
/>
|
||||||
onSubmit={methods.handleSubmit(onSubmit)}
|
</FormProvider>
|
||||||
/>
|
|
||||||
</FormProvider>
|
|
||||||
</div>
|
|
||||||
{topic && (
|
{topic && (
|
||||||
<DangerZoneContainer
|
<DangerZoneContainer
|
||||||
defaultPartitions={defaultValues.partitions}
|
defaultPartitions={defaultValues.partitions}
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
import React from 'react';
|
||||||
|
import DangerZone, {
|
||||||
|
Props,
|
||||||
|
} from 'components/Topics/Topic/Edit/DangerZone/DangerZone';
|
||||||
|
import { screen, waitFor, within } from '@testing-library/react';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { render } from 'lib/testHelpers';
|
||||||
|
|
||||||
|
import { topicName, clusterName } from './fixtures';
|
||||||
|
|
||||||
|
const renderComponent = (props?: Partial<Props>) =>
|
||||||
|
render(
|
||||||
|
<DangerZone
|
||||||
|
clusterName={clusterName}
|
||||||
|
topicName={topicName}
|
||||||
|
defaultPartitions={3}
|
||||||
|
defaultReplicationFactor={3}
|
||||||
|
partitionsCountIncreased={false}
|
||||||
|
replicationFactorUpdated={false}
|
||||||
|
updateTopicPartitionsCount={jest.fn()}
|
||||||
|
updateTopicReplicationFactor={jest.fn()}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const clickOnDialogSubmitButton = () => {
|
||||||
|
userEvent.click(
|
||||||
|
within(screen.getByRole('dialog')).getByRole('button', {
|
||||||
|
name: 'Submit',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
describe('DangerZone', () => {
|
||||||
|
it('renders', () => {
|
||||||
|
renderComponent();
|
||||||
|
|
||||||
|
const numberOfPartitionsEditForm = screen.getByRole('form', {
|
||||||
|
name: 'Edit number of partitions',
|
||||||
|
});
|
||||||
|
expect(numberOfPartitionsEditForm).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
within(numberOfPartitionsEditForm).getByRole('spinbutton', {
|
||||||
|
name: 'Number of partitions *',
|
||||||
|
})
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
within(numberOfPartitionsEditForm).getByRole('button', { name: 'Submit' })
|
||||||
|
).toBeInTheDocument();
|
||||||
|
|
||||||
|
const replicationFactorEditForm = screen.getByRole('form', {
|
||||||
|
name: 'Edit replication factor',
|
||||||
|
});
|
||||||
|
expect(replicationFactorEditForm).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
within(replicationFactorEditForm).getByRole('spinbutton', {
|
||||||
|
name: 'Replication Factor *',
|
||||||
|
})
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
within(replicationFactorEditForm).getByRole('button', { name: 'Submit' })
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls updateTopicPartitionsCount', async () => {
|
||||||
|
const mockUpdateTopicPartitionsCount = jest.fn();
|
||||||
|
renderComponent({
|
||||||
|
updateTopicPartitionsCount: mockUpdateTopicPartitionsCount,
|
||||||
|
});
|
||||||
|
const numberOfPartitionsEditForm = screen.getByRole('form', {
|
||||||
|
name: 'Edit number of partitions',
|
||||||
|
});
|
||||||
|
|
||||||
|
userEvent.type(
|
||||||
|
within(numberOfPartitionsEditForm).getByRole('spinbutton'),
|
||||||
|
'4'
|
||||||
|
);
|
||||||
|
userEvent.click(within(numberOfPartitionsEditForm).getByRole('button'));
|
||||||
|
|
||||||
|
await waitFor(() => expect(screen.getByRole('dialog')).toBeInTheDocument());
|
||||||
|
await waitFor(() => clickOnDialogSubmitButton());
|
||||||
|
|
||||||
|
expect(mockUpdateTopicPartitionsCount).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls updateTopicReplicationFactor', async () => {
|
||||||
|
const mockUpdateTopicReplicationFactor = jest.fn();
|
||||||
|
renderComponent({
|
||||||
|
updateTopicReplicationFactor: mockUpdateTopicReplicationFactor,
|
||||||
|
});
|
||||||
|
|
||||||
|
const replicationFactorEditForm = screen.getByRole('form', {
|
||||||
|
name: 'Edit replication factor',
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
within(replicationFactorEditForm).getByRole('spinbutton', {
|
||||||
|
name: 'Replication Factor *',
|
||||||
|
})
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
within(replicationFactorEditForm).getByRole('button', { name: 'Submit' })
|
||||||
|
).toBeInTheDocument();
|
||||||
|
|
||||||
|
userEvent.type(
|
||||||
|
within(replicationFactorEditForm).getByRole('spinbutton'),
|
||||||
|
'4'
|
||||||
|
);
|
||||||
|
userEvent.click(within(replicationFactorEditForm).getByRole('button'));
|
||||||
|
|
||||||
|
await waitFor(() => expect(screen.getByRole('dialog')).toBeInTheDocument());
|
||||||
|
await waitFor(() => clickOnDialogSubmitButton());
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(mockUpdateTopicReplicationFactor).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,34 @@
|
||||||
|
import React from 'react';
|
||||||
|
import Edit, { Props } from 'components/Topics/Topic/Edit/Edit';
|
||||||
|
import { screen } from '@testing-library/react';
|
||||||
|
import { render } from 'lib/testHelpers';
|
||||||
|
|
||||||
|
import { topicName, clusterName, topicWithInfo } from './fixtures';
|
||||||
|
|
||||||
|
const renderComponent = (props?: Partial<Props>) =>
|
||||||
|
render(
|
||||||
|
<Edit
|
||||||
|
clusterName={clusterName}
|
||||||
|
topicName={topicName}
|
||||||
|
topic={topicWithInfo}
|
||||||
|
isFetched
|
||||||
|
isTopicUpdated={false}
|
||||||
|
fetchTopicConfig={jest.fn()}
|
||||||
|
updateTopic={jest.fn()}
|
||||||
|
updateTopicPartitionsCount={jest.fn()}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('DangerZone', () => {
|
||||||
|
it('renders', () => {
|
||||||
|
renderComponent();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.getByRole('heading', { name: `Edit ${topicName}` })
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByRole('heading', { name: `Danger Zone` })
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,553 @@
|
||||||
|
import { CleanUpPolicy, ConfigSource, TopicConfig } from 'generated-sources';
|
||||||
|
import { TopicWithDetailedInfo } from 'redux/interfaces/topic';
|
||||||
|
|
||||||
|
export const clusterName = 'testCluster';
|
||||||
|
export const topicName = 'testTopic';
|
||||||
|
|
||||||
|
export const config: TopicConfig[] = [
|
||||||
|
{
|
||||||
|
name: 'compression.type',
|
||||||
|
value: 'producer',
|
||||||
|
defaultValue: 'producer',
|
||||||
|
source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'compression.type',
|
||||||
|
value: 'producer',
|
||||||
|
source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'compression.type',
|
||||||
|
value: 'producer',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'confluent.value.schema.validation',
|
||||||
|
value: 'false',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'leader.replication.throttled.replicas',
|
||||||
|
value: '',
|
||||||
|
defaultValue: '',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'confluent.key.subject.name.strategy',
|
||||||
|
value: 'io.confluent.kafka.serializers.subject.TopicNameStrategy',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'message.downconversion.enable',
|
||||||
|
value: 'true',
|
||||||
|
defaultValue: 'true',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'log.message.downconversion.enable',
|
||||||
|
value: 'true',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'min.insync.replicas',
|
||||||
|
value: '1',
|
||||||
|
defaultValue: '1',
|
||||||
|
source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'min.insync.replicas',
|
||||||
|
value: '1',
|
||||||
|
source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'min.insync.replicas',
|
||||||
|
value: '1',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'segment.jitter.ms',
|
||||||
|
value: '0',
|
||||||
|
defaultValue: '0',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'cleanup.policy',
|
||||||
|
value: 'delete',
|
||||||
|
defaultValue: 'delete',
|
||||||
|
source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'cleanup.policy',
|
||||||
|
value: 'delete',
|
||||||
|
source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'log.cleanup.policy',
|
||||||
|
value: 'delete',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'flush.ms',
|
||||||
|
value: '9223372036854775807',
|
||||||
|
defaultValue: '9223372036854775807',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'confluent.tier.local.hotset.ms',
|
||||||
|
value: '86400000',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'confluent.tier.local.hotset.ms',
|
||||||
|
value: '86400000',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'follower.replication.throttled.replicas',
|
||||||
|
value: '',
|
||||||
|
defaultValue: '',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'confluent.tier.local.hotset.bytes',
|
||||||
|
value: '-1',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'confluent.tier.local.hotset.bytes',
|
||||||
|
value: '-1',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'confluent.value.subject.name.strategy',
|
||||||
|
value: 'io.confluent.kafka.serializers.subject.TopicNameStrategy',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'segment.bytes',
|
||||||
|
value: '1073741824',
|
||||||
|
defaultValue: '1073741824',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'log.segment.bytes',
|
||||||
|
value: '1073741824',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'retention.ms',
|
||||||
|
value: '604800000',
|
||||||
|
defaultValue: '604800000',
|
||||||
|
source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'retention.ms',
|
||||||
|
value: '604800000',
|
||||||
|
source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'flush.messages',
|
||||||
|
value: '9223372036854775807',
|
||||||
|
defaultValue: '9223372036854775807',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'log.flush.interval.messages',
|
||||||
|
value: '9223372036854775807',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'confluent.tier.enable',
|
||||||
|
value: 'false',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'confluent.tier.enable',
|
||||||
|
value: 'false',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'confluent.tier.segment.hotset.roll.min.bytes',
|
||||||
|
value: '104857600',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'confluent.tier.segment.hotset.roll.min.bytes',
|
||||||
|
value: '104857600',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'confluent.segment.speculative.prefetch.enable',
|
||||||
|
value: 'false',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'confluent.segment.speculative.prefetch.enable',
|
||||||
|
value: 'false',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'message.format.version',
|
||||||
|
value: '2.7-IV2',
|
||||||
|
defaultValue: '2.7-IV2',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'log.message.format.version',
|
||||||
|
value: '2.7-IV2',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'max.compaction.lag.ms',
|
||||||
|
value: '9223372036854775807',
|
||||||
|
defaultValue: '9223372036854775807',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'log.cleaner.max.compaction.lag.ms',
|
||||||
|
value: '9223372036854775807',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'file.delete.delay.ms',
|
||||||
|
value: '60000',
|
||||||
|
defaultValue: '60000',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'log.segment.delete.delay.ms',
|
||||||
|
value: '60000',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'max.message.bytes',
|
||||||
|
value: '1000012',
|
||||||
|
defaultValue: '1000012',
|
||||||
|
source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'max.message.bytes',
|
||||||
|
value: '1000012',
|
||||||
|
source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'message.max.bytes',
|
||||||
|
value: '1048588',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'min.compaction.lag.ms',
|
||||||
|
value: '0',
|
||||||
|
defaultValue: '0',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'log.cleaner.min.compaction.lag.ms',
|
||||||
|
value: '0',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'message.timestamp.type',
|
||||||
|
value: 'CreateTime',
|
||||||
|
defaultValue: 'CreateTime',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'log.message.timestamp.type',
|
||||||
|
value: 'CreateTime',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'preallocate',
|
||||||
|
value: 'false',
|
||||||
|
defaultValue: 'false',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'log.preallocate',
|
||||||
|
value: 'false',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'confluent.placement.constraints',
|
||||||
|
value: '',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'min.cleanable.dirty.ratio',
|
||||||
|
value: '0.5',
|
||||||
|
defaultValue: '0.5',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'log.cleaner.min.cleanable.ratio',
|
||||||
|
value: '0.5',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'index.interval.bytes',
|
||||||
|
value: '4096',
|
||||||
|
defaultValue: '4096',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'log.index.interval.bytes',
|
||||||
|
value: '4096',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'unclean.leader.election.enable',
|
||||||
|
value: 'false',
|
||||||
|
defaultValue: 'false',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'unclean.leader.election.enable',
|
||||||
|
value: 'false',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'retention.bytes',
|
||||||
|
value: '-1',
|
||||||
|
defaultValue: '-1',
|
||||||
|
source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'retention.bytes',
|
||||||
|
value: '-1',
|
||||||
|
source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'log.retention.bytes',
|
||||||
|
value: '-1',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'delete.retention.ms',
|
||||||
|
value: '86400001',
|
||||||
|
defaultValue: '86400000',
|
||||||
|
source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'delete.retention.ms',
|
||||||
|
value: '86400001',
|
||||||
|
source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'log.cleaner.delete.retention.ms',
|
||||||
|
value: '86400000',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'confluent.prefer.tier.fetch.ms',
|
||||||
|
value: '-1',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'confluent.prefer.tier.fetch.ms',
|
||||||
|
value: '-1',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'confluent.key.schema.validation',
|
||||||
|
value: 'false',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'segment.ms',
|
||||||
|
value: '604800000',
|
||||||
|
defaultValue: '604800000',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'message.timestamp.difference.max.ms',
|
||||||
|
value: '9223372036854775807',
|
||||||
|
defaultValue: '9223372036854775807',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'log.message.timestamp.difference.max.ms',
|
||||||
|
value: '9223372036854775807',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'segment.index.bytes',
|
||||||
|
value: '10485760',
|
||||||
|
defaultValue: '10485760',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
isSensitive: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
synonyms: [
|
||||||
|
{
|
||||||
|
name: 'log.index.size.max.bytes',
|
||||||
|
value: '10485760',
|
||||||
|
source: ConfigSource.DEFAULT_CONFIG,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const partitions = [
|
||||||
|
{
|
||||||
|
partition: 0,
|
||||||
|
leader: 2,
|
||||||
|
replicas: [
|
||||||
|
{
|
||||||
|
broker: 2,
|
||||||
|
leader: false,
|
||||||
|
inSync: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
offsetMax: 0,
|
||||||
|
offsetMin: 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const topicWithInfo: TopicWithDetailedInfo = {
|
||||||
|
name: topicName,
|
||||||
|
internal: false,
|
||||||
|
partitionCount: 1,
|
||||||
|
replicationFactor: 1,
|
||||||
|
replicas: 1,
|
||||||
|
inSyncReplicas: 1,
|
||||||
|
segmentSize: 0,
|
||||||
|
segmentCount: 1,
|
||||||
|
underReplicatedPartitions: 0,
|
||||||
|
cleanUpPolicy: CleanUpPolicy.DELETE,
|
||||||
|
partitions,
|
||||||
|
config,
|
||||||
|
};
|
|
@ -1,64 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import DangerZone, {
|
|
||||||
Props,
|
|
||||||
} from 'components/Topics/Topic/Edit/DangerZone/DangerZone';
|
|
||||||
import { screen, waitFor } from '@testing-library/react';
|
|
||||||
import userEvent from '@testing-library/user-event';
|
|
||||||
import { render } from 'lib/testHelpers';
|
|
||||||
|
|
||||||
const setupWrapper = (props?: Partial<Props>) => (
|
|
||||||
<DangerZone
|
|
||||||
clusterName="testCluster"
|
|
||||||
topicName="testTopic"
|
|
||||||
defaultPartitions={3}
|
|
||||||
defaultReplicationFactor={3}
|
|
||||||
partitionsCountIncreased={false}
|
|
||||||
replicationFactorUpdated={false}
|
|
||||||
updateTopicPartitionsCount={jest.fn()}
|
|
||||||
updateTopicReplicationFactor={jest.fn()}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
describe('DangerZone', () => {
|
|
||||||
it('is rendered properly', () => {
|
|
||||||
const component = render(setupWrapper());
|
|
||||||
expect(component.baseElement).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('calls updateTopicPartitionsCount', async () => {
|
|
||||||
const mockUpdateTopicPartitionsCount = jest.fn();
|
|
||||||
render(
|
|
||||||
setupWrapper({
|
|
||||||
updateTopicPartitionsCount: mockUpdateTopicPartitionsCount,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
userEvent.type(screen.getByLabelText('Number of partitions *'), '4');
|
|
||||||
userEvent.click(screen.getByTestId('partitionsSubmit'));
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
userEvent.click(screen.getAllByText('Submit')[1]);
|
|
||||||
expect(mockUpdateTopicPartitionsCount).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('calls updateTopicReplicationFactor', async () => {
|
|
||||||
const mockUpdateTopicReplicationFactor = jest.fn();
|
|
||||||
render(
|
|
||||||
setupWrapper({
|
|
||||||
updateTopicReplicationFactor: mockUpdateTopicReplicationFactor,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
userEvent.type(screen.getByLabelText('Replication Factor *'), '4');
|
|
||||||
userEvent.click(screen.getByTestId('replicationFactorSubmit'));
|
|
||||||
await waitFor(() => {
|
|
||||||
userEvent.click(screen.getAllByText('Submit')[2]);
|
|
||||||
});
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(mockUpdateTopicReplicationFactor).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,360 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`DangerZone is rendered properly 1`] = `
|
|
||||||
.c6 {
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -webkit-flex;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-webkit-flex-direction: row;
|
|
||||||
-ms-flex-direction: row;
|
|
||||||
flex-direction: row;
|
|
||||||
-webkit-align-items: center;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
-ms-flex-align: center;
|
|
||||||
align-items: center;
|
|
||||||
-webkit-box-pack: center;
|
|
||||||
-webkit-justify-content: center;
|
|
||||||
-ms-flex-pack: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 0px 12px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
white-space: nowrap;
|
|
||||||
background: #4F4FFF;
|
|
||||||
color: #FFFFFF;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c6:hover:enabled {
|
|
||||||
background: #1717CF;
|
|
||||||
color: #FFFFFF;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c6:active:enabled {
|
|
||||||
background: #1414B8;
|
|
||||||
color: #FFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c6:disabled {
|
|
||||||
opacity: 0.5;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c6 a {
|
|
||||||
color: #FFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c6 i {
|
|
||||||
margin-right: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5 {
|
|
||||||
border: 1px #ABB5BA solid;
|
|
||||||
border-radius: 4px;
|
|
||||||
height: 32px;
|
|
||||||
width: 100%;
|
|
||||||
padding-left: 12px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5::-webkit-input-placeholder {
|
|
||||||
color: #ABB5BA;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5::-moz-placeholder {
|
|
||||||
color: #ABB5BA;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5:-ms-input-placeholder {
|
|
||||||
color: #ABB5BA;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5::placeholder {
|
|
||||||
color: #ABB5BA;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5:hover {
|
|
||||||
border-color: #73848C;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: #454F54;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5:focus::-webkit-input-placeholder {
|
|
||||||
color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5:focus::-moz-placeholder {
|
|
||||||
color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5:focus:-ms-input-placeholder {
|
|
||||||
color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5:focus::placeholder {
|
|
||||||
color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5:disabled {
|
|
||||||
color: #ABB5BA;
|
|
||||||
border-color: #E3E6E8;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5:read-only {
|
|
||||||
color: #171A1C;
|
|
||||||
border: none;
|
|
||||||
background-color: #F1F2F3;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5:-moz-read-only:focus::placeholder {
|
|
||||||
color: #ABB5BA;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c5:read-only:focus::placeholder {
|
|
||||||
color: #ABB5BA;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8 {
|
|
||||||
border: 1px #ABB5BA solid;
|
|
||||||
border-radius: 4px;
|
|
||||||
height: 40px;
|
|
||||||
width: 100%;
|
|
||||||
padding-left: 12px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8::-webkit-input-placeholder {
|
|
||||||
color: #ABB5BA;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8::-moz-placeholder {
|
|
||||||
color: #ABB5BA;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8:-ms-input-placeholder {
|
|
||||||
color: #ABB5BA;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8::placeholder {
|
|
||||||
color: #ABB5BA;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8:hover {
|
|
||||||
border-color: #73848C;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: #454F54;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8:focus::-webkit-input-placeholder {
|
|
||||||
color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8:focus::-moz-placeholder {
|
|
||||||
color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8:focus:-ms-input-placeholder {
|
|
||||||
color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8:focus::placeholder {
|
|
||||||
color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8:disabled {
|
|
||||||
color: #ABB5BA;
|
|
||||||
border-color: #E3E6E8;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8:read-only {
|
|
||||||
color: #171A1C;
|
|
||||||
border: none;
|
|
||||||
background-color: #F1F2F3;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8:-moz-read-only:focus::placeholder {
|
|
||||||
color: #ABB5BA;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c8:read-only:focus::placeholder {
|
|
||||||
color: #ABB5BA;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c7 {
|
|
||||||
color: #E51A1A;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c4 {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c3 {
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 20px;
|
|
||||||
color: #454F54;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c0 {
|
|
||||||
margin-top: 16px;
|
|
||||||
padding: 8px 16px;
|
|
||||||
border: 1px solid #E3E6E8;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c0 > div {
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -webkit-flex;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-webkit-flex-direction: column;
|
|
||||||
-ms-flex-direction: column;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c1 {
|
|
||||||
color: #E51A1A;
|
|
||||||
font-size: 20px;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c2 {
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -webkit-flex;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-webkit-align-items: flex-end;
|
|
||||||
-webkit-box-align: flex-end;
|
|
||||||
-ms-flex-align: flex-end;
|
|
||||||
align-items: flex-end;
|
|
||||||
gap: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c2 > *:first-child {
|
|
||||||
-webkit-box-flex: 4;
|
|
||||||
-webkit-flex-grow: 4;
|
|
||||||
-ms-flex-positive: 4;
|
|
||||||
flex-grow: 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c2 > *:last-child {
|
|
||||||
-webkit-box-flex: 1;
|
|
||||||
-webkit-flex-grow: 1;
|
|
||||||
-ms-flex-positive: 1;
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
class="c0"
|
|
||||||
>
|
|
||||||
<h1
|
|
||||||
class="c1"
|
|
||||||
>
|
|
||||||
Danger Zone
|
|
||||||
</h1>
|
|
||||||
<div>
|
|
||||||
<form
|
|
||||||
class="c2"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
class="c3"
|
|
||||||
for="partitions"
|
|
||||||
>
|
|
||||||
Number of partitions *
|
|
||||||
</label>
|
|
||||||
<div
|
|
||||||
class="c4"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
class="c5 c4"
|
|
||||||
id="partitions"
|
|
||||||
name="partitions"
|
|
||||||
placeholder="Number of partitions"
|
|
||||||
type="number"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
class="c6"
|
|
||||||
data-testid="partitionsSubmit"
|
|
||||||
disabled=""
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<p
|
|
||||||
class="c7"
|
|
||||||
/>
|
|
||||||
<form
|
|
||||||
class="c2"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
class="c3"
|
|
||||||
for="replicationFactor"
|
|
||||||
>
|
|
||||||
Replication Factor *
|
|
||||||
</label>
|
|
||||||
<div
|
|
||||||
class="c4"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
class="c8 c4"
|
|
||||||
id="replicationFactor"
|
|
||||||
name="replicationFactor"
|
|
||||||
placeholder="Replication Factor"
|
|
||||||
type="number"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
class="c6"
|
|
||||||
data-testid="replicationFactorSubmit"
|
|
||||||
disabled=""
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<p
|
|
||||||
class="c7"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
`;
|
|
|
@ -64,13 +64,14 @@ const CustomParamField: React.FC<Props> = ({
|
||||||
control={control}
|
control={control}
|
||||||
rules={{ required: 'Custom Parameter is required.' }}
|
rules={{ required: 'Custom Parameter is required.' }}
|
||||||
name={`customParams.${index}.name`}
|
name={`customParams.${index}.name`}
|
||||||
render={({ field: { name, onChange } }) => (
|
render={({ field: { value, name, onChange } }) => (
|
||||||
<Select
|
<Select
|
||||||
name={name}
|
name={name}
|
||||||
placeholder="Select"
|
placeholder="Select"
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
minWidth="270px"
|
minWidth="270px"
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
value={value}
|
||||||
options={Object.keys(TOPIC_CUSTOM_PARAMS)
|
options={Object.keys(TOPIC_CUSTOM_PARAMS)
|
||||||
.sort()
|
.sort()
|
||||||
.map((opt) => ({
|
.map((opt) => ({
|
||||||
|
|
|
@ -1,27 +1,25 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { TopicConfigByName, TopicFormData } from 'redux/interfaces';
|
import { TopicFormData } from 'redux/interfaces';
|
||||||
import { useFieldArray, useFormContext, useWatch } from 'react-hook-form';
|
import { useFieldArray, useFormContext, useWatch } from 'react-hook-form';
|
||||||
import { Button } from 'components/common/Button/Button';
|
import { Button } from 'components/common/Button/Button';
|
||||||
|
import { TOPIC_CUSTOM_PARAMS_PREFIX } from 'lib/constants';
|
||||||
|
|
||||||
import CustomParamField from './CustomParamField';
|
import CustomParamField from './CustomParamField';
|
||||||
import * as S from './CustomParams.styled';
|
import * as S from './CustomParams.styled';
|
||||||
|
|
||||||
export const INDEX_PREFIX = 'customParams';
|
|
||||||
|
|
||||||
export interface CustomParamsProps {
|
export interface CustomParamsProps {
|
||||||
isSubmitting: boolean;
|
isSubmitting: boolean;
|
||||||
config?: TopicConfigByName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const CustomParams: React.FC<CustomParamsProps> = ({ isSubmitting }) => {
|
const CustomParams: React.FC<CustomParamsProps> = ({ isSubmitting }) => {
|
||||||
const { control } = useFormContext<TopicFormData>();
|
const { control } = useFormContext<TopicFormData>();
|
||||||
const { fields, append, remove } = useFieldArray({
|
const { fields, append, remove } = useFieldArray({
|
||||||
control,
|
control,
|
||||||
name: INDEX_PREFIX,
|
name: TOPIC_CUSTOM_PARAMS_PREFIX,
|
||||||
});
|
});
|
||||||
const watchFieldArray = useWatch({
|
const watchFieldArray = useWatch({
|
||||||
control,
|
control,
|
||||||
name: INDEX_PREFIX,
|
name: TOPIC_CUSTOM_PARAMS_PREFIX,
|
||||||
defaultValue: fields,
|
defaultValue: fields,
|
||||||
});
|
});
|
||||||
const controlledFields = fields.map((field, index) => {
|
const controlledFields = fields.map((field, index) => {
|
||||||
|
|
|
@ -8,6 +8,8 @@ import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { TOPIC_CUSTOM_PARAMS } from 'lib/constants';
|
import { TOPIC_CUSTOM_PARAMS } from 'lib/constants';
|
||||||
|
|
||||||
|
import { defaultValues } from './fixtures';
|
||||||
|
|
||||||
const selectOption = async (listbox: HTMLElement, option: string) => {
|
const selectOption = async (listbox: HTMLElement, option: string) => {
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
userEvent.click(listbox);
|
userEvent.click(listbox);
|
||||||
|
@ -44,31 +46,44 @@ const expectOptionAvailability = async (
|
||||||
await waitFor(() => userEvent.click(listbox));
|
await waitFor(() => userEvent.click(listbox));
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('CustomParams', () => {
|
const renderComponent = (props: CustomParamsProps, defaults = {}) => {
|
||||||
const setupComponent = (props: CustomParamsProps) => {
|
const Wrapper: React.FC = ({ children }) => {
|
||||||
const Wrapper: React.FC = ({ children }) => {
|
const methods = useForm({ defaultValues: defaults });
|
||||||
const methods = useForm();
|
return <FormProvider {...methods}>{children}</FormProvider>;
|
||||||
return <FormProvider {...methods}>{children}</FormProvider>;
|
|
||||||
};
|
|
||||||
|
|
||||||
return render(
|
|
||||||
<Wrapper>
|
|
||||||
<CustomParams {...props} />
|
|
||||||
</Wrapper>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
return render(
|
||||||
setupComponent({ isSubmitting: false });
|
<Wrapper>
|
||||||
});
|
<CustomParams {...props} />
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('CustomParams', () => {
|
||||||
it('renders with props', () => {
|
it('renders with props', () => {
|
||||||
|
renderComponent({ isSubmitting: false });
|
||||||
|
|
||||||
const button = screen.getByRole('button');
|
const button = screen.getByRole('button');
|
||||||
expect(button).toBeInTheDocument();
|
expect(button).toBeInTheDocument();
|
||||||
expect(button).toHaveTextContent('Add Custom Parameter');
|
expect(button).toHaveTextContent('Add Custom Parameter');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('has defaultValues when they are set', () => {
|
||||||
|
renderComponent({ isSubmitting: false }, defaultValues);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.getByRole('option', { name: defaultValues.customParams[0].name })
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('textbox')).toHaveValue(
|
||||||
|
defaultValues.customParams[0].value
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
describe('works with user inputs correctly', () => {
|
describe('works with user inputs correctly', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
renderComponent({ isSubmitting: false });
|
||||||
|
});
|
||||||
|
|
||||||
it('button click creates custom param fieldset', async () => {
|
it('button click creates custom param fieldset', async () => {
|
||||||
const button = screen.getByRole('button');
|
const button = screen.getByRole('button');
|
||||||
await waitFor(() => userEvent.click(button));
|
await waitFor(() => userEvent.click(button));
|
|
@ -0,0 +1,15 @@
|
||||||
|
export const defaultValues = {
|
||||||
|
partitions: 1,
|
||||||
|
replicationFactor: 1,
|
||||||
|
minInSyncReplicas: 1,
|
||||||
|
cleanupPolicy: 'delete',
|
||||||
|
retentionBytes: -1,
|
||||||
|
maxMessageBytes: 1000012,
|
||||||
|
name: 'TestCustomParamEdit',
|
||||||
|
customParams: [
|
||||||
|
{
|
||||||
|
name: 'delete.retention.ms',
|
||||||
|
value: '86400001',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useFormContext, Controller } from 'react-hook-form';
|
import { useFormContext, Controller } from 'react-hook-form';
|
||||||
import { NOT_SET, BYTES_IN_GB } from 'lib/constants';
|
import { NOT_SET, BYTES_IN_GB } from 'lib/constants';
|
||||||
import { TopicName, TopicConfigByName } from 'redux/interfaces';
|
import { TopicName } from 'redux/interfaces';
|
||||||
import { ErrorMessage } from '@hookform/error-message';
|
import { ErrorMessage } from '@hookform/error-message';
|
||||||
import Select, { SelectOption } from 'components/common/Select/Select';
|
import Select, { SelectOption } from 'components/common/Select/Select';
|
||||||
import Input from 'components/common/Input/Input';
|
import Input from 'components/common/Input/Input';
|
||||||
|
@ -16,7 +16,6 @@ import * as S from './TopicForm.styled';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
topicName?: TopicName;
|
topicName?: TopicName;
|
||||||
config?: TopicConfigByName;
|
|
||||||
isEditing?: boolean;
|
isEditing?: boolean;
|
||||||
isSubmitting: boolean;
|
isSubmitting: boolean;
|
||||||
onSubmit: (e: React.BaseSyntheticEvent) => Promise<void>;
|
onSubmit: (e: React.BaseSyntheticEvent) => Promise<void>;
|
||||||
|
@ -38,7 +37,6 @@ const RetentionBytesOptions: Array<SelectOption> = [
|
||||||
|
|
||||||
const TopicForm: React.FC<Props> = ({
|
const TopicForm: React.FC<Props> = ({
|
||||||
topicName,
|
topicName,
|
||||||
config,
|
|
||||||
isEditing,
|
isEditing,
|
||||||
isSubmitting,
|
isSubmitting,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
|
@ -197,7 +195,7 @@ const TopicForm: React.FC<Props> = ({
|
||||||
</S.Column>
|
</S.Column>
|
||||||
|
|
||||||
<S.CustomParamsHeading>Custom parameters</S.CustomParamsHeading>
|
<S.CustomParamsHeading>Custom parameters</S.CustomParamsHeading>
|
||||||
<CustomParamsContainer isSubmitting={isSubmitting} config={config} />
|
<CustomParamsContainer isSubmitting={isSubmitting} />
|
||||||
|
|
||||||
<Button type="submit" buttonType="primary" buttonSize="L">
|
<Button type="submit" buttonType="primary" buttonSize="L">
|
||||||
Send
|
Send
|
||||||
|
|
|
@ -17,6 +17,7 @@ export const BASE_PARAMS: ConfigurationParameters = {
|
||||||
export const TOPIC_NAME_VALIDATION_PATTERN = /^[.,A-Za-z0-9_-]+$/;
|
export const TOPIC_NAME_VALIDATION_PATTERN = /^[.,A-Za-z0-9_-]+$/;
|
||||||
export const SCHEMA_NAME_VALIDATION_PATTERN = /^[.,A-Za-z0-9_-]+$/;
|
export const SCHEMA_NAME_VALIDATION_PATTERN = /^[.,A-Za-z0-9_-]+$/;
|
||||||
|
|
||||||
|
export const TOPIC_CUSTOM_PARAMS_PREFIX = 'customParams';
|
||||||
export const TOPIC_CUSTOM_PARAMS: Record<string, string> = {
|
export const TOPIC_CUSTOM_PARAMS: Record<string, string> = {
|
||||||
'compression.type': 'producer',
|
'compression.type': 'producer',
|
||||||
'leader.replication.throttled.replicas': '',
|
'leader.replication.throttled.replicas': '',
|
||||||
|
|
Loading…
Add table
Reference in a new issue