Fix the problem with instant redirect (#390)
* Fix the problem with instant redirect * Rewrite updateSchema thunk
This commit is contained in:
parent
f3c0866940
commit
42a1c97686
12 changed files with 112 additions and 139 deletions
|
@ -33,6 +33,7 @@ const LatestVersionItem: React.FC<LatestVersionProps> = ({
|
|||
<div className="tile is-parent">
|
||||
<div className="tile is-child box">
|
||||
<JSONEditor
|
||||
isFixedHeight
|
||||
name="schema"
|
||||
value={JSON.stringify(JSON.parse(schema), null, '\t')}
|
||||
showGutter={false}
|
||||
|
|
|
@ -15,6 +15,7 @@ const SchemaVersion: React.FC<SchemaVersionProps> = ({
|
|||
<td>{id}</td>
|
||||
<td>
|
||||
<JSONEditor
|
||||
isFixedHeight
|
||||
name="schema"
|
||||
value={JSON.stringify(JSON.parse(schema), null, '\t')}
|
||||
showGutter={false}
|
||||
|
|
|
@ -49,6 +49,7 @@ exports[`LatestVersionItem matches snapshot 1`] = `
|
|||
className="tile is-child box"
|
||||
>
|
||||
<JSONEditor
|
||||
isFixedHeight={true}
|
||||
name="schema"
|
||||
readOnly={true}
|
||||
showGutter={false}
|
||||
|
|
|
@ -10,6 +10,7 @@ exports[`SchemaVersion matches snapshot 1`] = `
|
|||
</td>
|
||||
<td>
|
||||
<JSONEditor
|
||||
isFixedHeight={true}
|
||||
name="schema"
|
||||
readOnly={true}
|
||||
showGutter={false}
|
||||
|
|
|
@ -43,7 +43,7 @@ const Edit = ({
|
|||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
formState: { isSubmitting, isDirty },
|
||||
control,
|
||||
} = useForm<NewSchemaSubjectRaw>({ mode: 'onChange' });
|
||||
|
||||
|
@ -62,15 +62,19 @@ const Edit = ({
|
|||
compatibilityLevel: CompatibilityLevelCompatibilityEnum;
|
||||
newSchema: string;
|
||||
}) => {
|
||||
await updateSchema(
|
||||
schema,
|
||||
newSchema,
|
||||
schemaType,
|
||||
compatibilityLevel,
|
||||
clusterName,
|
||||
subject
|
||||
);
|
||||
history.push(clusterSchemaPath(clusterName, subject));
|
||||
try {
|
||||
await updateSchema(
|
||||
schema,
|
||||
newSchema,
|
||||
schemaType,
|
||||
compatibilityLevel,
|
||||
clusterName,
|
||||
subject
|
||||
);
|
||||
history.push(clusterSchemaPath(clusterName, subject));
|
||||
} catch (e) {
|
||||
// do not redirect
|
||||
}
|
||||
},
|
||||
[schema, register, control, clusterName, subject, updateSchema, history]
|
||||
);
|
||||
|
@ -96,7 +100,7 @@ const Edit = ({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{schemasAreFetched && !isSubmitting ? (
|
||||
{schemasAreFetched ? (
|
||||
<div className="box">
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
|
@ -111,6 +115,7 @@ const Edit = ({
|
|||
required: 'Schema Type is required.',
|
||||
})}
|
||||
defaultValue={schema.schemaType}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{Object.keys(SchemaType).map((type: string) => (
|
||||
<option key={type} value={type}>
|
||||
|
@ -128,6 +133,7 @@ const Edit = ({
|
|||
name="compatibilityLevel"
|
||||
ref={register()}
|
||||
defaultValue={schema.compatibilityLevel}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{Object.keys(CompatibilityLevelCompatibilityEnum).map(
|
||||
(level: string) => (
|
||||
|
@ -143,7 +149,9 @@ const Edit = ({
|
|||
<div className="column is-one-half">
|
||||
<h4 className="title is-5 mb-2">Latest Schema</h4>
|
||||
<JSONEditor
|
||||
isFixedHeight
|
||||
readOnly
|
||||
height="500px"
|
||||
value={getFormattedSchema()}
|
||||
name="latestSchema"
|
||||
highlightActiveLine={false}
|
||||
|
@ -154,8 +162,10 @@ const Edit = ({
|
|||
<Controller
|
||||
control={control}
|
||||
name="newSchema"
|
||||
disabled={isSubmitting}
|
||||
render={({ name, onChange }) => (
|
||||
<JSONEditor
|
||||
readOnly={isSubmitting}
|
||||
defaultValue={getFormattedSchema()}
|
||||
name={name}
|
||||
onChange={onChange}
|
||||
|
@ -164,7 +174,11 @@ const Edit = ({
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" className="button is-primary">
|
||||
<button
|
||||
type="submit"
|
||||
className="button is-primary"
|
||||
disabled={!isDirty || isSubmitting}
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</form>
|
||||
|
|
|
@ -48,6 +48,7 @@ exports[`Edit Component when schemas are fetched matches the snapshot 1`] = `
|
|||
>
|
||||
<select
|
||||
defaultValue="AVRO"
|
||||
disabled={false}
|
||||
name="schemaType"
|
||||
>
|
||||
<option
|
||||
|
@ -84,6 +85,7 @@ exports[`Edit Component when schemas are fetched matches the snapshot 1`] = `
|
|||
>
|
||||
<select
|
||||
defaultValue="BACKWARD"
|
||||
disabled={false}
|
||||
name="compatibilityLevel"
|
||||
>
|
||||
<option
|
||||
|
@ -143,7 +145,9 @@ exports[`Edit Component when schemas are fetched matches the snapshot 1`] = `
|
|||
Latest Schema
|
||||
</h4>
|
||||
<JSONEditor
|
||||
height="500px"
|
||||
highlightActiveLine={false}
|
||||
isFixedHeight={true}
|
||||
name="latestSchema"
|
||||
readOnly={true}
|
||||
value="{
|
||||
|
@ -261,6 +265,7 @@ exports[`Edit Component when schemas are fetched matches the snapshot 1`] = `
|
|||
"watchInternal": [Function],
|
||||
}
|
||||
}
|
||||
disabled={false}
|
||||
name="newSchema"
|
||||
render={[Function]}
|
||||
/>
|
||||
|
@ -268,6 +273,7 @@ exports[`Edit Component when schemas are fetched matches the snapshot 1`] = `
|
|||
</div>
|
||||
<button
|
||||
className="button is-primary"
|
||||
disabled={true}
|
||||
type="submit"
|
||||
>
|
||||
Submit
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { RootState } from 'redux/interfaces';
|
||||
import { createSchema } from 'redux/actions';
|
||||
import { getSchemaCreated } from 'redux/reducers/schemas/selectors';
|
||||
|
||||
import New from './New';
|
||||
|
||||
const mapStateToProps = (state: RootState) => ({
|
||||
isSchemaCreated: getSchemaCreated(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
createSchema,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(New);
|
||||
export default connect(null, mapDispatchToProps)(New);
|
||||
|
|
|
@ -4,15 +4,25 @@ import 'ace-builds/src-noconflict/mode-json5';
|
|||
import 'ace-builds/src-noconflict/theme-textmate';
|
||||
import React from 'react';
|
||||
|
||||
const JSONEditor: React.FC<IAceEditorProps> = (props) => (
|
||||
<AceEditor
|
||||
mode="json5"
|
||||
theme="textmate"
|
||||
tabSize={2}
|
||||
width="100%"
|
||||
wrapEnabled
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
interface JSONEditorProps extends IAceEditorProps {
|
||||
isFixedHeight?: boolean;
|
||||
}
|
||||
|
||||
const JSONEditor: React.FC<JSONEditorProps> = (props) => {
|
||||
const { isFixedHeight, value } = props;
|
||||
return (
|
||||
<AceEditor
|
||||
mode="json5"
|
||||
theme="textmate"
|
||||
tabSize={2}
|
||||
width="100%"
|
||||
height={
|
||||
isFixedHeight ? `${(value?.split('\n').length || 32) * 16}px` : '500px'
|
||||
}
|
||||
wrapEnabled
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default JSONEditor;
|
||||
|
|
|
@ -122,53 +122,22 @@ describe('Thunks', () => {
|
|||
expect(error.status).toEqual(404);
|
||||
expect(store.getActions()).toEqual([
|
||||
actions.createSchemaAction.request(),
|
||||
actions.createSchemaAction.failure({}),
|
||||
actions.createSchemaAction.failure({
|
||||
alert: {
|
||||
response: {
|
||||
body: undefined,
|
||||
status: 404,
|
||||
statusText: 'Not Found',
|
||||
},
|
||||
subject: 'schema-NewSchema',
|
||||
title: 'Schema NewSchema',
|
||||
},
|
||||
}),
|
||||
]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateSchemaCompatibilityLevel', () => {
|
||||
it('creates UPDATE_SCHEMA__SUCCESS when patching a schema', async () => {
|
||||
fetchMock.putOnce(
|
||||
`/api/clusters/${clusterName}/schemas/${subject}/compatibility`,
|
||||
200
|
||||
);
|
||||
await store.dispatch(
|
||||
thunks.updateSchemaCompatibilityLevel(
|
||||
clusterName,
|
||||
subject,
|
||||
CompatibilityLevelCompatibilityEnum.BACKWARD
|
||||
)
|
||||
);
|
||||
expect(store.getActions()).toEqual([
|
||||
actions.updateSchemaCompatibilityLevelAction.request(),
|
||||
actions.updateSchemaCompatibilityLevelAction.success(),
|
||||
]);
|
||||
});
|
||||
|
||||
it('creates UPDATE_SCHEMA__SUCCESS when failing to patch a schema', async () => {
|
||||
fetchMock.putOnce(
|
||||
`/api/clusters/${clusterName}/schemas/${subject}/compatibility`,
|
||||
404
|
||||
);
|
||||
try {
|
||||
await store.dispatch(
|
||||
thunks.updateSchemaCompatibilityLevel(
|
||||
clusterName,
|
||||
subject,
|
||||
CompatibilityLevelCompatibilityEnum.BACKWARD
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(store.getActions()).toEqual([
|
||||
actions.updateSchemaCompatibilityLevelAction.request(),
|
||||
actions.updateSchemaCompatibilityLevelAction.failure({}),
|
||||
]);
|
||||
}
|
||||
});
|
||||
});
|
||||
describe('deleteSchema', () => {
|
||||
it('fires DELETE_SCHEMA__SUCCESS on success', async () => {
|
||||
fetchMock.deleteOnce(
|
||||
|
@ -203,7 +172,7 @@ describe('Thunks', () => {
|
|||
});
|
||||
|
||||
describe('updateSchema', () => {
|
||||
it('calls createSchema', () => {
|
||||
it('calls PATCH_SCHEMA__REQUEST', () => {
|
||||
store.dispatch(
|
||||
thunks.updateSchema(
|
||||
fixtures.schema,
|
||||
|
@ -215,23 +184,7 @@ describe('Thunks', () => {
|
|||
)
|
||||
);
|
||||
expect(store.getActions()).toEqual([
|
||||
actions.createSchemaAction.request(),
|
||||
]);
|
||||
});
|
||||
|
||||
it('calls updateSchema and does not call createSchema when schema does not change', () => {
|
||||
store.dispatch(
|
||||
thunks.updateSchema(
|
||||
fixtures.schema,
|
||||
fixtures.schema.schema,
|
||||
SchemaType.JSON,
|
||||
CompatibilityLevelCompatibilityEnum.FORWARD,
|
||||
clusterName,
|
||||
subject
|
||||
)
|
||||
);
|
||||
expect(store.getActions()).toEqual([
|
||||
actions.updateSchemaCompatibilityLevelAction.request(),
|
||||
actions.updateSchemaAction.request(),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -130,11 +130,11 @@ export const createSchemaAction = createAsyncAction(
|
|||
'POST_SCHEMA__FAILURE'
|
||||
)<undefined, SchemaSubject, { alert?: FailurePayload }>();
|
||||
|
||||
export const updateSchemaCompatibilityLevelAction = createAsyncAction(
|
||||
'PATCH_SCHEMA_COMPATIBILITY__REQUEST',
|
||||
'PATCH_SCHEMA_COMPATIBILITY__SUCCESS',
|
||||
'PATCH_SCHEMA_COMPATIBILITY__FAILURE'
|
||||
)<undefined, undefined, { alert?: FailurePayload }>();
|
||||
export const updateSchemaAction = createAsyncAction(
|
||||
'PATCH_SCHEMA__REQUEST',
|
||||
'PATCH_SCHEMA__SUCCESS',
|
||||
'PATCH_SCHEMA__FAILURE'
|
||||
)<undefined, SchemaSubject, { alert?: FailurePayload }>();
|
||||
|
||||
export const deleteSchemaAction = createAsyncAction(
|
||||
'DELETE_SCHEMA__REQUEST',
|
||||
|
|
|
@ -68,32 +68,7 @@ export const createSchema = (
|
|||
response,
|
||||
};
|
||||
dispatch(actions.createSchemaAction.failure({ alert }));
|
||||
}
|
||||
};
|
||||
|
||||
export const updateSchemaCompatibilityLevel = (
|
||||
clusterName: ClusterName,
|
||||
subject: string,
|
||||
compatibilityLevel: CompatibilityLevelCompatibilityEnum
|
||||
): PromiseThunkResult => async (dispatch) => {
|
||||
dispatch(actions.updateSchemaCompatibilityLevelAction.request());
|
||||
try {
|
||||
await schemasApiClient.updateSchemaCompatibilityLevel({
|
||||
clusterName,
|
||||
subject,
|
||||
compatibilityLevel: {
|
||||
compatibility: compatibilityLevel,
|
||||
},
|
||||
});
|
||||
dispatch(actions.updateSchemaCompatibilityLevelAction.success());
|
||||
} catch (error) {
|
||||
const response = await getResponse(error);
|
||||
const alert: FailurePayload = {
|
||||
subject: 'compatibilityLevel',
|
||||
title: `Compatibility level ${subject}`,
|
||||
response,
|
||||
};
|
||||
dispatch(actions.updateSchemaCompatibilityLevelAction.failure({ alert }));
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -105,27 +80,42 @@ export const updateSchema = (
|
|||
clusterName: string,
|
||||
subject: string
|
||||
): PromiseThunkResult => async (dispatch) => {
|
||||
if (
|
||||
(newSchema &&
|
||||
!isEqual(JSON.parse(latestSchema.schema), JSON.parse(newSchema))) ||
|
||||
newSchemaType !== latestSchema.schemaType
|
||||
) {
|
||||
await dispatch(
|
||||
createSchema(clusterName, {
|
||||
...latestSchema,
|
||||
schema: newSchema || latestSchema.schema,
|
||||
schemaType: newSchemaType || latestSchema.schemaType,
|
||||
})
|
||||
);
|
||||
}
|
||||
if (newCompatibilityLevel !== latestSchema.compatibilityLevel) {
|
||||
await dispatch(
|
||||
updateSchemaCompatibilityLevel(
|
||||
dispatch(actions.updateSchemaAction.request());
|
||||
try {
|
||||
let schema: SchemaSubject = latestSchema;
|
||||
if (
|
||||
(newSchema &&
|
||||
!isEqual(JSON.parse(latestSchema.schema), JSON.parse(newSchema))) ||
|
||||
newSchemaType !== latestSchema.schemaType
|
||||
) {
|
||||
schema = await schemasApiClient.createNewSchema({
|
||||
clusterName,
|
||||
newSchemaSubject: {
|
||||
...latestSchema,
|
||||
schema: newSchema || latestSchema.schema,
|
||||
schemaType: newSchemaType || latestSchema.schemaType,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (newCompatibilityLevel !== latestSchema.compatibilityLevel) {
|
||||
await schemasApiClient.updateSchemaCompatibilityLevel({
|
||||
clusterName,
|
||||
subject,
|
||||
newCompatibilityLevel
|
||||
)
|
||||
);
|
||||
compatibilityLevel: {
|
||||
compatibility: newCompatibilityLevel,
|
||||
},
|
||||
});
|
||||
}
|
||||
actions.updateSchemaAction.success(schema);
|
||||
} catch (e) {
|
||||
const response = await getResponse(e);
|
||||
const alert: FailurePayload = {
|
||||
subject: ['schema', subject].join('-'),
|
||||
title: `Schema ${subject}`,
|
||||
response,
|
||||
};
|
||||
dispatch(actions.updateSchemaAction.failure({ alert }));
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
export const deleteSchema = (
|
||||
|
|
|
@ -66,6 +66,8 @@ const reducer = (state = initialState, action: Action): SchemasState => {
|
|||
return { ...state, currentSchemaVersions: action.payload };
|
||||
case 'POST_SCHEMA__SUCCESS':
|
||||
return addToSchemaList(state, action.payload);
|
||||
case 'PATCH_SCHEMA__SUCCESS':
|
||||
return addToSchemaList(state, action.payload);
|
||||
case getType(actions.deleteSchemaAction.success):
|
||||
return deleteFromSchemaList(state, action.payload);
|
||||
default:
|
||||
|
|
Loading…
Add table
Reference in a new issue