Skip to content

Commit a84acbf

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

File tree

7 files changed

+114
-3
lines changed

7 files changed

+114
-3
lines changed

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
};

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

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,32 @@
1+
import React from 'react';
2+
3+
import * as S from './MessageContent.styled';
4+
5+
export interface AvroMetadataProps {
6+
deserializeProperties?: { [key: string]: any | undefined };
7+
}
8+
9+
const AvroMetadata: React.FC<AvroMetadataProps> = ({ deserializeProperties }) => {
10+
if (
11+
!deserializeProperties || deserializeProperties.type !== 'AVRO' ||
12+
!deserializeProperties.name || !deserializeProperties.schemaId
13+
) {
14+
return null;
15+
}
16+
17+
return (
18+
<S.Metadata>
19+
<S.MetadataLabel>Value Type</S.MetadataLabel>
20+
<span>
21+
<S.MetadataValue>
22+
{deserializeProperties.name.split('.').pop()}
23+
</S.MetadataValue>
24+
<S.MetadataMeta>
25+
Schema Id: {deserializeProperties.schemaId}
26+
</S.MetadataMeta>
27+
</span>
28+
</S.Metadata>
29+
);
30+
};
31+
32+
export default AvroMetadata;

frontend/src/components/Topics/Topic/Messages/MessageContent/MessageContent.tsx

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import EditorViewer from 'components/common/EditorViewer/EditorViewer';
33
import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted';
44
import { SchemaType, TopicMessageTimestampTypeEnum } from 'generated-sources';
55
import { formatTimestamp } from 'lib/dateTimeHelpers';
6+
import AvroMetadata from './AvroMetadata';
67

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

@@ -18,6 +19,8 @@ export interface MessageContentProps {
1819
contentSize?: number;
1920
keySerde?: string;
2021
valueSerde?: string;
22+
keyDeserializeProperties?: { [key: string]: any | undefined };
23+
valueDeserializeProperties?: { [key: string]: any | 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 = () => {
@@ -117,6 +122,8 @@ const MessageContent: React.FC<MessageContentProps> = ({
117122
</S.MetadataMeta>
118123
</span>
119124
</S.Metadata>
125+
126+
<AvroMetadata deserializeProperties={keyDeserializeProperties} />
120127

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

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,13 +41,17 @@ 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();
51+
});
52+
53+
it('valueType in document', () => {
54+
expect(screen.getByText('Value Type')).toBeInTheDocument();
4655
});
4756
});
4857

0 commit comments

Comments
 (0)