= ({
{internal ? 'Internal' : 'External'}
-
-
-
-
-
- }
- right
- >
-
- Clear Messages
-
- setDeleteTopicConfirmationVisible(true)}
+
+ {!internal ? (
+ <>
+
+
+
+
+ }
+ right
+ >
+
+ Clear Messages
+
+ setDeleteTopicConfirmationVisible(true)}
+ >
+ Remove Topic
+
+
+
+ setDeleteTopicConfirmationVisible(false)}
+ onConfirm={deleteTopicHandler}
>
- Remove Topic
-
-
-
- setDeleteTopicConfirmationVisible(false)}
- onConfirm={deleteTopicHandler}
- >
- Are you sure want to remove {name} topic?
-
+ Are you sure want to remove {name} topic?
+
+ >
+ ) : null}
|
);
diff --git a/kafka-ui-react-app/src/components/Topics/List/__tests__/ListItem.spec.tsx b/kafka-ui-react-app/src/components/Topics/List/__tests__/ListItem.spec.tsx
index 6aa399efa6..f652155374 100644
--- a/kafka-ui-react-app/src/components/Topics/List/__tests__/ListItem.spec.tsx
+++ b/kafka-ui-react-app/src/components/Topics/List/__tests__/ListItem.spec.tsx
@@ -28,28 +28,31 @@ describe('ListItem', () => {
);
it('triggers the deleting messages when clicked on the delete messages button', () => {
- const component = shallow(setupComponent());
+ const component = shallow(setupComponent({ topic: externalTopicPayload }));
+ expect(component.exists('.topic-action-block')).toBeTruthy();
component.find('DropdownItem').at(0).simulate('click');
expect(mockDeleteMessages).toBeCalledTimes(1);
expect(mockDeleteMessages).toBeCalledWith(
clusterName,
- internalTopicPayload.name
+ externalTopicPayload.name
);
});
it('triggers the deleteTopic when clicked on the delete button', () => {
- const wrapper = shallow(setupComponent());
+ const wrapper = shallow(setupComponent({ topic: externalTopicPayload }));
+ expect(wrapper.exists('.topic-action-block')).toBeTruthy();
expect(wrapper.find('mock-ConfirmationModal').prop('isOpen')).toBeFalsy();
wrapper.find('DropdownItem').at(1).simulate('click');
const modal = wrapper.find('mock-ConfirmationModal');
expect(modal.prop('isOpen')).toBeTruthy();
modal.simulate('confirm');
expect(mockDelete).toBeCalledTimes(1);
- expect(mockDelete).toBeCalledWith(clusterName, internalTopicPayload.name);
+ expect(mockDelete).toBeCalledWith(clusterName, externalTopicPayload.name);
});
it('closes ConfirmationModal when clicked on the cancel button', () => {
- const wrapper = shallow(setupComponent());
+ const wrapper = shallow(setupComponent({ topic: externalTopicPayload }));
+ expect(wrapper.exists('.topic-action-block')).toBeTruthy();
expect(wrapper.find('mock-ConfirmationModal').prop('isOpen')).toBeFalsy();
wrapper.find('DropdownItem').last().simulate('click');
expect(wrapper.find('mock-ConfirmationModal').prop('isOpen')).toBeTruthy();
diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Details.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Details/Details.tsx
index 379ffc53a6..62fcca3882 100644
--- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Details.tsx
+++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Details.tsx
@@ -19,6 +19,7 @@ import SettingsContainer from './Settings/SettingsContainer';
interface Props extends Topic, TopicDetails {
clusterName: ClusterName;
topicName: TopicName;
+ isInternal: boolean;
deleteTopic: (clusterName: ClusterName, topicName: TopicName) => void;
clearTopicMessages(clusterName: ClusterName, topicName: TopicName): void;
}
@@ -26,15 +27,14 @@ interface Props extends Topic, TopicDetails {
const Details: React.FC = ({
clusterName,
topicName,
+ isInternal,
deleteTopic,
clearTopicMessages,
}) => {
const history = useHistory();
const { isReadOnly } = React.useContext(ClusterContext);
- const [
- isDeleteTopicConfirmationVisible,
- setDeleteTopicConfirmationVisible,
- ] = React.useState(false);
+ const [isDeleteTopicConfirmationVisible, setDeleteTopicConfirmationVisible] =
+ React.useState(false);
const deleteTopicHandler = React.useCallback(() => {
deleteTopic(clusterName, topicName);
history.push(clusterTopicsPath(clusterName));
@@ -74,8 +74,8 @@ const Details: React.FC = ({
-
- {!isReadOnly && (
+ {!isReadOnly && !isInternal ? (
+
<>
+
+ ) : null}
diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/DetailsContainer.ts b/kafka-ui-react-app/src/components/Topics/Topic/Details/DetailsContainer.ts
index b704926fc8..475f138bd1 100644
--- a/kafka-ui-react-app/src/components/Topics/Topic/Details/DetailsContainer.ts
+++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/DetailsContainer.ts
@@ -2,6 +2,7 @@ import { connect } from 'react-redux';
import { ClusterName, RootState, TopicName } from 'redux/interfaces';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { deleteTopic, clearTopicMessages } from 'redux/actions';
+import { getIsTopicInternal } from 'redux/reducers/topics/selectors';
import Details from './Details';
@@ -22,6 +23,7 @@ const mapStateToProps = (
) => ({
clusterName,
topicName,
+ isInternal: getIsTopicInternal(state, topicName),
});
const mapDispatchToProps = {
diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Messages.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Messages.tsx
index fd0d4499f8..034d942c68 100644
--- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Messages.tsx
+++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Messages.tsx
@@ -50,9 +50,8 @@ const Messages: React.FC = ({
fetchTopicMessages,
}) => {
const [searchQuery, setSearchQuery] = React.useState('');
- const [searchTimestamp, setSearchTimestamp] = React.useState(
- null
- );
+ const [searchTimestamp, setSearchTimestamp] =
+ React.useState(null);
const [filterProps, setFilterProps] = React.useState([]);
const [selectedSeekType, setSelectedSeekType] = React.useState(
SeekType.OFFSET
diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/Overview.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/Overview.tsx
index 02f235475b..52811ac353 100644
--- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/Overview.tsx
+++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/Overview.tsx
@@ -75,22 +75,24 @@ const Overview: React.FC = ({
{offsetMin} |
{offsetMax} |
-
-
-
- }
- right
- >
-
- clearTopicMessages(clusterName, topicName, [partition])
+ {!internal ? (
+
+
+
}
+ right
>
- Clear Messages
-
-
+
+ clearTopicMessages(clusterName, topicName, [partition])
+ }
+ >
+ Clear Messages
+
+
+ ) : null}
|
))}
diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/__test__/Overview.spec.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/__test__/Overview.spec.tsx
new file mode 100644
index 0000000000..824e327fb5
--- /dev/null
+++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/__test__/Overview.spec.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import Overview from 'components/Topics/Topic/Details/Overview/Overview';
+
+describe('Overview', () => {
+ const mockInternal = false;
+ const mockClusterName = 'local';
+ const mockTopicName = 'topic';
+ const mockClearTopicMessages = jest.fn();
+ const mockPartitions = [
+ {
+ partition: 1,
+ leader: 1,
+ replicas: [
+ {
+ broker: 1,
+ leader: false,
+ inSync: true,
+ },
+ ],
+ offsetMax: 0,
+ offsetMin: 0,
+ },
+ ];
+
+ describe('when it has internal flag', () => {
+ it('does not render the Action button a Topic', () => {
+ const component = shallow(
+
+ );
+
+ expect(component.exists('Dropdown')).toBeTruthy();
+ });
+ });
+});
diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/__test__/Details.spec.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Details/__test__/Details.spec.tsx
new file mode 100644
index 0000000000..a32b88a95e
--- /dev/null
+++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/__test__/Details.spec.tsx
@@ -0,0 +1,71 @@
+import React from 'react';
+import { mount } from 'enzyme';
+import { StaticRouter } from 'react-router-dom';
+import ClusterContext from 'components/contexts/ClusterContext';
+import Details from 'components/Topics/Topic/Details/Details';
+import {
+ internalTopicPayload,
+ externalTopicPayload,
+} from 'redux/reducers/topics/__test__/fixtures';
+
+describe('Details', () => {
+ const mockDelete = jest.fn();
+ const mockClusterName = 'local';
+ const mockClearTopicMessages = jest.fn();
+ const mockInternalTopicPayload = internalTopicPayload.internal;
+ const mockExternalTopicPayload = externalTopicPayload.internal;
+
+ describe('when it has readonly flag', () => {
+ it('does not render the Action button a Topic', () => {
+ const component = mount(
+
+
+
+
+
+ );
+
+ expect(component.exists('button')).toBeFalsy();
+ });
+ });
+
+ describe('when it does not have readonly flag', () => {
+ it('renders the Action button a Topic', () => {
+ const component = mount(
+
+
+
+
+
+ );
+
+ expect(component.exists('button')).toBeTruthy();
+ });
+ });
+});
diff --git a/kafka-ui-react-app/src/components/Topics/shared/Form/CustomParams/CustomParamSelect.tsx b/kafka-ui-react-app/src/components/Topics/shared/Form/CustomParams/CustomParamSelect.tsx
index 31965e372b..2eb11cf8b5 100644
--- a/kafka-ui-react-app/src/components/Topics/shared/Form/CustomParams/CustomParamSelect.tsx
+++ b/kafka-ui-react-app/src/components/Topics/shared/Form/CustomParams/CustomParamSelect.tsx
@@ -39,12 +39,11 @@ const CustomParamSelect: React.FC = ({
return valid || 'Custom Parameter must be unique';
};
- const onChange = (inputName: string) => (
- event: React.ChangeEvent
- ) => {
- trigger(inputName);
- onNameChange(index, event.target.value);
- };
+ const onChange =
+ (inputName: string) => (event: React.ChangeEvent) => {
+ trigger(inputName);
+ onNameChange(index, event.target.value);
+ };
return (
<>
diff --git a/kafka-ui-react-app/src/components/Topics/shared/Form/CustomParams/CustomParams.tsx b/kafka-ui-react-app/src/components/Topics/shared/Form/CustomParams/CustomParams.tsx
index 570d0154f4..f05e33382a 100644
--- a/kafka-ui-react-app/src/components/Topics/shared/Form/CustomParams/CustomParams.tsx
+++ b/kafka-ui-react-app/src/components/Topics/shared/Form/CustomParams/CustomParams.tsx
@@ -35,13 +35,11 @@ const CustomParams: React.FC = ({ isSubmitting, config }) => {
)
: {};
- const [
- formCustomParams,
- setFormCustomParams,
- ] = React.useState({
- byIndex,
- allIndexes: Object.keys(byIndex),
- });
+ const [formCustomParams, setFormCustomParams] =
+ React.useState({
+ byIndex,
+ allIndexes: Object.keys(byIndex),
+ });
const onAdd = (event: React.MouseEvent) => {
event.preventDefault();
diff --git a/kafka-ui-react-app/src/redux/actions/thunks/brokers.ts b/kafka-ui-react-app/src/redux/actions/thunks/brokers.ts
index f698f45c29..025929b08f 100644
--- a/kafka-ui-react-app/src/redux/actions/thunks/brokers.ts
+++ b/kafka-ui-react-app/src/redux/actions/thunks/brokers.ts
@@ -6,30 +6,29 @@ import * as actions from 'redux/actions/actions';
const apiClientConf = new Configuration(BASE_PARAMS);
export const brokersApiClient = new BrokersApi(apiClientConf);
-export const fetchBrokers = (
- clusterName: ClusterName
-): PromiseThunkResult => async (dispatch) => {
- dispatch(actions.fetchBrokersAction.request());
- try {
- const payload = await brokersApiClient.getBrokers({ clusterName });
- dispatch(actions.fetchBrokersAction.success(payload));
- } catch (e) {
- dispatch(actions.fetchBrokersAction.failure());
- }
-};
+export const fetchBrokers =
+ (clusterName: ClusterName): PromiseThunkResult =>
+ async (dispatch) => {
+ dispatch(actions.fetchBrokersAction.request());
+ try {
+ const payload = await brokersApiClient.getBrokers({ clusterName });
+ dispatch(actions.fetchBrokersAction.success(payload));
+ } catch (e) {
+ dispatch(actions.fetchBrokersAction.failure());
+ }
+ };
-export const fetchBrokerMetrics = (
- clusterName: ClusterName,
- brokerId: BrokerId
-): PromiseThunkResult => async (dispatch) => {
- dispatch(actions.fetchBrokerMetricsAction.request());
- try {
- const payload = await brokersApiClient.getBrokersMetrics({
- clusterName,
- id: brokerId,
- });
- dispatch(actions.fetchBrokerMetricsAction.success(payload));
- } catch (e) {
- dispatch(actions.fetchBrokerMetricsAction.failure());
- }
-};
+export const fetchBrokerMetrics =
+ (clusterName: ClusterName, brokerId: BrokerId): PromiseThunkResult =>
+ async (dispatch) => {
+ dispatch(actions.fetchBrokerMetricsAction.request());
+ try {
+ const payload = await brokersApiClient.getBrokersMetrics({
+ clusterName,
+ id: brokerId,
+ });
+ dispatch(actions.fetchBrokerMetricsAction.success(payload));
+ } catch (e) {
+ dispatch(actions.fetchBrokerMetricsAction.failure());
+ }
+ };
diff --git a/kafka-ui-react-app/src/redux/actions/thunks/clusters.ts b/kafka-ui-react-app/src/redux/actions/thunks/clusters.ts
index 8d7f2030e7..14d04b01f8 100644
--- a/kafka-ui-react-app/src/redux/actions/thunks/clusters.ts
+++ b/kafka-ui-react-app/src/redux/actions/thunks/clusters.ts
@@ -16,26 +16,28 @@ export const fetchClustersList = (): PromiseThunkResult => async (dispatch) => {
}
};
-export const fetchClusterStats = (
- clusterName: ClusterName
-): PromiseThunkResult => async (dispatch) => {
- dispatch(actions.fetchClusterStatsAction.request());
- try {
- const payload = await clustersApiClient.getClusterStats({ clusterName });
- dispatch(actions.fetchClusterStatsAction.success(payload));
- } catch (e) {
- dispatch(actions.fetchClusterStatsAction.failure());
- }
-};
+export const fetchClusterStats =
+ (clusterName: ClusterName): PromiseThunkResult =>
+ async (dispatch) => {
+ dispatch(actions.fetchClusterStatsAction.request());
+ try {
+ const payload = await clustersApiClient.getClusterStats({ clusterName });
+ dispatch(actions.fetchClusterStatsAction.success(payload));
+ } catch (e) {
+ dispatch(actions.fetchClusterStatsAction.failure());
+ }
+ };
-export const fetchClusterMetrics = (
- clusterName: ClusterName
-): PromiseThunkResult => async (dispatch) => {
- dispatch(actions.fetchClusterMetricsAction.request());
- try {
- const payload = await clustersApiClient.getClusterMetrics({ clusterName });
- dispatch(actions.fetchClusterMetricsAction.success(payload));
- } catch (e) {
- dispatch(actions.fetchClusterMetricsAction.failure());
- }
-};
+export const fetchClusterMetrics =
+ (clusterName: ClusterName): PromiseThunkResult =>
+ async (dispatch) => {
+ dispatch(actions.fetchClusterMetricsAction.request());
+ try {
+ const payload = await clustersApiClient.getClusterMetrics({
+ clusterName,
+ });
+ dispatch(actions.fetchClusterMetricsAction.success(payload));
+ } catch (e) {
+ dispatch(actions.fetchClusterMetricsAction.failure());
+ }
+ };
diff --git a/kafka-ui-react-app/src/redux/actions/thunks/consumerGroups.ts b/kafka-ui-react-app/src/redux/actions/thunks/consumerGroups.ts
index 4a5445cb3b..37ce7b9aed 100644
--- a/kafka-ui-react-app/src/redux/actions/thunks/consumerGroups.ts
+++ b/kafka-ui-react-app/src/redux/actions/thunks/consumerGroups.ts
@@ -10,39 +10,40 @@ import * as actions from 'redux/actions/actions';
const apiClientConf = new Configuration(BASE_PARAMS);
export const consumerGroupsApiClient = new ConsumerGroupsApi(apiClientConf);
-export const fetchConsumerGroupsList = (
- clusterName: ClusterName
-): PromiseThunkResult => async (dispatch) => {
- dispatch(actions.fetchConsumerGroupsAction.request());
- try {
- const consumerGroups = await consumerGroupsApiClient.getConsumerGroups({
- clusterName,
- });
- dispatch(actions.fetchConsumerGroupsAction.success(consumerGroups));
- } catch (e) {
- dispatch(actions.fetchConsumerGroupsAction.failure());
- }
-};
-
-export const fetchConsumerGroupDetails = (
- clusterName: ClusterName,
- consumerGroupID: ConsumerGroupID
-): PromiseThunkResult => async (dispatch) => {
- dispatch(actions.fetchConsumerGroupDetailsAction.request());
- try {
- const consumerGroupDetails = await consumerGroupsApiClient.getConsumerGroup(
- {
+export const fetchConsumerGroupsList =
+ (clusterName: ClusterName): PromiseThunkResult =>
+ async (dispatch) => {
+ dispatch(actions.fetchConsumerGroupsAction.request());
+ try {
+ const consumerGroups = await consumerGroupsApiClient.getConsumerGroups({
clusterName,
- id: consumerGroupID,
- }
- );
- dispatch(
- actions.fetchConsumerGroupDetailsAction.success({
- consumerGroupID,
- details: consumerGroupDetails,
- })
- );
- } catch (e) {
- dispatch(actions.fetchConsumerGroupDetailsAction.failure());
- }
-};
+ });
+ dispatch(actions.fetchConsumerGroupsAction.success(consumerGroups));
+ } catch (e) {
+ dispatch(actions.fetchConsumerGroupsAction.failure());
+ }
+ };
+
+export const fetchConsumerGroupDetails =
+ (
+ clusterName: ClusterName,
+ consumerGroupID: ConsumerGroupID
+ ): PromiseThunkResult =>
+ async (dispatch) => {
+ dispatch(actions.fetchConsumerGroupDetailsAction.request());
+ try {
+ const consumerGroupDetails =
+ await consumerGroupsApiClient.getConsumerGroup({
+ clusterName,
+ id: consumerGroupID,
+ });
+ dispatch(
+ actions.fetchConsumerGroupDetailsAction.success({
+ consumerGroupID,
+ details: consumerGroupDetails,
+ })
+ );
+ } catch (e) {
+ dispatch(actions.fetchConsumerGroupDetailsAction.failure());
+ }
+ };
diff --git a/kafka-ui-react-app/src/redux/actions/thunks/schemas.ts b/kafka-ui-react-app/src/redux/actions/thunks/schemas.ts
index bc98688afb..03f1c20960 100644
--- a/kafka-ui-react-app/src/redux/actions/thunks/schemas.ts
+++ b/kafka-ui-react-app/src/redux/actions/thunks/schemas.ts
@@ -20,160 +20,164 @@ import { isEqual } from 'lodash';
const apiClientConf = new Configuration(BASE_PARAMS);
export const schemasApiClient = new SchemasApi(apiClientConf);
-export const fetchSchemasByClusterName = (
- clusterName: ClusterName
-): PromiseThunkResult => async (dispatch) => {
- dispatch(actions.fetchSchemasByClusterNameAction.request());
- try {
- const schemas = await schemasApiClient.getSchemas({ clusterName });
- dispatch(actions.fetchSchemasByClusterNameAction.success(schemas));
- } catch (e) {
- dispatch(actions.fetchSchemasByClusterNameAction.failure());
- }
-};
-
-export const fetchSchemaVersions = (
- clusterName: ClusterName,
- subject: SchemaName
-): PromiseThunkResult => async (dispatch) => {
- if (!subject) return;
- dispatch(actions.fetchSchemaVersionsAction.request());
- try {
- const versions = await schemasApiClient.getAllVersionsBySubject({
- clusterName,
- subject,
- });
- dispatch(actions.fetchSchemaVersionsAction.success(versions));
- } catch (e) {
- dispatch(actions.fetchSchemaVersionsAction.failure());
- }
-};
-
-export const fetchGlobalSchemaCompatibilityLevel = (
- clusterName: ClusterName
-): PromiseThunkResult => async (dispatch) => {
- dispatch(actions.fetchGlobalSchemaCompatibilityLevelAction.request());
- try {
- const result = await schemasApiClient.getGlobalSchemaCompatibilityLevel({
- clusterName,
- });
- dispatch(
- actions.fetchGlobalSchemaCompatibilityLevelAction.success(
- result.compatibility
- )
- );
- } catch (e) {
- dispatch(actions.fetchGlobalSchemaCompatibilityLevelAction.failure());
- }
-};
-
-export const updateGlobalSchemaCompatibilityLevel = (
- clusterName: ClusterName,
- compatibilityLevel: CompatibilityLevelCompatibilityEnum
-): PromiseThunkResult => async (dispatch) => {
- dispatch(actions.updateGlobalSchemaCompatibilityLevelAction.request());
- try {
- await schemasApiClient.updateGlobalSchemaCompatibilityLevel({
- clusterName,
- compatibilityLevel: { compatibility: compatibilityLevel },
- });
- dispatch(
- actions.updateGlobalSchemaCompatibilityLevelAction.success(
- compatibilityLevel
- )
- );
- } catch (e) {
- dispatch(actions.updateGlobalSchemaCompatibilityLevelAction.failure());
- }
-};
-
-export const createSchema = (
- clusterName: ClusterName,
- newSchemaSubject: NewSchemaSubject
-): PromiseThunkResult => async (dispatch) => {
- dispatch(actions.createSchemaAction.request());
- try {
- const schema: SchemaSubject = await schemasApiClient.createNewSchema({
- clusterName,
- newSchemaSubject,
- });
- dispatch(actions.createSchemaAction.success(schema));
- } catch (error) {
- const response = await getResponse(error);
- const alert: FailurePayload = {
- subject: ['schema', newSchemaSubject.subject].join('-'),
- title: `Schema ${newSchemaSubject.subject}`,
- response,
- };
- dispatch(actions.createSchemaAction.failure({ alert }));
- throw error;
- }
-};
-
-export const updateSchema = (
- latestSchema: SchemaSubject,
- newSchema: string,
- newSchemaType: SchemaType,
- newCompatibilityLevel: CompatibilityLevelCompatibilityEnum,
- clusterName: string,
- subject: string
-): PromiseThunkResult => async (dispatch) => {
- 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,
- },
- });
+export const fetchSchemasByClusterName =
+ (clusterName: ClusterName): PromiseThunkResult =>
+ async (dispatch) => {
+ dispatch(actions.fetchSchemasByClusterNameAction.request());
+ try {
+ const schemas = await schemasApiClient.getSchemas({ clusterName });
+ dispatch(actions.fetchSchemasByClusterNameAction.success(schemas));
+ } catch (e) {
+ dispatch(actions.fetchSchemasByClusterNameAction.failure());
}
- if (newCompatibilityLevel !== latestSchema.compatibilityLevel) {
- await schemasApiClient.updateSchemaCompatibilityLevel({
+ };
+
+export const fetchSchemaVersions =
+ (clusterName: ClusterName, subject: SchemaName): PromiseThunkResult =>
+ async (dispatch) => {
+ if (!subject) return;
+ dispatch(actions.fetchSchemaVersionsAction.request());
+ try {
+ const versions = await schemasApiClient.getAllVersionsBySubject({
clusterName,
subject,
- compatibilityLevel: {
- compatibility: newCompatibilityLevel,
- },
});
+ dispatch(actions.fetchSchemaVersionsAction.success(versions));
+ } catch (e) {
+ dispatch(actions.fetchSchemaVersionsAction.failure());
}
- 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 = (
- 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 }));
- }
-};
+ };
+
+export const fetchGlobalSchemaCompatibilityLevel =
+ (clusterName: ClusterName): PromiseThunkResult =>
+ async (dispatch) => {
+ dispatch(actions.fetchGlobalSchemaCompatibilityLevelAction.request());
+ try {
+ const result = await schemasApiClient.getGlobalSchemaCompatibilityLevel({
+ clusterName,
+ });
+ dispatch(
+ actions.fetchGlobalSchemaCompatibilityLevelAction.success(
+ result.compatibility
+ )
+ );
+ } catch (e) {
+ dispatch(actions.fetchGlobalSchemaCompatibilityLevelAction.failure());
+ }
+ };
+
+export const updateGlobalSchemaCompatibilityLevel =
+ (
+ clusterName: ClusterName,
+ compatibilityLevel: CompatibilityLevelCompatibilityEnum
+ ): PromiseThunkResult =>
+ async (dispatch) => {
+ dispatch(actions.updateGlobalSchemaCompatibilityLevelAction.request());
+ try {
+ await schemasApiClient.updateGlobalSchemaCompatibilityLevel({
+ clusterName,
+ compatibilityLevel: { compatibility: compatibilityLevel },
+ });
+ dispatch(
+ actions.updateGlobalSchemaCompatibilityLevelAction.success(
+ compatibilityLevel
+ )
+ );
+ } catch (e) {
+ dispatch(actions.updateGlobalSchemaCompatibilityLevelAction.failure());
+ }
+ };
+
+export const createSchema =
+ (
+ clusterName: ClusterName,
+ newSchemaSubject: NewSchemaSubject
+ ): PromiseThunkResult =>
+ async (dispatch) => {
+ dispatch(actions.createSchemaAction.request());
+ try {
+ const schema: SchemaSubject = await schemasApiClient.createNewSchema({
+ clusterName,
+ newSchemaSubject,
+ });
+ dispatch(actions.createSchemaAction.success(schema));
+ } catch (error) {
+ const response = await getResponse(error);
+ const alert: FailurePayload = {
+ subject: ['schema', newSchemaSubject.subject].join('-'),
+ title: `Schema ${newSchemaSubject.subject}`,
+ response,
+ };
+ dispatch(actions.createSchemaAction.failure({ alert }));
+ throw error;
+ }
+ };
+
+export const updateSchema =
+ (
+ latestSchema: SchemaSubject,
+ newSchema: string,
+ newSchemaType: SchemaType,
+ newCompatibilityLevel: CompatibilityLevelCompatibilityEnum,
+ clusterName: string,
+ subject: string
+ ): PromiseThunkResult =>
+ async (dispatch) => {
+ 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,
+ 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 =
+ (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 }));
+ }
+ };
diff --git a/kafka-ui-react-app/src/redux/actions/thunks/topics.ts b/kafka-ui-react-app/src/redux/actions/thunks/topics.ts
index 7ce6bbe6a9..22e9fb359e 100644
--- a/kafka-ui-react-app/src/redux/actions/thunks/topics.ts
+++ b/kafka-ui-react-app/src/redux/actions/thunks/topics.ts
@@ -32,136 +32,138 @@ export interface FetchTopicsListParams {
perPage?: number;
}
-export const fetchTopicsList = (
- params: FetchTopicsListParams
-): PromiseThunkResult => async (dispatch, getState) => {
- dispatch(actions.fetchTopicsListAction.request());
- try {
- const { topics, pageCount } = await topicsApiClient.getTopics(params);
- const newState = (topics || []).reduce(
- (memo: TopicsState, topic) => ({
- ...memo,
+export const fetchTopicsList =
+ (params: FetchTopicsListParams): PromiseThunkResult =>
+ async (dispatch, getState) => {
+ dispatch(actions.fetchTopicsListAction.request());
+ try {
+ const { topics, pageCount } = await topicsApiClient.getTopics(params);
+ const newState = (topics || []).reduce(
+ (memo: TopicsState, topic) => ({
+ ...memo,
+ byName: {
+ ...memo.byName,
+ [topic.name]: {
+ ...memo.byName[topic.name],
+ ...topic,
+ id: v4(),
+ },
+ },
+ allNames: [...memo.allNames, topic.name],
+ }),
+ {
+ ...getState().topics,
+ allNames: [],
+ totalPages: pageCount || 1,
+ }
+ );
+ dispatch(actions.fetchTopicsListAction.success(newState));
+ } catch (e) {
+ dispatch(actions.fetchTopicsListAction.failure());
+ }
+ };
+
+export const fetchTopicMessages =
+ (
+ clusterName: ClusterName,
+ topicName: TopicName,
+ queryParams: Partial
+ ): PromiseThunkResult =>
+ async (dispatch) => {
+ dispatch(actions.fetchTopicMessagesAction.request());
+ try {
+ const messages = await messagesApiClient.getTopicMessages({
+ clusterName,
+ topicName,
+ ...queryParams,
+ });
+ dispatch(actions.fetchTopicMessagesAction.success(messages));
+ } catch (e) {
+ dispatch(actions.fetchTopicMessagesAction.failure());
+ }
+ };
+
+export const clearTopicMessages =
+ (
+ clusterName: ClusterName,
+ topicName: TopicName,
+ partitions?: number[]
+ ): PromiseThunkResult =>
+ async (dispatch) => {
+ dispatch(actions.clearMessagesTopicAction.request());
+ try {
+ await messagesApiClient.deleteTopicMessages({
+ clusterName,
+ topicName,
+ partitions,
+ });
+ dispatch(actions.clearMessagesTopicAction.success(topicName));
+ } catch (e) {
+ const response = await getResponse(e);
+ const alert: FailurePayload = {
+ subject: [clusterName, topicName, partitions].join('-'),
+ title: `Clear Topic Messages`,
+ response,
+ };
+ dispatch(actions.clearMessagesTopicAction.failure({ alert }));
+ }
+ };
+
+export const fetchTopicDetails =
+ (clusterName: ClusterName, topicName: TopicName): PromiseThunkResult =>
+ async (dispatch, getState) => {
+ dispatch(actions.fetchTopicDetailsAction.request());
+ try {
+ const topicDetails = await topicsApiClient.getTopicDetails({
+ clusterName,
+ topicName,
+ });
+ const state = getState().topics;
+ const newState = {
+ ...state,
byName: {
- ...memo.byName,
- [topic.name]: {
- ...memo.byName[topic.name],
- ...topic,
- id: v4(),
+ ...state.byName,
+ [topicName]: {
+ ...state.byName[topicName],
+ ...topicDetails,
},
},
- allNames: [...memo.allNames, topic.name],
- }),
- {
- ...getState().topics,
- allNames: [],
- totalPages: pageCount || 1,
- }
- );
- dispatch(actions.fetchTopicsListAction.success(newState));
- } catch (e) {
- dispatch(actions.fetchTopicsListAction.failure());
- }
-};
+ };
+ dispatch(actions.fetchTopicDetailsAction.success(newState));
+ } catch (e) {
+ dispatch(actions.fetchTopicDetailsAction.failure());
+ }
+ };
-export const fetchTopicMessages = (
- clusterName: ClusterName,
- topicName: TopicName,
- queryParams: Partial
-): PromiseThunkResult => async (dispatch) => {
- dispatch(actions.fetchTopicMessagesAction.request());
- try {
- const messages = await messagesApiClient.getTopicMessages({
- clusterName,
- topicName,
- ...queryParams,
- });
- dispatch(actions.fetchTopicMessagesAction.success(messages));
- } catch (e) {
- dispatch(actions.fetchTopicMessagesAction.failure());
- }
-};
+export const fetchTopicConfig =
+ (clusterName: ClusterName, topicName: TopicName): PromiseThunkResult =>
+ async (dispatch, getState) => {
+ dispatch(actions.fetchTopicConfigAction.request());
+ try {
+ const config = await topicsApiClient.getTopicConfigs({
+ clusterName,
+ topicName,
+ });
-export const clearTopicMessages = (
- clusterName: ClusterName,
- topicName: TopicName,
- partitions?: number[]
-): PromiseThunkResult => async (dispatch) => {
- dispatch(actions.clearMessagesTopicAction.request());
- try {
- await messagesApiClient.deleteTopicMessages({
- clusterName,
- topicName,
- partitions,
- });
- dispatch(actions.clearMessagesTopicAction.success(topicName));
- } catch (e) {
- const response = await getResponse(e);
- const alert: FailurePayload = {
- subject: [clusterName, topicName, partitions].join('-'),
- title: `Clear Topic Messages`,
- response,
- };
- dispatch(actions.clearMessagesTopicAction.failure({ alert }));
- }
-};
-
-export const fetchTopicDetails = (
- clusterName: ClusterName,
- topicName: TopicName
-): PromiseThunkResult => async (dispatch, getState) => {
- dispatch(actions.fetchTopicDetailsAction.request());
- try {
- const topicDetails = await topicsApiClient.getTopicDetails({
- clusterName,
- topicName,
- });
- const state = getState().topics;
- const newState = {
- ...state,
- byName: {
- ...state.byName,
- [topicName]: {
- ...state.byName[topicName],
- ...topicDetails,
+ const state = getState().topics;
+ const newState = {
+ ...state,
+ byName: {
+ ...state.byName,
+ [topicName]: {
+ ...state.byName[topicName],
+ config: config.map((inputConfig) => ({
+ ...inputConfig,
+ })),
+ },
},
- },
- };
- dispatch(actions.fetchTopicDetailsAction.success(newState));
- } catch (e) {
- dispatch(actions.fetchTopicDetailsAction.failure());
- }
-};
+ };
-export const fetchTopicConfig = (
- clusterName: ClusterName,
- topicName: TopicName
-): PromiseThunkResult => async (dispatch, getState) => {
- dispatch(actions.fetchTopicConfigAction.request());
- try {
- const config = await topicsApiClient.getTopicConfigs({
- clusterName,
- topicName,
- });
-
- const state = getState().topics;
- const newState = {
- ...state,
- byName: {
- ...state.byName,
- [topicName]: {
- ...state.byName[topicName],
- config: config.map((inputConfig) => ({
- ...inputConfig,
- })),
- },
- },
- };
-
- dispatch(actions.fetchTopicConfigAction.success(newState));
- } catch (e) {
- dispatch(actions.fetchTopicConfigAction.failure());
- }
-};
+ dispatch(actions.fetchTopicConfigAction.success(newState));
+ } catch (e) {
+ dispatch(actions.fetchTopicConfigAction.failure());
+ }
+ };
const formatTopicCreation = (form: TopicFormDataRaw): TopicCreation => {
const {
@@ -229,84 +231,84 @@ const formatTopicUpdate = (form: TopicFormDataRaw): TopicUpdate => {
};
};
-export const createTopic = (
- clusterName: ClusterName,
- form: TopicFormDataRaw
-): PromiseThunkResult => async (dispatch, getState) => {
- dispatch(actions.createTopicAction.request());
- try {
- const topic: Topic = await topicsApiClient.createTopic({
- clusterName,
- topicCreation: formatTopicCreation(form),
- });
+export const createTopic =
+ (clusterName: ClusterName, form: TopicFormDataRaw): PromiseThunkResult =>
+ async (dispatch, getState) => {
+ dispatch(actions.createTopicAction.request());
+ try {
+ const topic: Topic = await topicsApiClient.createTopic({
+ clusterName,
+ topicCreation: formatTopicCreation(form),
+ });
- const state = getState().topics;
- const newState = {
- ...state,
- byName: {
- ...state.byName,
- [topic.name]: {
- ...topic,
+ const state = getState().topics;
+ const newState = {
+ ...state,
+ byName: {
+ ...state.byName,
+ [topic.name]: {
+ ...topic,
+ },
},
- },
- allNames: [...state.allNames, topic.name],
- };
+ allNames: [...state.allNames, topic.name],
+ };
- dispatch(actions.createTopicAction.success(newState));
- } catch (error) {
- const response = await getResponse(error);
- const alert: FailurePayload = {
- subject: ['schema', form.name].join('-'),
- title: `Schema ${form.name}`,
- response,
- };
- dispatch(actions.createTopicAction.failure({ alert }));
- }
-};
+ dispatch(actions.createTopicAction.success(newState));
+ } catch (error) {
+ const response = await getResponse(error);
+ const alert: FailurePayload = {
+ subject: ['schema', form.name].join('-'),
+ title: `Schema ${form.name}`,
+ response,
+ };
+ dispatch(actions.createTopicAction.failure({ alert }));
+ }
+ };
-export const updateTopic = (
- clusterName: ClusterName,
- topicName: TopicName,
- form: TopicFormDataRaw
-): PromiseThunkResult => async (dispatch, getState) => {
- dispatch(actions.updateTopicAction.request());
- try {
- const topic: Topic = await topicsApiClient.updateTopic({
- clusterName,
- topicName,
- topicUpdate: formatTopicUpdate(form),
- });
+export const updateTopic =
+ (
+ clusterName: ClusterName,
+ topicName: TopicName,
+ form: TopicFormDataRaw
+ ): PromiseThunkResult =>
+ async (dispatch, getState) => {
+ dispatch(actions.updateTopicAction.request());
+ try {
+ const topic: Topic = await topicsApiClient.updateTopic({
+ clusterName,
+ topicName,
+ topicUpdate: formatTopicUpdate(form),
+ });
- const state = getState().topics;
- const newState = {
- ...state,
- byName: {
- ...state.byName,
- [topic.name]: {
- ...state.byName[topic.name],
- ...topic,
+ const state = getState().topics;
+ const newState = {
+ ...state,
+ byName: {
+ ...state.byName,
+ [topic.name]: {
+ ...state.byName[topic.name],
+ ...topic,
+ },
},
- },
- };
+ };
- dispatch(actions.updateTopicAction.success(newState));
- } catch (e) {
- dispatch(actions.updateTopicAction.failure());
- }
-};
+ dispatch(actions.updateTopicAction.success(newState));
+ } catch (e) {
+ dispatch(actions.updateTopicAction.failure());
+ }
+ };
-export const deleteTopic = (
- clusterName: ClusterName,
- topicName: TopicName
-): PromiseThunkResult => async (dispatch) => {
- dispatch(actions.deleteTopicAction.request());
- try {
- await topicsApiClient.deleteTopic({
- clusterName,
- topicName,
- });
- dispatch(actions.deleteTopicAction.success(topicName));
- } catch (e) {
- dispatch(actions.deleteTopicAction.failure());
- }
-};
+export const deleteTopic =
+ (clusterName: ClusterName, topicName: TopicName): PromiseThunkResult =>
+ async (dispatch) => {
+ dispatch(actions.deleteTopicAction.request());
+ try {
+ await topicsApiClient.deleteTopic({
+ clusterName,
+ topicName,
+ });
+ dispatch(actions.deleteTopicAction.success(topicName));
+ } catch (e) {
+ dispatch(actions.deleteTopicAction.failure());
+ }
+ };
diff --git a/kafka-ui-react-app/src/redux/reducers/topics/selectors.ts b/kafka-ui-react-app/src/redux/reducers/topics/selectors.ts
index 1da0cf9110..6aa5a6f228 100644
--- a/kafka-ui-react-app/src/redux/reducers/topics/selectors.ts
+++ b/kafka-ui-react-app/src/redux/reducers/topics/selectors.ts
@@ -18,12 +18,10 @@ export const getTopicListTotalPages = (state: RootState) =>
topicsState(state).totalPages;
const getTopicListFetchingStatus = createFetchingSelector('GET_TOPICS');
-const getTopicDetailsFetchingStatus = createFetchingSelector(
- 'GET_TOPIC_DETAILS'
-);
-const getTopicMessagesFetchingStatus = createFetchingSelector(
- 'GET_TOPIC_MESSAGES'
-);
+const getTopicDetailsFetchingStatus =
+ createFetchingSelector('GET_TOPIC_DETAILS');
+const getTopicMessagesFetchingStatus =
+ createFetchingSelector('GET_TOPIC_MESSAGES');
const getTopicConfigFetchingStatus = createFetchingSelector('GET_TOPIC_CONFIG');
const getTopicCreationStatus = createFetchingSelector('POST_TOPIC');
const getTopicUpdateStatus = createFetchingSelector('PATCH_TOPIC');
@@ -123,3 +121,8 @@ export const getTopicConfigByParamName = createSelector(
return byParamName;
}
);
+
+export const getIsTopicInternal = createSelector(
+ getTopicByName,
+ ({ internal }) => !!internal
+);
diff --git a/kafka-ui-react-app/src/redux/store/configureStore/mockStoreCreator.ts b/kafka-ui-react-app/src/redux/store/configureStore/mockStoreCreator.ts
index 373edbe3a0..9c20ad7f1a 100644
--- a/kafka-ui-react-app/src/redux/store/configureStore/mockStoreCreator.ts
+++ b/kafka-ui-react-app/src/redux/store/configureStore/mockStoreCreator.ts
@@ -6,9 +6,7 @@ import { RootState, Action } from 'redux/interfaces';
const middlewares: Array = [thunk];
type DispatchExts = ThunkDispatch;
-const mockStoreCreator: MockStoreCreator<
- RootState,
- DispatchExts
-> = configureMockStore(middlewares);
+const mockStoreCreator: MockStoreCreator =
+ configureMockStore(middlewares);
export default mockStoreCreator();
diff --git a/pom.xml b/pom.xml
index 95895193a4..6d83ebfbbd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,6 +6,7 @@
kafka-ui-contract
kafka-ui-api
+ kafka-ui-e2e-checks
|