From 8a6a235e77116153cf467074f0bcece63cfdb487 Mon Sep 17 00:00:00 2001 From: Philipp Czora Date: Fri, 14 Dec 2018 16:01:57 +0100 Subject: [PATCH] Implement Git repo config --- .../src/main/js/RepositoryConfig.js | 120 ++++++++++++++++++ .../scm-git-plugin/src/main/js/index.js | 31 ++++- .../main/resources/locales/en/plugins.json | 15 ++- .../ui-components/src}/BranchSelector.js | 26 ++-- .../ui-components/src/forms}/DropDown.js | 0 .../packages/ui-components/src/forms/index.js | 3 +- .../packages/ui-components/src/index.js | 1 + scm-ui/src/repos/containers/ChangesetsRoot.js | 23 ++-- scm-ui/src/repos/containers/RepositoryRoot.js | 41 ++---- .../src/repos/sources/containers/Sources.js | 21 ++- 10 files changed, 203 insertions(+), 78 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/main/js/RepositoryConfig.js rename {scm-ui/src/repos/containers => scm-ui-components/packages/ui-components/src}/BranchSelector.js (73%) rename {scm-ui/src/repos/components => scm-ui-components/packages/ui-components/src/forms}/DropDown.js (100%) diff --git a/scm-plugins/scm-git-plugin/src/main/js/RepositoryConfig.js b/scm-plugins/scm-git-plugin/src/main/js/RepositoryConfig.js new file mode 100644 index 0000000000..520af4a38c --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/js/RepositoryConfig.js @@ -0,0 +1,120 @@ +// @flow + +import React from "react"; + +import {apiClient, BranchSelector, ErrorPage, Loading, SubmitButton} from "@scm-manager/ui-components"; +import type {Branch, Repository} from "@scm-manager/ui-types"; +import {translate} from "react-i18next"; + +type Props = { + repository: Repository, + + t: string => string +}; +type State = { + loadingBranches: boolean, + loadingDefaultBranch: boolean, + submitPending: boolean, + error: Error, + branches: Branch[], + selectedBranchName: string +}; + +const GIT_CONFIG_CONTENT_TYPE = "application/vnd.scmm-gitConfig+json"; + +class RepositoryConfig extends React.Component { + state = { + branches: [] + }; + + componentDidMount() { + const { repository } = this.props; + this.setState({ ...this.state, loadingBranches: true }); + apiClient + .get(repository._links.branches.href) + .then(response => response.json()) + .then(payload => payload._embedded.branches) + .then(branches => + this.setState({ ...this.state, branches, loadingBranches: false }) + ) + .catch(error => this.setState({ ...this.state, error })); + + this.setState({ ...this.state, loadingDefaultBranch: true }); + apiClient + .get(repository._links.configuration.href) + .then(response => response.json()) + .then(payload => payload.defaultBranch) + .then(selectedBranchName => + this.setState({ + ...this.state, + selectedBranchName, + loadingDefaultBranch: false + }) + ) + .catch(error => this.setState({ ...this.state, error })); + } + + branchSelected = (branch: Branch) => { + if (!branch) { + this.setState({ ...this.state, selectedBranchName: null }); + } + this.setState({ ...this.state, selectedBranchName: branch.name }); + }; + + submit = (event: Event) => { + event.preventDefault(); + + const { repository } = this.props; + const newConfig = { + defaultBranch: this.state.selectedBranchName + }; + this.setState({ ...this.state, submitPending: true }); + apiClient + .put( + repository._links.configuration.href, + newConfig, + GIT_CONFIG_CONTENT_TYPE + ) + .then(() => this.setState({ ...this.state, submitPending: false })) + .catch(error => this.setState({ ...this.state, error })); + }; + + render() { + const { t, error } = this.props; + const { loadingBranches, loadingDefaultBranch, submitPending } = this.state; + + if (error) { + return ( + + ); + } + if (!(loadingBranches || loadingDefaultBranch)) { + + return ( +
+ + + + ); + } else { + return ; + } + } +} + +export default translate("plugins")(RepositoryConfig); diff --git a/scm-plugins/scm-git-plugin/src/main/js/index.js b/scm-plugins/scm-git-plugin/src/main/js/index.js index bdeda4cd0e..a066247dde 100644 --- a/scm-plugins/scm-git-plugin/src/main/js/index.js +++ b/scm-plugins/scm-git-plugin/src/main/js/index.js @@ -1,11 +1,13 @@ //@flow -import { binder } from "@scm-manager/ui-extensions"; +import React from "react"; +import {binder} from "@scm-manager/ui-extensions"; import ProtocolInformation from "./ProtocolInformation"; import GitAvatar from "./GitAvatar"; -import { ConfigurationBinder as cfgBinder } from "@scm-manager/ui-components"; +import {ConfigurationBinder as cfgBinder} from "@scm-manager/ui-components"; import GitGlobalConfiguration from "./GitGlobalConfiguration"; import GitMergeInformation from "./GitMergeInformation"; +import RepositoryConfig from "./RepositoryConfig"; // repository @@ -13,10 +15,29 @@ const gitPredicate = (props: Object) => { return props.repository && props.repository.type === "git"; }; -binder.bind("repos.repository-details.information", ProtocolInformation, gitPredicate); -binder.bind("repos.repository-merge.information", GitMergeInformation, gitPredicate); +binder.bind( + "repos.repository-details.information", + ProtocolInformation, + gitPredicate +); +binder.bind( + "repos.repository-merge.information", + GitMergeInformation, + gitPredicate +); binder.bind("repos.repository-avatar", GitAvatar, gitPredicate); +cfgBinder.bindRepository( + "/configuration", + "scm-git-plugin.repo-config.link", + "configuration", + RepositoryConfig +); // global config -cfgBinder.bindGlobal("/git", "scm-git-plugin.config.link", "gitConfig", GitGlobalConfiguration); +cfgBinder.bindGlobal( + "/git", + "scm-git-plugin.config.link", + "gitConfig", + GitGlobalConfiguration +); diff --git a/scm-plugins/scm-git-plugin/src/main/resources/locales/en/plugins.json b/scm-plugins/scm-git-plugin/src/main/resources/locales/en/plugins.json index c02cd9e101..a1ad9764d1 100644 --- a/scm-plugins/scm-git-plugin/src/main/resources/locales/en/plugins.json +++ b/scm-plugins/scm-git-plugin/src/main/resources/locales/en/plugins.json @@ -1,9 +1,9 @@ { "scm-git-plugin": { "information": { - "clone" : "Clone the repository", - "create" : "Create a new repository", - "replace" : "Push an existing repository", + "clone": "Clone the repository", + "create": "Create a new repository", + "replace": "Push an existing repository", "merge": { "heading": "How to merge source branch into target branch", "checkout": "1. Make sure your workspace is clean and checkout target branch", @@ -22,6 +22,15 @@ "disabled": "Disabled", "disabledHelpText": "Enable or disable the Git plugin", "submit": "Submit" + }, + "repo-config": { + "link": "Configuration", + "default-branch": "Default branch", + "submit": "Submit", + "error": { + "title": "Error", + "subtitle": "Something went wrong" + } } } } diff --git a/scm-ui/src/repos/containers/BranchSelector.js b/scm-ui-components/packages/ui-components/src/BranchSelector.js similarity index 73% rename from scm-ui/src/repos/containers/BranchSelector.js rename to scm-ui-components/packages/ui-components/src/BranchSelector.js index ced1cb8f44..1f17891140 100644 --- a/scm-ui/src/repos/containers/BranchSelector.js +++ b/scm-ui-components/packages/ui-components/src/BranchSelector.js @@ -1,12 +1,10 @@ // @flow import React from "react"; -import type { Branch } from "@scm-manager/ui-types"; -import DropDown from "../components/DropDown"; -import { translate } from "react-i18next"; +import type {Branch} from "packages/ui-types/src/index"; import injectSheet from "react-jss"; -import { compose } from "redux"; import classNames from "classnames"; +import DropDown from "./forms/DropDown"; const styles = { zeroflex: { @@ -20,11 +18,11 @@ const styles = { type Props = { branches: Branch[], // TODO: Use generics? selected: (branch?: Branch) => void, - selectedBranch: string, + selectedBranch?: string, + label: string, // context props - classes: Object, - t: string => string + classes: Object }; type State = { selectedBranch?: Branch }; @@ -36,13 +34,12 @@ class BranchSelector extends React.Component { } componentDidMount() { - this.props.branches - .filter(branch => branch.name === this.props.selectedBranch) - .forEach(branch => this.setState({ selectedBranch: branch })); + const selectedBranch = this.props.branches.find(branch => branch.name === this.props.selectedBranch); + this.setState({ selectedBranch }) } render() { - const { branches, classes, t } = this.props; + const { branches, classes, label } = this.props; if (branches) { return ( @@ -55,7 +52,7 @@ class BranchSelector extends React.Component { classes.minWidthOfLabel )} > - +
@@ -89,7 +86,4 @@ class BranchSelector extends React.Component { }; } -export default compose( - injectSheet(styles), - translate("repos") -)(BranchSelector); +export default injectSheet(styles)(BranchSelector); diff --git a/scm-ui/src/repos/components/DropDown.js b/scm-ui-components/packages/ui-components/src/forms/DropDown.js similarity index 100% rename from scm-ui/src/repos/components/DropDown.js rename to scm-ui-components/packages/ui-components/src/forms/DropDown.js diff --git a/scm-ui-components/packages/ui-components/src/forms/index.js b/scm-ui-components/packages/ui-components/src/forms/index.js index 714b9b3301..3bc3820f16 100644 --- a/scm-ui-components/packages/ui-components/src/forms/index.js +++ b/scm-ui-components/packages/ui-components/src/forms/index.js @@ -7,5 +7,6 @@ export { default as InputField } from "./InputField.js"; export { default as Select } from "./Select.js"; export { default as Textarea } from "./Textarea.js"; export { default as PasswordConfirmation } from "./PasswordConfirmation.js"; -export { default as LabelWithHelpIcon } from "./LabelWithHelpIcon"; +export { default as LabelWithHelpIcon } from "./LabelWithHelpIcon.js"; +export { default as DropDown } from "./DropDown.js"; diff --git a/scm-ui-components/packages/ui-components/src/index.js b/scm-ui-components/packages/ui-components/src/index.js index 91c41a9d25..5b3cdb4c95 100644 --- a/scm-ui-components/packages/ui-components/src/index.js +++ b/scm-ui-components/packages/ui-components/src/index.js @@ -24,6 +24,7 @@ export { default as HelpIcon } from "./HelpIcon"; export { default as Tooltip } from "./Tooltip"; export { getPageFromMatch } from "./urls"; export { default as Autocomplete} from "./Autocomplete"; +export { default as BranchSelector } from "./BranchSelector"; export { apiClient, NOT_FOUND_ERROR, UNAUTHORIZED_ERROR, CONFLICT_ERROR } from "./apiclient.js"; diff --git a/scm-ui/src/repos/containers/ChangesetsRoot.js b/scm-ui/src/repos/containers/ChangesetsRoot.js index 1f3f0c1e3b..b914cd8298 100644 --- a/scm-ui/src/repos/containers/ChangesetsRoot.js +++ b/scm-ui/src/repos/containers/ChangesetsRoot.js @@ -1,19 +1,14 @@ // @flow import React from "react"; -import type { Branch, Repository } from "@scm-manager/ui-types"; -import { Route, withRouter } from "react-router-dom"; +import type {Branch, Repository} from "@scm-manager/ui-types"; +import {translate} from "react-i18next"; +import {Route, withRouter} from "react-router-dom"; import Changesets from "./Changesets"; -import BranchSelector from "./BranchSelector"; -import { connect } from "react-redux"; -import { ErrorNotification, Loading } from "@scm-manager/ui-components"; -import { - fetchBranches, - getBranches, - getFetchBranchesFailure, - isFetchBranchesPending -} from "../modules/branches"; -import { compose } from "redux"; +import {connect} from "react-redux"; +import {BranchSelector, ErrorNotification, Loading} from "@scm-manager/ui-components"; +import {fetchBranches, getBranches, getFetchBranchesFailure, isFetchBranchesPending} from "../modules/branches"; +import {compose} from "redux"; type Props = { repository: Repository, @@ -92,10 +87,11 @@ class BranchRoot extends React.Component { } renderBranchSelector = () => { - const { repository, branches, selected } = this.props; + const { repository, branches, selected, t } = this.props; if (repository._links.branches) { return ( { @@ -133,6 +129,7 @@ const mapStateToProps = (state: any, ownProps: Props) => { export default compose( withRouter, + translate("repos"), connect( mapStateToProps, mapDispatchToProps diff --git a/scm-ui/src/repos/containers/RepositoryRoot.js b/scm-ui/src/repos/containers/RepositoryRoot.js index 81de0296fc..d4095ac065 100644 --- a/scm-ui/src/repos/containers/RepositoryRoot.js +++ b/scm-ui/src/repos/containers/RepositoryRoot.js @@ -1,32 +1,19 @@ //@flow import React from "react"; -import { - deleteRepo, - fetchRepoByName, - getFetchRepoFailure, - getRepository, - isFetchRepoPending -} from "../modules/repos"; +import {deleteRepo, fetchRepoByName, getFetchRepoFailure, getRepository, isFetchRepoPending} from "../modules/repos"; -import { connect } from "react-redux"; -import { Route, Switch } from "react-router-dom"; -import type { Repository } from "@scm-manager/ui-types"; +import {connect} from "react-redux"; +import {Route, Switch} from "react-router-dom"; +import type {Repository} from "@scm-manager/ui-types"; -import { - ErrorPage, - Loading, - Navigation, - NavLink, - Page, - Section -} from "@scm-manager/ui-components"; -import { translate } from "react-i18next"; +import {ErrorPage, Loading, Navigation, NavLink, Page, Section} from "@scm-manager/ui-components"; +import {translate} from "react-i18next"; import RepositoryDetails from "../components/RepositoryDetails"; import DeleteNavAction from "../components/DeleteNavAction"; import Edit from "../containers/Edit"; import Permissions from "../permissions/containers/Permissions"; -import type { History } from "history"; +import type {History} from "history"; import EditNavLink from "../components/EditNavLink"; import BranchRoot from "./ChangesetsRoot"; @@ -34,8 +21,8 @@ import ChangesetView from "./ChangesetView"; import PermissionsNavLink from "../components/PermissionsNavLink"; import Sources from "../sources/containers/Sources"; import RepositoryNavLink from "../components/RepositoryNavLink"; -import { getRepositoriesLink } from "../../modules/indexResource"; -import { ExtensionPoint } from "@scm-manager/ui-extensions"; +import {getRepositoriesLink} from "../../modules/indexResource"; +import {ExtensionPoint} from "@scm-manager/ui-extensions"; type Props = { namespace: string, @@ -198,16 +185,16 @@ class RepositoryRoot extends React.Component { label={t("repository-root.sources")} activeOnlyWhenExact={false} /> - +
diff --git a/scm-ui/src/repos/sources/containers/Sources.js b/scm-ui/src/repos/sources/containers/Sources.js index 890ab595d0..b04bcb990d 100644 --- a/scm-ui/src/repos/sources/containers/Sources.js +++ b/scm-ui/src/repos/sources/containers/Sources.js @@ -1,20 +1,15 @@ // @flow import React from "react"; -import { connect } from "react-redux"; -import { withRouter } from "react-router-dom"; -import type { Branch, Repository } from "@scm-manager/ui-types"; +import {connect} from "react-redux"; +import {withRouter} from "react-router-dom"; +import type {Branch, Repository} from "@scm-manager/ui-types"; import FileTree from "../components/FileTree"; -import { ErrorNotification, Loading } from "@scm-manager/ui-components"; -import BranchSelector from "../../containers/BranchSelector"; -import { - fetchBranches, - getBranches, - getFetchBranchesFailure, - isFetchBranchesPending -} from "../../modules/branches"; -import { compose } from "redux"; +import {ErrorNotification, Loading} from "@scm-manager/ui-components"; +import BranchSelector from "../../../../../scm-ui-components/packages/ui-components/src/BranchSelector"; +import {fetchBranches, getBranches, getFetchBranchesFailure, isFetchBranchesPending} from "../../modules/branches"; +import {compose} from "redux"; import Content from "./Content"; -import { fetchSources, isDirectory } from "../modules/sources"; +import {fetchSources, isDirectory} from "../modules/sources"; type Props = { repository: Repository,