Skip to content

Commit e9c29ac

Browse files
committed
fe: abstract SR mode and compat types
Unfortunately this is not yet in our proto services, so for now we have to follow the same approach we have for the REST endpoints
1 parent eeec4ee commit e9c29ac

6 files changed

Lines changed: 113 additions & 79 deletions

File tree

frontend/src/components/pages/schemas/edit-compatibility.tsx

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ import {
2727
useUpdateSubjectCompatibilityMutation,
2828
} from '../../../react-query/api/schema-registry';
2929
import { api } from '../../../state/backend-api';
30-
import type {
31-
SchemaRegistryCompatibilityMode,
32-
SchemaRegistrySubjectDetails,
33-
SchemaRegistryVersionedSchema,
30+
import {
31+
type SchemaRegistryCompatibilityMode,
32+
SchemaRegistryCompatibilityModes,
33+
type SchemaRegistryCompatibilityModeWithDefault,
34+
type SchemaRegistrySubjectDetails,
35+
type SchemaRegistryVersionedSchema,
3436
} from '../../../state/rest-interfaces';
3537
import { useSupportedFeaturesStore } from '../../../state/supported-features';
3638
import { uiState } from '../../../state/ui-state';
@@ -131,7 +133,7 @@ export default EditSchemaCompatibilityPage;
131133
function EditSchemaCompatibility(p: {
132134
subjectName?: string;
133135
contextName?: string;
134-
contextCompatibility?: string;
136+
contextCompatibility?: SchemaRegistryCompatibilityModeWithDefault;
135137
schemaMode: string | null | undefined;
136138
schemaCompatibility: string | null | undefined;
137139
schemaDetails: SchemaRegistrySubjectDetails | undefined;
@@ -147,11 +149,12 @@ function EditSchemaCompatibility(p: {
147149
(x: SchemaRegistryVersionedSchema) => x.version === schemaDetails.latestActiveVersion
148150
);
149151

150-
const [configMode, setConfigMode] = useState<string>(
151-
contextName
152-
? (contextCompatibility ?? 'DEFAULT')
153-
: ((subjectName ? schemaDetails?.compatibility : schemaCompatibility) ?? 'DEFAULT')
154-
);
152+
const getInitialCompatibility = (): SchemaRegistryCompatibilityModeWithDefault => {
153+
if (contextName) return contextCompatibility ?? SchemaRegistryCompatibilityModes.DEFAULT;
154+
const source = subjectName ? schemaDetails?.compatibility : schemaCompatibility;
155+
return (source as SchemaRegistryCompatibilityModeWithDefault) ?? SchemaRegistryCompatibilityModes.DEFAULT;
156+
};
157+
const [configMode, setConfigMode] = useState<SchemaRegistryCompatibilityModeWithDefault>(getInitialCompatibility);
155158

156159
if (subjectName && !schema) {
157160
return DefaultSkeleton;
@@ -182,15 +185,9 @@ function EditSchemaCompatibility(p: {
182185
};
183186

184187
if (contextName) {
185-
updateContextMutation.mutate(
186-
{ contextName, mode: configMode as 'DEFAULT' | SchemaRegistryCompatibilityMode },
187-
callbacks
188-
);
188+
updateContextMutation.mutate({ contextName, mode: configMode }, callbacks);
189189
} else if (subjectName) {
190-
updateSubjectMutation.mutate(
191-
{ subjectName, mode: configMode as 'DEFAULT' | SchemaRegistryCompatibilityMode },
192-
callbacks
193-
);
190+
updateSubjectMutation.mutate({ subjectName, mode: configMode }, callbacks);
194191
} else {
195192
updateGlobalMutation.mutate(configMode as SchemaRegistryCompatibilityMode, callbacks);
196193
}
@@ -220,11 +217,11 @@ function EditSchemaCompatibility(p: {
220217
isAttached={false}
221218
name="configMode"
222219
onChange={(e) => {
223-
setConfigMode(e);
220+
setConfigMode(e as SchemaRegistryCompatibilityModeWithDefault);
224221
}}
225222
options={[
226223
{
227-
value: 'DEFAULT',
224+
value: SchemaRegistryCompatibilityModes.DEFAULT,
228225
disabled: !(schemaDetails || contextName),
229226
label: (
230227
<Box>
@@ -234,7 +231,7 @@ function EditSchemaCompatibility(p: {
234231
),
235232
},
236233
{
237-
value: 'NONE',
234+
value: SchemaRegistryCompatibilityModes.NONE,
238235
label: (
239236
<Box>
240237
<Text>None</Text>
@@ -243,7 +240,7 @@ function EditSchemaCompatibility(p: {
243240
),
244241
},
245242
{
246-
value: 'BACKWARD',
243+
value: SchemaRegistryCompatibilityModes.BACKWARD,
247244
label: (
248245
<Box>
249246
<Text>Backward</Text>
@@ -255,7 +252,7 @@ function EditSchemaCompatibility(p: {
255252
),
256253
},
257254
{
258-
value: 'BACKWARD_TRANSITIVE',
255+
value: SchemaRegistryCompatibilityModes.BACKWARD_TRANSITIVE,
259256
label: (
260257
<Box>
261258
<Text>Transitive Backward</Text>
@@ -267,7 +264,7 @@ function EditSchemaCompatibility(p: {
267264
),
268265
},
269266
{
270-
value: 'FORWARD',
267+
value: SchemaRegistryCompatibilityModes.FORWARD,
271268
label: (
272269
<Box>
273270
<Text>Forward</Text>
@@ -279,7 +276,7 @@ function EditSchemaCompatibility(p: {
279276
),
280277
},
281278
{
282-
value: 'FORWARD_TRANSITIVE',
279+
value: SchemaRegistryCompatibilityModes.FORWARD_TRANSITIVE,
283280
label: (
284281
<Box>
285282
<Text>Transitive Forward</Text>
@@ -291,7 +288,7 @@ function EditSchemaCompatibility(p: {
291288
),
292289
},
293290
{
294-
value: 'FULL',
291+
value: SchemaRegistryCompatibilityModes.FULL,
295292
label: (
296293
<Box>
297294
<Text>Full</Text>
@@ -303,7 +300,7 @@ function EditSchemaCompatibility(p: {
303300
),
304301
},
305302
{
306-
value: 'FULL_TRANSITIVE',
303+
value: SchemaRegistryCompatibilityModes.FULL_TRANSITIVE,
307304
label: (
308305
<Box>
309306
<Text>Transitive Full</Text>

frontend/src/components/pages/schemas/edit-mode.test.tsx

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -32,32 +32,36 @@ vi.mock('@tanstack/react-router', async (importOriginal) => {
3232
};
3333
});
3434

35-
vi.mock('react-query/api/schema-registry', () => ({
36-
useSchemaModeQuery: vi.fn(() => ({
37-
data: 'READWRITE',
38-
isLoading: false,
39-
})),
40-
useSchemaDetailsQuery: vi.fn((_subject: string | undefined, _opts?: { enabled?: boolean }) => ({
41-
data: undefined,
42-
isLoading: false,
43-
})),
44-
useUpdateGlobalModeMutation: vi.fn(() => ({
45-
mutate: mockMutateGlobal,
46-
isPending: false,
47-
})),
48-
useUpdateSubjectModeMutation: vi.fn(() => ({
49-
mutate: mockMutateSubject,
50-
isPending: false,
51-
})),
52-
useSchemaRegistryContextsQuery: vi.fn(() => ({
53-
data: [],
54-
isLoading: false,
55-
})),
56-
useUpdateContextModeMutation: vi.fn(() => ({
57-
mutate: mockMutateContext,
58-
isPending: false,
59-
})),
60-
}));
35+
vi.mock('react-query/api/schema-registry', async (importOriginal) => {
36+
const actual = await importOriginal<typeof import('react-query/api/schema-registry')>();
37+
return {
38+
...actual,
39+
useSchemaModeQuery: vi.fn(() => ({
40+
data: 'READWRITE',
41+
isLoading: false,
42+
})),
43+
useSchemaDetailsQuery: vi.fn((_subject: string | undefined, _opts?: { enabled?: boolean }) => ({
44+
data: undefined,
45+
isLoading: false,
46+
})),
47+
useUpdateGlobalModeMutation: vi.fn(() => ({
48+
mutate: mockMutateGlobal,
49+
isPending: false,
50+
})),
51+
useUpdateSubjectModeMutation: vi.fn(() => ({
52+
mutate: mockMutateSubject,
53+
isPending: false,
54+
})),
55+
useSchemaRegistryContextsQuery: vi.fn(() => ({
56+
data: [],
57+
isLoading: false,
58+
})),
59+
useUpdateContextModeMutation: vi.fn(() => ({
60+
mutate: mockMutateContext,
61+
isPending: false,
62+
})),
63+
};
64+
});
6165

6266
vi.mock('state/backend-api', async (importOriginal) => {
6367
const actual = await importOriginal<typeof import('state/backend-api')>();

frontend/src/components/pages/schemas/edit-mode.tsx

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import { getFormattedSchemaText, schemaTypeToCodeBlockLanguage } from './schema-
3030
import { SchemaNotConfiguredPage } from './schema-not-configured';
3131
import {
3232
type SchemaRegistryMode,
33+
SchemaRegistryModes,
34+
type SchemaRegistryModeWithDefault,
3335
useSchemaDetailsQuery,
3436
useSchemaModeQuery,
3537
useSchemaRegistryContextsQuery,
@@ -44,7 +46,7 @@ import { uiState } from '../../../state/ui-state';
4446
import PageContent from '../../misc/page-content';
4547

4648
const DEFAULT_OPTION = {
47-
value: 'DEFAULT',
49+
value: SchemaRegistryModes.DEFAULT,
4850
title: 'Default',
4951
description: 'Use the globally configured default mode.',
5052
warning: null,
@@ -57,20 +59,20 @@ const MODE_OPTIONS: {
5759
warning: string | null;
5860
}[] = [
5961
{
60-
value: 'READWRITE',
62+
value: SchemaRegistryModes.READWRITE,
6163
title: 'Read/Write',
6264
description: 'The registry accepts new schema registrations and allows reads. This is the normal operating mode.',
6365
warning: null,
6466
},
6567
{
66-
value: 'READONLY',
68+
value: SchemaRegistryModes.READONLY,
6769
title: 'Read Only',
6870
description:
6971
'Schema lookups are permitted but registration is blocked. Use this for standby clusters in a disaster recovery setup that replicate schemas from an active cluster.',
7072
warning: null,
7173
},
7274
{
73-
value: 'IMPORT',
75+
value: SchemaRegistryModes.IMPORT,
7476
title: 'Import',
7577
description:
7678
'Allows registering schemas with specific IDs and versions while bypassing compatibility checks. Use this on target clusters during migrations to preserve schema IDs. Requires an empty registry or subject.',
@@ -184,7 +186,7 @@ function EditSchemaMode({
184186
onClose: () => void;
185187
subjectName?: string;
186188
contextName?: string;
187-
contextMode?: string;
189+
contextMode?: SchemaRegistryModeWithDefault;
188190
schemaDetails?: SchemaRegistrySubjectDetails;
189191
}) {
190192
const updateGlobalMutation = useUpdateGlobalModeMutation();
@@ -195,15 +197,19 @@ function EditSchemaMode({
195197
(x: SchemaRegistryVersionedSchema) => x.version === schemaDetails.latestActiveVersion
196198
);
197199

198-
const initialMode = contextName
199-
? (contextMode ?? 'DEFAULT')
200-
: subjectName
201-
? (schemaDetails?.mode ?? 'READWRITE')
202-
: (schemaMode ?? 'READWRITE');
203-
const [selectedMode, setSelectedMode] = useState<string>(initialMode);
200+
const getInitialMode = (): SchemaRegistryModeWithDefault => {
201+
if (contextName) return contextMode ?? SchemaRegistryModes.DEFAULT;
202+
if (subjectName) return schemaDetails?.mode ?? SchemaRegistryModes.READWRITE;
203+
return (schemaMode as SchemaRegistryModeWithDefault) ?? SchemaRegistryModes.READWRITE;
204+
};
205+
const [selectedMode, setSelectedMode] = useState<SchemaRegistryModeWithDefault>(getInitialMode);
204206

205-
const allOptions: { value: string; title: string; description: string; warning: string | null }[] =
206-
subjectName || contextName ? [DEFAULT_OPTION, ...MODE_OPTIONS] : MODE_OPTIONS;
207+
const allOptions: {
208+
value: SchemaRegistryModeWithDefault;
209+
title: string;
210+
description: string;
211+
warning: string | null;
212+
}[] = subjectName || contextName ? [DEFAULT_OPTION, ...MODE_OPTIONS] : MODE_OPTIONS;
207213

208214
const onSave = () => {
209215
const callbacks = {
@@ -217,9 +223,9 @@ function EditSchemaMode({
217223
};
218224

219225
if (contextName) {
220-
updateContextMutation.mutate({ contextName, mode: selectedMode as 'DEFAULT' | SchemaRegistryMode }, callbacks);
226+
updateContextMutation.mutate({ contextName, mode: selectedMode }, callbacks);
221227
} else if (subjectName) {
222-
updateSubjectMutation.mutate({ subjectName, mode: selectedMode as 'DEFAULT' | SchemaRegistryMode }, callbacks);
228+
updateSubjectMutation.mutate({ subjectName, mode: selectedMode }, callbacks);
223229
} else {
224230
updateGlobalMutation.mutate(selectedMode as SchemaRegistryMode, callbacks);
225231
}
@@ -244,7 +250,7 @@ function EditSchemaMode({
244250
<Choicebox
245251
className="w-full"
246252
data-testid="edit-mode-radio"
247-
onValueChange={setSelectedMode}
253+
onValueChange={(v) => setSelectedMode(v as SchemaRegistryModeWithDefault)}
248254
value={selectedMode}
249255
>
250256
{allOptions.map((option) => (

frontend/src/react-query/api/schema-registry.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ import { config } from 'config';
1010
import { api } from 'state/backend-api';
1111
import type {
1212
SchemaRegistryCompatibilityMode,
13+
SchemaRegistryCompatibilityModeWithDefault,
1314
SchemaRegistryConfigResponse,
15+
SchemaRegistryMode,
16+
SchemaRegistryModeWithDefault,
1417
SchemaRegistrySubject,
1518
SchemaRegistrySubjectDetails,
1619
SchemaVersion,
@@ -24,8 +27,8 @@ const STALE_TIME_MEDIUM = 30_000; // 30 seconds
2427

2528
export type SchemaRegistryContextResponse = {
2629
name: string;
27-
mode: string;
28-
compatibility: string;
30+
mode: SchemaRegistryModeWithDefault;
31+
compatibility: SchemaRegistryCompatibilityModeWithDefault;
2932
};
3033

3134
export const useSchemaRegistryContextsQuery = (enabled = true) =>
@@ -154,7 +157,14 @@ export const useSchemaDetailsQuery = (subjectName?: string, options?: { enabled?
154157
enabled: options?.enabled !== false && subjectName !== '',
155158
});
156159

157-
export type SchemaRegistryMode = 'READWRITE' | 'READONLY' | 'IMPORT';
160+
export type { SchemaRegistryMode, SchemaRegistryModeWithDefault } from 'state/rest-interfaces';
161+
162+
export const SchemaRegistryModes = {
163+
DEFAULT: 'DEFAULT',
164+
READWRITE: 'READWRITE',
165+
READONLY: 'READONLY',
166+
IMPORT: 'IMPORT',
167+
} as const satisfies Record<string, SchemaRegistryModeWithDefault>;
158168

159169
export const useUpdateGlobalModeMutation = () => {
160170
const queryClient = useQueryClient();
@@ -232,7 +242,7 @@ export const useUpdateSubjectCompatibilityMutation = () => {
232242
return useTanstackMutation<
233243
SchemaRegistryConfigResponse,
234244
Error,
235-
{ subjectName: string; mode: 'DEFAULT' | SchemaRegistryCompatibilityMode }
245+
{ subjectName: string; mode: SchemaRegistryCompatibilityModeWithDefault }
236246
>({
237247
mutationFn: async ({ subjectName, mode }) => {
238248
if (mode === 'DEFAULT') {
@@ -290,7 +300,7 @@ export const useUpdateSubjectCompatibilityMutation = () => {
290300
export const useUpdateSubjectModeMutation = () => {
291301
const queryClient = useQueryClient();
292302

293-
return useTanstackMutation<{ mode: string }, Error, { subjectName: string; mode: 'DEFAULT' | SchemaRegistryMode }>({
303+
return useTanstackMutation<{ mode: string }, Error, { subjectName: string; mode: SchemaRegistryModeWithDefault }>({
294304
mutationFn: async ({ subjectName, mode }) => {
295305
if (mode === 'DEFAULT') {
296306
const response = await fetch(`${config.restBasePath}/schema-registry/mode/${encodeURIComponent(subjectName)}`, {
@@ -344,7 +354,7 @@ export const useUpdateSubjectModeMutation = () => {
344354
export const useUpdateContextModeMutation = () => {
345355
const queryClient = useQueryClient();
346356

347-
return useTanstackMutation<{ mode: string }, Error, { contextName: string; mode: 'DEFAULT' | SchemaRegistryMode }>({
357+
return useTanstackMutation<{ mode: string }, Error, { contextName: string; mode: SchemaRegistryModeWithDefault }>({
348358
mutationFn: async ({ contextName, mode }) => {
349359
const qualifiedName = `:${contextName}:`;
350360
if (mode === 'DEFAULT') {
@@ -402,7 +412,7 @@ export const useUpdateContextCompatibilityMutation = () => {
402412
return useTanstackMutation<
403413
SchemaRegistryConfigResponse,
404414
Error,
405-
{ contextName: string; mode: 'DEFAULT' | SchemaRegistryCompatibilityMode }
415+
{ contextName: string; mode: SchemaRegistryCompatibilityModeWithDefault }
406416
>({
407417
mutationFn: async ({ contextName, mode }) => {
408418
const qualifiedName = `:${contextName}:`;

frontend/src/state/backend-api.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ import {
9191
type ResourceConfig,
9292
type SchemaReferencedByEntry,
9393
type SchemaRegistryCompatibilityMode,
94+
type SchemaRegistryCompatibilityModeWithDefault,
9495
type SchemaRegistryConfigResponse,
9596
type SchemaRegistryCreateSchema,
9697
type SchemaRegistryCreateSchemaResponse,
@@ -1465,7 +1466,7 @@ const _apiCreator = (set: any, get: any) => ({
14651466

14661467
async setSchemaRegistrySubjectCompatibilityMode(
14671468
subjectName: string,
1468-
mode: 'DEFAULT' | SchemaRegistryCompatibilityMode
1469+
mode: SchemaRegistryCompatibilityModeWithDefault
14691470
): Promise<SchemaRegistryConfigResponse> {
14701471
if (mode === 'DEFAULT') {
14711472
const response = await appConfig.fetch(

0 commit comments

Comments
 (0)