Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deleting schemas #366

Merged
merged 1 commit into from
Apr 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion kafka-ui-react-app/src/components/Schemas/Details/Details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { SchemaSubject } from 'generated-sources';
import { ClusterName, SchemaName } from 'redux/interfaces';
import { clusterSchemasPath } from 'lib/paths';
import ClusterContext from 'components/contexts/ClusterContext';
import { useHistory } from 'react-router';
import Breadcrumb from '../../common/Breadcrumb/Breadcrumb';
import SchemaVersion from './SchemaVersion';
import LatestVersionItem from './LatestVersionItem';
Expand All @@ -18,13 +19,15 @@ export interface DetailsProps {
clusterName: ClusterName,
schemaName: SchemaName
) => void;
deleteSchema: (clusterName: ClusterName, subject: string) => Promise<void>;
}

const Details: React.FC<DetailsProps> = ({
subject,
schema,
clusterName,
fetchSchemaVersions,
deleteSchema,
versions,
isFetched,
}) => {
Expand All @@ -33,6 +36,12 @@ const Details: React.FC<DetailsProps> = ({
fetchSchemaVersions(clusterName, subject);
}, [fetchSchemaVersions, clusterName]);

const history = useHistory();
const onDelete = async () => {
await deleteSchema(clusterName, subject);
history.push(clusterSchemasPath(clusterName));
};

return (
<div className="section">
<div className="level">
Expand Down Expand Up @@ -75,7 +84,7 @@ const Details: React.FC<DetailsProps> = ({
className="button is-danger is-small level-item"
type="button"
title="in development"
disabled
onClick={onDelete}
>
Delete
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
getSchema,
getSortedSchemaVersions,
} from 'redux/reducers/schemas/selectors';
import { fetchSchemaVersions } from 'redux/actions';
import { fetchSchemaVersions, deleteSchema } from 'redux/actions';
import Details from './Details';

interface RouteProps {
Expand All @@ -33,6 +33,7 @@ const mapStateToProps = (

const mapDispatchToProps = {
fetchSchemaVersions,
deleteSchema,
};

export default withRouter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe('Details', () => {
schema={schema}
clusterName="Test cluster"
fetchSchemaVersions={jest.fn()}
deleteSchema={jest.fn()}
isFetched
versions={[]}
{...props}
Expand Down Expand Up @@ -100,6 +101,17 @@ describe('Details', () => {
expect(wrapper.find('SchemaVersion').length).toEqual(2);
});

it('calls deleteSchema on button click', () => {
const mockDelete = jest.fn();
const component = mount(
<StaticRouter>
{setupWrapper({ versions, deleteSchema: mockDelete })}
</StaticRouter>
);
component.find('button').at(1).simulate('click');
expect(mockDelete).toHaveBeenCalledTimes(1);
});

it('matches snapshot', () => {
expect(shallow(setupWrapper({ versions }))).toMatchSnapshot();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ exports[`Details View Initial state matches snapshot 1`] = `
</button>
<button
className="button is-danger is-small level-item"
disabled={true}
onClick={[Function]}
title="in development"
type="button"
>
Expand Down Expand Up @@ -196,7 +196,7 @@ exports[`Details View when page with schema versions loaded when schema has vers
</button>
<button
className="button is-danger is-small level-item"
disabled={true}
onClick={[Function]}
title="in development"
type="button"
>
Expand Down Expand Up @@ -334,7 +334,7 @@ exports[`Details View when page with schema versions loaded when versions are em
</button>
<button
className="button is-danger is-small level-item"
disabled={true}
onClick={[Function]}
title="in development"
type="button"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,37 @@ describe('Thunks', () => {
}
});
});

describe('deleteSchema', () => {
it('fires DELETE_SCHEMA__SUCCESS on success', async () => {
fetchMock.deleteOnce(
`/api/clusters/${clusterName}/schemas/${subject}`,
200
);

await store.dispatch(thunks.deleteSchema(clusterName, subject));

expect(store.getActions()).toEqual([
actions.deleteSchemaAction.request(),
actions.deleteSchemaAction.success(subject),
]);
});

it('fires DELETE_SCHEMA__FAILURE on failure', async () => {
fetchMock.deleteOnce(
`/api/clusters/${clusterName}/schemas/${subject}`,
404
);

try {
await store.dispatch(thunks.deleteSchema(clusterName, subject));
} catch (error) {
expect(error.status).toEqual(404);
expect(store.getActions()).toEqual([
actions.deleteSchemaAction.request(),
actions.deleteSchemaAction.failure({}),
]);
}
});
});
});
6 changes: 6 additions & 0 deletions kafka-ui-react-app/src/redux/actions/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ export const createSchemaAction = createAsyncAction(
'POST_SCHEMA__FAILURE'
)<undefined, SchemaSubject, { alert?: FailurePayload }>();

export const deleteSchemaAction = createAsyncAction(
'DELETE_SCHEMA__REQUEST',
'DELETE_SCHEMA__SUCCESS',
'DELETE_SCHEMA__FAILURE'
)<undefined, string, { alert?: FailurePayload }>();

export const dismissAlert = createAction('DISMISS_ALERT')<string>();

export const fetchConnectsAction = createAsyncAction(
Expand Down
22 changes: 22 additions & 0 deletions kafka-ui-react-app/src/redux/actions/thunks/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,25 @@ export const createSchema = (
dispatch(actions.createSchemaAction.failure({ alert }));
}
};

export const deleteSchema = (
clusterName: ClusterName,
subject: string
): PromiseThunkResult => async (dispatch) => {
dispatch(actions.deleteSchemaAction.request());
try {
await schemasApiClient.deleteSchema({
clusterName,
subject,
});
dispatch(actions.deleteSchemaAction.success(subject));
} catch (error) {
const response = await getResponse(error);
const alert: FailurePayload = {
subject: ['schema', subject].join('-'),
title: `Schema ${subject}`,
response,
};
dispatch(actions.deleteSchemaAction.failure({ alert }));
}
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { SchemaSubject, SchemaType } from 'generated-sources';
import {
createSchemaAction,
deleteSchemaAction,
fetchSchemasByClusterNameAction,
fetchSchemaVersionsAction,
} from 'redux/actions';
Expand Down Expand Up @@ -46,4 +48,31 @@ describe('Schemas reducer', () => {
reducer(undefined, createSchemaAction.success(schemaVersionsPayload[0]))
).toMatchSnapshot();
});

it('deletes the schema from the list on DELETE_SCHEMA__SUCCESS', () => {
const schema: SchemaSubject = {
subject: 'name',
version: '1',
id: 1,
schema: '{}',
compatibilityLevel: 'BACKWARD',
schemaType: SchemaType.AVRO,
};
expect(
reducer(
{
byName: {
[schema.subject]: schema,
},
allNames: [schema.subject],
currentSchemaVersions: [],
},
deleteSchemaAction.success(schema.subject)
)
).toEqual({
byName: {},
allNames: [],
currentSchemaVersions: [],
});
});
});
16 changes: 16 additions & 0 deletions kafka-ui-react-app/src/redux/reducers/schemas/reducer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { SchemaSubject } from 'generated-sources';
import { Action, SchemasState } from 'redux/interfaces';
import * as actions from 'redux/actions';
import { getType } from 'typesafe-actions';

export const initialState: SchemasState = {
byName: {},
Expand Down Expand Up @@ -44,6 +46,18 @@ const addToSchemaList = (
return newState;
};

const deleteFromSchemaList = (
state: SchemasState,
payload: string
): SchemasState => {
const newState: SchemasState = {
...state,
};
delete newState.byName[payload];
newState.allNames = newState.allNames.filter((name) => name !== payload);
return newState;
};

const reducer = (state = initialState, action: Action): SchemasState => {
switch (action.type) {
case 'GET_CLUSTER_SCHEMAS__SUCCESS':
Expand All @@ -52,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 getType(actions.deleteSchemaAction.success):
return deleteFromSchemaList(state, action.payload);
default:
return state;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('topics reducer', () => {
reducer(
{
byName: {
topic,
[topic.name]: topic,
},
allNames: [topic.name],
messages: [],
Expand Down