Skip to content

Commit

Permalink
Topic settings editing (provectus#55)
Browse files Browse the repository at this point in the history
* Topic editing

* Remove old code

* Implement unique field name select

* Final changes to topic editing

* Cleanup eslint.json
  • Loading branch information
diokhan committed Jun 16, 2020
1 parent 4e7c818 commit ca6b646
Show file tree
Hide file tree
Showing 39 changed files with 5,876 additions and 3,545 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ build/

### VS Code ###
.vscode/
/kafka-ui-api/app/node
/kafka-ui-api/app/node

.DS_Store
7,810 changes: 4,810 additions & 3,000 deletions kafka-ui-react-app/package-lock.json

Large diffs are not rendered by default.

42 changes: 22 additions & 20 deletions kafka-ui-react-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,21 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"@types/classnames": "^2.2.9",
"@types/jest": "^24.0.25",
"@types/lodash": "^4.14.149",
"@types/node": "^12.12.24",
"@types/react": "^16.9.17",
"@types/react-dom": "^16.9.0",
"@types/react-redux": "^7.1.5",
"@types/react-router-dom": "^5.1.3",
"@types/redux": "^3.6.0",
"@types/redux-thunk": "^2.1.0",
"bulma": "^0.8.0",
"bulma-switch": "^2.0.0",
"classnames": "^2.2.6",
"json-server": "^0.15.1",
"immer": "^6.0.5",
"lodash": "^4.17.15",
"node-sass": "^4.13.1",
"pretty-ms": "^6.0.1",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-hook-form": "^4.5.5",
"react-redux": "^7.1.3",
"react-router-dom": "^5.1.2",
"react-scripts": "3.3.0",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"reselect": "^4.0.0",
"typesafe-actions": "^5.1.0",
"typescript": "~3.7.4"
"typesafe-actions": "^5.1.0"
},
"lint-staged": {
"*.{js,ts,jsx,tsx}": [
Expand Down Expand Up @@ -70,6 +54,19 @@
]
},
"devDependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"@types/classnames": "^2.2.9",
"@types/jest": "^24.0.25",
"@types/lodash": "^4.14.149",
"@types/node": "^12.12.24",
"@types/react": "^16.9.17",
"@types/react-dom": "^16.9.0",
"@types/react-redux": "^7.1.5",
"@types/react-router-dom": "^5.1.3",
"@types/redux": "^3.6.0",
"@types/redux-thunk": "^2.1.0",
"@typescript-eslint/eslint-plugin": "^2.27.0",
"@typescript-eslint/parser": "^2.27.0",
"eslint": "^6.8.0",
Expand All @@ -82,7 +79,12 @@
"eslint-plugin-react-hooks": "^2.5.1",
"esprint": "^0.6.0",
"husky": "^4.2.5",
"json-server": "^0.15.1",
"lint-staged": ">=10",
"prettier": "^2.0.4"
}
"node-sass": "^4.13.1",
"prettier": "^2.0.4",
"react-scripts": "3.4.0",
"typescript": "~3.7.4"
},
"proxy": "http://localhost:8080"
}
5 changes: 5 additions & 0 deletions kafka-ui-react-app/src/components/Topics/Details/Details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import {
clusterTopicSettingsPath,
clusterTopicPath,
clusterTopicMessagesPath,
clusterTopicsTopicEditPath,
} from 'lib/paths';
import OverviewContainer from './Overview/OverviewContainer';
import MessagesContainer from './Messages/MessagesContainer';
import SettingsContainer from './Settings/SettingsContainer';
import SettingsEditButton from './Settings/SettingsEditButton';

interface Props extends Topic, TopicDetails {
clusterName: ClusterName;
Expand All @@ -30,6 +32,9 @@ const Details: React.FC<Props> = ({ clusterName, topicName }) => {
{topicName}
</Breadcrumb>
</div>
<SettingsEditButton
to={clusterTopicsTopicEditPath(clusterName, topicName)}
/>
</div>

<div className="box">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { Link } from 'react-router-dom';

interface Props {
to: string;
}

const SettingsEditButton: React.FC<Props> = ({ to }) => (
<Link to={to}>
<button type="button" className="button is-small is-warning">
Edit settings
</button>
</Link>
);

export default SettingsEditButton;
143 changes: 143 additions & 0 deletions kafka-ui-react-app/src/components/Topics/Edit/Edit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import React from 'react';
import {
ClusterName,
TopicFormData,
TopicName,
TopicConfigByName,
TopicWithDetailedInfo,
CleanupPolicy,
} from 'redux/interfaces';
import { useForm, FormContext } from 'react-hook-form';
import { camelCase } from 'lodash';

import TopicForm from '../shared/Form/TopicForm';
import FormBreadcrumbs from '../shared/Form/FormBreadcrumbs';

interface Props {
clusterName: ClusterName;
topicName: TopicName;
topic?: TopicWithDetailedInfo;
isFetched: boolean;
isTopicDetailsFetched: boolean;
isTopicUpdated: boolean;
fetchTopicDetails: (clusterName: ClusterName, topicName: TopicName) => void;
fetchTopicConfig: (clusterName: ClusterName, topicName: TopicName) => void;
updateTopic: (clusterName: ClusterName, form: TopicFormData) => void;
redirectToTopicPath: (clusterName: ClusterName, topicName: TopicName) => void;
resetUploadedState: () => void;
}

const DEFAULTS = {
partitions: 1,
replicationFactor: 1,
minInSyncReplicas: 1,
cleanupPolicy: CleanupPolicy.Delete,
retentionBytes: -1,
maxMessageBytes: 1000012,
};

const topicParams = (topic: TopicWithDetailedInfo | undefined) => {
if (!topic) {
return DEFAULTS;
}

const { name, replicationFactor } = topic;

const configs = topic.config?.reduce(
(result: { [name: string]: string }, param) => {
result[camelCase(param.name)] = param.value || param.defaultValue;
return result;
},
{}
);

return {
...DEFAULTS,
name,
partitions: topic.partitionCount || DEFAULTS.partitions,
replicationFactor,
...configs,
};
};

let formInit = false;

const Edit: React.FC<Props> = ({
clusterName,
topicName,
topic,
isFetched,
isTopicDetailsFetched,
isTopicUpdated,
fetchTopicDetails,
fetchTopicConfig,
updateTopic,
redirectToTopicPath,
}) => {
const defaultValues = topicParams(topic);

const methods = useForm<TopicFormData>({ defaultValues });

const [isSubmitting, setIsSubmitting] = React.useState<boolean>(false);

React.useEffect(() => {
fetchTopicConfig(clusterName, topicName);
fetchTopicDetails(clusterName, topicName);
}, [fetchTopicConfig, fetchTopicDetails, clusterName, topicName]);

React.useEffect(() => {
if (isSubmitting && isTopicUpdated) {
const { name } = methods.getValues();
redirectToTopicPath(clusterName, name);
}
}, [isSubmitting, isTopicUpdated, redirectToTopicPath, clusterName, methods]);

if (!isFetched || !isTopicDetailsFetched || !topic || !topic.config) {
return null;
}

if (!formInit) {
methods.reset(defaultValues);
formInit = true;
}

const config: TopicConfigByName = {
byName: {},
};

topic.config.forEach((param) => {
config.byName[param.name] = param;
});

const onSubmit = async (data: TopicFormData) => {
setIsSubmitting(true);
updateTopic(clusterName, data);
};

return (
<div className="section">
<div className="level">
<FormBreadcrumbs
clusterName={clusterName}
topicName={topicName}
current="Edit Topic"
/>
</div>

<div className="box">
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
<FormContext {...methods}>
<TopicForm
topicName={topicName}
config={config}
isSubmitting={isSubmitting}
isEditing
onSubmit={methods.handleSubmit(onSubmit)}
/>
</FormContext>
</div>
</div>
);
};

export default Edit;
63 changes: 63 additions & 0 deletions kafka-ui-react-app/src/components/Topics/Edit/EditContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { connect } from 'react-redux';
import {
RootState,
ClusterName,
TopicFormData,
TopicName,
Action,
} from 'redux/interfaces';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import {
updateTopic,
fetchTopicConfig,
fetchTopicDetails,
} from 'redux/actions';
import {
getTopicConfigFetched,
getTopicUpdated,
getIsTopicDetailsFetched,
getFullTopic,
} from 'redux/reducers/topics/selectors';
import { clusterTopicPath } from 'lib/paths';
import { ThunkDispatch } from 'redux-thunk';
import Edit from './Edit';

interface RouteProps {
clusterName: ClusterName;
topicName: TopicName;
}

type OwnProps = RouteComponentProps<RouteProps>;

const mapStateToProps = (
state: RootState,
{
match: {
params: { topicName, clusterName },
},
}: OwnProps
) => ({
clusterName,
topicName,
topic: getFullTopic(state, topicName),
isFetched: getTopicConfigFetched(state),
isTopicDetailsFetched: getIsTopicDetailsFetched(state),
isTopicUpdated: getTopicUpdated(state),
});

const mapDispatchToProps = (
dispatch: ThunkDispatch<RootState, undefined, Action>,
{ history }: OwnProps
) => ({
fetchTopicDetails: (clusterName: ClusterName, topicName: TopicName) =>
dispatch(fetchTopicDetails(clusterName, topicName)),
fetchTopicConfig: (clusterName: ClusterName, topicName: TopicName) =>
dispatch(fetchTopicConfig(clusterName, topicName)),
updateTopic: (clusterName: ClusterName, form: TopicFormData) =>
dispatch(updateTopic(clusterName, form)),
redirectToTopicPath: (clusterName: ClusterName, topicName: TopicName) => {
history.push(clusterTopicPath(clusterName, topicName));
},
});

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Edit));

This file was deleted.

Loading

0 comments on commit ca6b646

Please sign in to comment.