Merge branch 'master' into DISCUSSION-4109_sr_serde_serialize

This commit is contained in:
Ilya Kuramshin 2023-08-29 13:34:45 +04:00 committed by GitHub
commit b4f1e7d93c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 1350 additions and 1227 deletions

View file

@ -25,11 +25,11 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }}
- uses: pnpm/action-setup@v2.4.0
with:
version: 7.4.0
version: 8.6.12
- name: Install node
uses: actions/setup-node@v3.8.1
with:
node-version: "16.15.0"
node-version: "18.17.1"
cache: "pnpm"
cache-dependency-path: "./kafka-ui-react-app/pnpm-lock.yaml"
- name: Install Node dependencies

View file

@ -16,6 +16,8 @@ import java.util.stream.Stream;
public class BrokersConfigTab extends BasePage {
protected List<SelenideElement> editBtn = $$x("//button[@aria-label='editAction']");
protected SelenideElement searchByKeyField = $x("//input[@placeholder='Search by Key or Value']");
protected SelenideElement sourceInfoIcon = $x("//div[text()='Source']/..//div/div[@class]");
protected SelenideElement sourceInfoTooltip = $x("//div[text()='Source']/..//div/div[@style]");
protected ElementsCollection editBtns = $$x("//button[@aria-label='editAction']");

View file

@ -1 +1 @@
v16.15.0
v18.17.1

View file

@ -106,7 +106,7 @@
"vite-plugin-ejs": "^1.6.4"
},
"engines": {
"node": "v16.15.0",
"pnpm": "^7.4.0"
"node": "v18.17.1",
"pnpm": "^8.6.12"
}
}

File diff suppressed because it is too large Load diff

View file

@ -34,14 +34,19 @@ const Configs: React.FC = () => {
const getData = () => {
return data
.filter(
(item) =>
item.name.toLocaleLowerCase().indexOf(keyword.toLocaleLowerCase()) >
-1
)
.filter((item) => {
const nameMatch = item.name
.toLocaleLowerCase()
.includes(keyword.toLocaleLowerCase());
return nameMatch
? true
: item.value &&
item.value
.toLocaleLowerCase()
.includes(keyword.toLocaleLowerCase()); // try to match the keyword on any of the item.value elements when nameMatch fails but item.value exists
})
.sort((a, b) => {
if (a.source === b.source) return 0;
return a.source === ConfigSource.DYNAMIC_BROKER_CONFIG ? -1 : 1;
});
};
@ -95,7 +100,7 @@ const Configs: React.FC = () => {
<S.SearchWrapper>
<Search
onChange={setKeyword}
placeholder="Search by Key"
placeholder="Search by Key or Value"
value={keyword}
/>
</S.SearchWrapper>

View file

@ -13,7 +13,7 @@ import { brokersPayload } from 'lib/fixtures/brokers';
import { clusterStatsPayload } from 'lib/fixtures/clusters';
const clusterName = 'local';
const brokerId = 1;
const brokerId = 200;
const activeClassName = 'is-active';
const brokerLogdir = {
pageText: 'brokerLogdir',

View file

@ -73,13 +73,13 @@ const BrokersList: React.FC = () => {
header: 'Broker ID',
accessorKey: 'brokerId',
// eslint-disable-next-line react/no-unstable-nested-components
cell: ({ row: { id }, getValue }) => (
cell: ({ getValue }) => (
<S.RowCell>
<LinkCell
value={`${getValue<string | number>()}`}
to={encodeURIComponent(`${getValue<string | number>()}`)}
/>
{id === String(activeControllers) && (
{getValue<string | number>() === activeControllers && (
<Tooltip
value={<CheckMarkRoundIcon />}
content="Active Controller"

View file

@ -56,11 +56,11 @@ describe('BrokersList Component', () => {
});
it('opens broker when row clicked', async () => {
renderComponent();
await userEvent.click(screen.getByRole('cell', { name: '0' }));
await userEvent.click(screen.getByRole('cell', { name: '100' }));
await waitFor(() =>
expect(mockedUsedNavigate).toBeCalledWith(
clusterBrokerPath(clusterName, '0')
clusterBrokerPath(clusterName, '100')
)
);
});
@ -124,6 +124,39 @@ describe('BrokersList Component', () => {
});
});
describe('BrokersList', () => {
describe('when the brokers are loaded', () => {
const testActiveControllers = 0;
beforeEach(() => {
(useBrokers as jest.Mock).mockImplementation(() => ({
data: brokersPayload,
}));
(useClusterStats as jest.Mock).mockImplementation(() => ({
data: clusterStatsPayload,
}));
});
it(`Indicates correct active cluster`, async () => {
renderComponent();
await waitFor(() =>
expect(screen.getByRole('tooltip')).toBeInTheDocument()
);
});
it(`Correct display even if there is no active cluster: ${testActiveControllers} `, async () => {
(useClusterStats as jest.Mock).mockImplementation(() => ({
data: {
...clusterStatsPayload,
activeControllers: testActiveControllers,
},
}));
renderComponent();
await waitFor(() =>
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument()
);
});
});
});
describe('when diskUsage is empty', () => {
beforeEach(() => {
(useBrokers as jest.Mock).mockImplementation(() => ({
@ -157,11 +190,11 @@ describe('BrokersList Component', () => {
});
it('opens broker when row clicked', async () => {
renderComponent();
await userEvent.click(screen.getByRole('cell', { name: '1' }));
await userEvent.click(screen.getByRole('cell', { name: '100' }));
await waitFor(() =>
expect(mockedUsedNavigate).toBeCalledWith(
clusterBrokerPath(clusterName, '1')
clusterBrokerPath(clusterName, '100')
)
);
});

View file

@ -15,7 +15,7 @@ enum Filters {
PARTITION_COUNT = 'partitionCount',
REPLICATION_FACTOR = 'replicationFactor',
INSYNC_REPLICAS = 'inSyncReplicas',
CLEANUP_POLICY = 'Delete',
CLEANUP_POLICY = 'cleanUpPolicy',
}
const New: React.FC = () => {

View file

@ -60,16 +60,16 @@ describe('New', () => {
await userEvent.clear(screen.getByPlaceholderText('Topic Name'));
await userEvent.tab();
await expect(
screen.getByText('name is a required field')
screen.getByText('Topic Name is required')
).toBeInTheDocument();
await userEvent.type(
screen.getByLabelText('Number of partitions *'),
screen.getByLabelText('Number of Partitions *'),
minValue
);
await userEvent.clear(screen.getByLabelText('Number of partitions *'));
await userEvent.clear(screen.getByLabelText('Number of Partitions *'));
await userEvent.tab();
await expect(
screen.getByText('Number of partitions is required and must be a number')
screen.getByText('Number of Partitions is required and must be a number')
).toBeInTheDocument();
expect(createTopicMock).not.toHaveBeenCalled();
@ -89,7 +89,7 @@ describe('New', () => {
renderComponent(clusterTopicNewPath(clusterName));
await userEvent.type(screen.getByPlaceholderText('Topic Name'), topicName);
await userEvent.type(
screen.getByLabelText('Number of partitions *'),
screen.getByLabelText('Number of Partitions *'),
minValue
);
await userEvent.click(screen.getByText('Create topic'));

View file

@ -1,4 +1,5 @@
import styled from 'styled-components';
import Input from 'components/common/Input/Input';
export const Column = styled.div`
display: flex;
@ -16,6 +17,10 @@ export const CustomParamsHeading = styled.h4`
color: ${({ theme }) => theme.heading.h4};
`;
export const MessageSizeInput = styled(Input)`
min-width: 195px;
`;
export const Label = styled.div`
display: flex;
gap: 16px;

View file

@ -109,12 +109,12 @@ const TopicForm: React.FC<Props> = ({
{!isEditing && (
<div>
<InputLabel htmlFor="topicFormNumberOfPartitions">
Number of partitions *
Number of Partitions *
</InputLabel>
<Input
id="topicFormNumberOfPartitions"
type="number"
placeholder="Number of partitions"
placeholder="Number of Partitions"
min="1"
name="partitions"
positiveOnly
@ -228,7 +228,7 @@ const TopicForm: React.FC<Props> = ({
<InputLabel htmlFor="topicFormMaxMessageBytes">
Maximum message size in bytes
</InputLabel>
<Input
<S.MessageSizeInput
id="topicFormMaxMessageBytes"
type="number"
placeholder="Maximum message size"

View file

@ -37,7 +37,7 @@ describe('TopicForm', () => {
expectByRoleAndNameToBeInDocument('textbox', 'Topic Name *');
expectByRoleAndNameToBeInDocument('spinbutton', 'Number of partitions *');
expectByRoleAndNameToBeInDocument('spinbutton', 'Number of Partitions *');
expectByRoleAndNameToBeInDocument('spinbutton', 'Replication Factor');
expectByRoleAndNameToBeInDocument('spinbutton', 'Min In Sync Replicas');

View file

@ -7,6 +7,7 @@ const CheckMarkRoundIcon: React.FC = () => {
height="14"
viewBox="0 0 14 14"
fill="none"
role="tooltip"
xmlns="http://www.w3.org/2000/svg"
>
<path

View file

@ -1,8 +1,8 @@
import { BrokerConfig, BrokersLogdirs, ConfigSource } from 'generated-sources';
export const brokersPayload = [
{ id: 1, host: 'b-1.test.kafka.amazonaws.com', port: 9092 },
{ id: 2, host: 'b-2.test.kafka.amazonaws.com', port: 9092 },
{ id: 100, host: 'b-1.test.kafka.amazonaws.com', port: 9092 },
{ id: 200, host: 'b-2.test.kafka.amazonaws.com', port: 9092 },
];
const partition = {

View file

@ -32,15 +32,15 @@ export const clustersPayload: Cluster[] = [
export const clusterStatsPayload = {
brokerCount: 2,
activeControllers: 1,
activeControllers: 100,
onlinePartitionCount: 138,
offlinePartitionCount: 0,
inSyncReplicasCount: 239,
outOfSyncReplicasCount: 0,
underReplicatedPartitionCount: 0,
diskUsage: [
{ brokerId: 0, segmentSize: 334567, segmentCount: 245 },
{ brokerId: 1, segmentSize: 12345678, segmentCount: 121 },
{ brokerId: 100, segmentSize: 334567, segmentCount: 245 },
{ brokerId: 200, segmentSize: 12345678, segmentCount: 121 },
],
version: '2.2.1',
};

View file

@ -76,7 +76,6 @@ const formatTopicCreation = (form: TopicFormData): TopicCreation => {
partitions,
replicationFactor,
cleanupPolicy,
retentionBytes,
retentionMs,
maxMessageBytes,
minInSyncReplicas,
@ -86,7 +85,6 @@ const formatTopicCreation = (form: TopicFormData): TopicCreation => {
const configs = {
'cleanup.policy': cleanupPolicy,
'retention.ms': retentionMs.toString(),
'retention.bytes': retentionBytes.toString(),
'max.message.bytes': maxMessageBytes.toString(),
'min.insync.replicas': minInSyncReplicas.toString(),
...Object.values(customParams || {}).reduce(topicReducer, {}),

View file

@ -66,17 +66,17 @@ export const topicFormValidationSchema = yup.object().shape({
name: yup
.string()
.max(249)
.required()
.required('Topic Name is required')
.matches(
TOPIC_NAME_VALIDATION_PATTERN,
'Only alphanumeric, _, -, and . allowed'
),
partitions: yup
.number()
.min(1)
.min(1, 'Number of Partitions must be greater than or equal to 1')
.max(2147483647)
.required()
.typeError('Number of partitions is required and must be a number'),
.typeError('Number of Partitions is required and must be a number'),
replicationFactor: yup.string(),
minInSyncReplicas: yup.string(),
cleanupPolicy: yup.string().required(),

View file

@ -44,7 +44,6 @@ export interface TopicFormData {
minInSyncReplicas: number;
cleanupPolicy: string;
retentionMs: number;
retentionBytes: number;
maxMessageBytes: number;
customParams: {
name: string;

View file

@ -49,8 +49,8 @@
<testcontainers.version>1.17.5</testcontainers.version>
<!-- Frontend dependency versions -->
<node.version>v16.15.0</node.version>
<pnpm.version>v7.4.0</pnpm.version>
<node.version>v18.17.1</node.version>
<pnpm.version>v8.6.12</pnpm.version>
<!-- Plugin versions -->
<fabric8-maven-plugin.version>0.42.1</fabric8-maven-plugin.version>