Skip to content

Commit 6311755

Browse files
committed
Adds type and schema id information to the UI for avro message keys and values.
Closes: #77
1 parent 8e8ff06 commit 6311755

File tree

7 files changed

+120
-3
lines changed

7 files changed

+120
-3
lines changed

Diff for: api/src/main/java/io/kafbat/ui/serdes/builtin/sr/SchemaRegistrySerde.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -276,18 +276,26 @@ public Serializer serializer(String topic, Target type) {
276276
};
277277
}
278278

279+
private String getNameBySchemaId(int schemaId) {
280+
return getSchemaById(schemaId)
281+
.map(it -> it.name().toString())
282+
.orElseThrow(() -> new ValidationException(String.format("Schema for id '%d' not found ", schemaId)));
283+
}
284+
279285
@Override
280286
public Deserializer deserializer(String topic, Target type) {
281287
return (headers, data) -> {
282288
var schemaId = extractSchemaIdFromMsg(data);
283289
SchemaType format = getMessageFormatBySchemaId(schemaId);
290+
String name = getNameBySchemaId(schemaId);
284291
MessageFormatter formatter = schemaRegistryFormatters.get(format);
285292
return new DeserializeResult(
286293
formatter.format(topic, data),
287294
DeserializeResult.Type.JSON,
288295
Map.of(
289296
"schemaId", schemaId,
290-
"type", format.name()
297+
"type", format.name(),
298+
"name", name
291299
)
292300
);
293301
};

Diff for: api/src/test/java/io/kafbat/ui/serdes/builtin/sr/SchemaRegistrySerdeTest.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ void deserializeReturnsJsonAvroMsgJsonRepresentation() throws RestClientExceptio
127127
assertThat(result.getType()).isEqualTo(DeserializeResult.Type.JSON);
128128
assertThat(result.getAdditionalProperties())
129129
.contains(Map.entry("type", "AVRO"))
130-
.contains(Map.entry("schemaId", schemaId));
130+
.contains(Map.entry("schemaId", schemaId))
131+
.contains(Map.entry("name", "TestAvroRecord1"));
131132
}
132133

133134
@Nested

Diff for: frontend/src/components/Topics/Topic/Messages/Message.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ const Message: React.FC<Props> = ({
3737
headers,
3838
valueSerde,
3939
keySerde,
40+
keyDeserializeProperties,
41+
valueDeserializeProperties,
4042
},
4143
keyFilters,
4244
contentFilters,
@@ -157,6 +159,8 @@ const Message: React.FC<Props> = ({
157159
contentSize={valueSize}
158160
keySerde={keySerde}
159161
valueSerde={valueSerde}
162+
keyDeserializeProperties={keyDeserializeProperties}
163+
valueDeserializeProperties={valueDeserializeProperties}
160164
/>
161165
)}
162166
</>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React from 'react';
2+
3+
import * as S from './MessageContent.styled';
4+
5+
export interface AvroMetadataProps {
6+
deserializeProperties?: { [key: string]: unknown | undefined };
7+
}
8+
9+
const AvroMetadata: React.FC<AvroMetadataProps> = ({
10+
deserializeProperties,
11+
}) => {
12+
if (
13+
!deserializeProperties ||
14+
deserializeProperties.type !== 'AVRO' ||
15+
!deserializeProperties.name ||
16+
!deserializeProperties.schemaId
17+
) {
18+
return null;
19+
}
20+
21+
if (
22+
typeof deserializeProperties.name !== 'string' ||
23+
typeof deserializeProperties.schemaId !== 'number'
24+
) {
25+
return null;
26+
}
27+
28+
return (
29+
<S.Metadata>
30+
<S.MetadataLabel>Value Type</S.MetadataLabel>
31+
<span>
32+
<S.MetadataValue>
33+
{deserializeProperties.name.split('.').pop()}
34+
</S.MetadataValue>
35+
<S.MetadataMeta>
36+
Schema Id: {deserializeProperties.schemaId}
37+
</S.MetadataMeta>
38+
</span>
39+
</S.Metadata>
40+
);
41+
};
42+
43+
export default AvroMetadata;

Diff for: frontend/src/components/Topics/Topic/Messages/MessageContent/MessageContent.tsx

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted';
44
import { SchemaType, TopicMessageTimestampTypeEnum } from 'generated-sources';
55
import { formatTimestamp } from 'lib/dateTimeHelpers';
66

7+
import AvroMetadata from './AvroMetadata';
78
import * as S from './MessageContent.styled';
89

910
type Tab = 'key' | 'content' | 'headers';
@@ -18,6 +19,8 @@ export interface MessageContentProps {
1819
contentSize?: number;
1920
keySerde?: string;
2021
valueSerde?: string;
22+
keyDeserializeProperties?: { [key: string]: unknown | undefined };
23+
valueDeserializeProperties?: { [key: string]: unknown | undefined };
2124
}
2225

2326
const MessageContent: React.FC<MessageContentProps> = ({
@@ -30,6 +33,8 @@ const MessageContent: React.FC<MessageContentProps> = ({
3033
contentSize,
3134
keySerde,
3235
valueSerde,
36+
keyDeserializeProperties,
37+
valueDeserializeProperties,
3338
}) => {
3439
const [activeTab, setActiveTab] = React.useState<Tab>('content');
3540
const activeTabContent = () => {
@@ -118,6 +123,8 @@ const MessageContent: React.FC<MessageContentProps> = ({
118123
</span>
119124
</S.Metadata>
120125

126+
<AvroMetadata deserializeProperties={keyDeserializeProperties} />
127+
121128
<S.Metadata>
122129
<S.MetadataLabel>Value Serde</S.MetadataLabel>
123130
<span>
@@ -127,6 +134,8 @@ const MessageContent: React.FC<MessageContentProps> = ({
127134
</S.MetadataMeta>
128135
</span>
129136
</S.Metadata>
137+
138+
<AvroMetadata deserializeProperties={valueDeserializeProperties} />
130139
</S.MetadataWrapper>
131140
</S.Section>
132141
</td>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { TextEncoder } from 'util';
2+
3+
import React from 'react';
4+
import { screen } from '@testing-library/react';
5+
import { render } from 'lib/testHelpers';
6+
import AvroMetadata, {
7+
AvroMetadataProps,
8+
} from 'components/Topics/Topic/Messages/MessageContent/AvroMetadata';
9+
10+
const setupWrapper = (props?: Partial<AvroMetadataProps>) => {
11+
return (
12+
<table>
13+
<tbody>
14+
<AvroMetadata
15+
deserializeProperties={{
16+
type: 'AVRO',
17+
name: 'com.kafbat.MessageType',
18+
schemaId: 1,
19+
}}
20+
{...props}
21+
/>
22+
</tbody>
23+
</table>
24+
);
25+
};
26+
27+
global.TextEncoder = TextEncoder;
28+
29+
describe('AvroMetadata screen', () => {
30+
beforeEach(() => {
31+
render(setupWrapper());
32+
});
33+
34+
describe('Checking type and schema id', () => {
35+
it('type in document', () => {
36+
expect(screen.getByText('MessageType')).toBeInTheDocument();
37+
});
38+
39+
it('schema id in document', () => {
40+
expect(screen.getByText('Schema Id: 1')).toBeInTheDocument();
41+
});
42+
});
43+
});

Diff for: frontend/src/components/Topics/Topic/Messages/MessageContent/__tests__/MessageContent.spec.tsx

+10-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ const setupWrapper = (props?: Partial<MessageContentProps>) => {
2222
timestampType={TopicMessageTimestampTypeEnum.CREATE_TIME}
2323
keySerde="SchemaRegistry"
2424
valueSerde="Avro"
25+
valueDeserializeProperties={{
26+
type: 'AVRO',
27+
name: 'MessageType',
28+
schemaId: 1,
29+
}}
2530
{...props}
2631
/>
2732
</tbody>
@@ -36,14 +41,18 @@ describe('MessageContent screen', () => {
3641
render(setupWrapper());
3742
});
3843

39-
describe('Checking keySerde and valueSerde', () => {
44+
describe('Checking keySerde, valueSerde and valueType', () => {
4045
it('keySerde in document', () => {
4146
expect(screen.getByText('SchemaRegistry')).toBeInTheDocument();
4247
});
4348

4449
it('valueSerde in document', () => {
4550
expect(screen.getByText('Avro')).toBeInTheDocument();
4651
});
52+
53+
it('valueType in document', () => {
54+
expect(screen.getByText('Value Type')).toBeInTheDocument();
55+
});
4756
});
4857

4958
describe('when switched to display the key', () => {

0 commit comments

Comments
 (0)