From 9d43cc745f6188357d830f92e1cc682188ac7e1f Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Thu, 28 Mar 2019 10:16:19 +0100 Subject: [PATCH 01/37] renamed branches url --- scm-ui/src/repos/containers/CreateBranch.js | 13 ++++++++++++ scm-ui/src/repos/containers/RepositoryRoot.js | 20 +++++++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 scm-ui/src/repos/containers/CreateBranch.js diff --git a/scm-ui/src/repos/containers/CreateBranch.js b/scm-ui/src/repos/containers/CreateBranch.js new file mode 100644 index 0000000000..be20fe0a03 --- /dev/null +++ b/scm-ui/src/repos/containers/CreateBranch.js @@ -0,0 +1,13 @@ +// @flow +import React from "react"; + +class CreateBranch extends React.Component<> { + + render() { + return ( +

Create placeholder

+ ); + } +} + +export default CreateBranch; diff --git a/scm-ui/src/repos/containers/RepositoryRoot.js b/scm-ui/src/repos/containers/RepositoryRoot.js index 62c1800100..c5be3bd9d0 100644 --- a/scm-ui/src/repos/containers/RepositoryRoot.js +++ b/scm-ui/src/repos/containers/RepositoryRoot.js @@ -12,7 +12,6 @@ import {Redirect, Route, Switch} from "react-router-dom"; import type { Repository } from "@scm-manager/ui-types"; import { - CollapsibleErrorPage, Loading, Navigation, SubNavigation, @@ -23,6 +22,7 @@ import { import { translate } from "react-i18next"; import RepositoryDetails from "../components/RepositoryDetails"; import EditRepo from "./EditRepo"; +import CreateBranch from "./CreateBranch"; import Permissions from "../permissions/containers/Permissions"; import type { History } from "history"; @@ -74,7 +74,7 @@ class RepositoryRoot extends React.Component { matches = (route: any) => { const url = this.matchedUrl(); - const regex = new RegExp(`${url}(/branches)?/?[^/]*/changesets?.*`); + const regex = new RegExp(`${url}(/branch)?/?[^/]*/changesets?.*`); return route.location.pathname.match(regex); }; @@ -86,7 +86,7 @@ class RepositoryRoot extends React.Component { title={t("repositoryRoot.errorTitle")} subtitle={t("repositoryRoot.errorSubtitle")} error={error} - /> + />; } if (!repository || loading) { @@ -156,21 +156,29 @@ class RepositoryRoot extends React.Component { render={() => ( )} /> ( )} /> + ( + + )} + /> Date: Thu, 28 Mar 2019 11:51:00 +0100 Subject: [PATCH 02/37] added branches overview and navlink --- scm-ui/public/locales/de/repos.json | 1 + scm-ui/public/locales/en/repos.json | 1 + .../src/repos/containers/BranchesOverview.js | 98 +++++++++++++++++++ scm-ui/src/repos/containers/RepositoryRoot.js | 17 ++++ 4 files changed, 117 insertions(+) create mode 100644 scm-ui/src/repos/containers/BranchesOverview.js diff --git a/scm-ui/public/locales/de/repos.json b/scm-ui/public/locales/de/repos.json index 141d58d1d2..dc444f59ff 100644 --- a/scm-ui/public/locales/de/repos.json +++ b/scm-ui/public/locales/de/repos.json @@ -26,6 +26,7 @@ "menu": { "navigationLabel": "Repository Navigation", "informationNavLink": "Informationen", + "branchesNavLink": "Branches", "historyNavLink": "Commits", "sourcesNavLink": "Sources", "settingsNavLink": "Einstellungen", diff --git a/scm-ui/public/locales/en/repos.json b/scm-ui/public/locales/en/repos.json index f10c771d96..d888d73c29 100644 --- a/scm-ui/public/locales/en/repos.json +++ b/scm-ui/public/locales/en/repos.json @@ -26,6 +26,7 @@ "menu": { "navigationLabel": "Repository Navigation", "informationNavLink": "Information", + "branchesNavLink": "Branches", "historyNavLink": "Commits", "sourcesNavLink": "Sources", "settingsNavLink": "Settings", diff --git a/scm-ui/src/repos/containers/BranchesOverview.js b/scm-ui/src/repos/containers/BranchesOverview.js new file mode 100644 index 0000000000..d13449eeb6 --- /dev/null +++ b/scm-ui/src/repos/containers/BranchesOverview.js @@ -0,0 +1,98 @@ +// @flow +import React from "react"; +import {fetchBranches, getBranches, getFetchBranchesFailure, isFetchBranchesPending} from "../modules/branches"; +import {connect} from "react-redux"; +import type {Branch, Repository} from "@scm-manager/ui-types"; +import {compose} from "redux"; +import {translate} from "react-i18next"; +import {withRouter} from "react-router-dom"; +import {ErrorNotification, Loading} from "@scm-manager/ui-components"; + +type Props = { + repository: Repository, + loading: boolean, + error: Error, + branches: Branch[], + + // dispatch props + fetchBranches: Repository => void, + + // Context props + history: any, + match: any, + t: string => string +}; +class BranchesOverview extends React.Component { + componentDidMount() { + const { + fetchBranches, + repository + } = this.props; + + fetchBranches(repository); + } + + render() { + const { + loading, + error, + } = this.props; + + if (error) { + return ; + } + + if (loading) { + return ; + } + + return <>{this.renderBranches()}; + } + + renderBranches() { + const { branches } = this.props; + + let branchesList = null; + if (branches) { + branchesList = ( +
    + {branches.map((branch, index) => { + return
  • {branch.name}
  • ; + })} +
+ ); + } + return branchesList; + } +} + +const mapStateToProps = (state, ownProps) => { + const { repository } = ownProps; + const loading = isFetchBranchesPending(state, repository); + const error = getFetchBranchesFailure(state, repository); + const branches = getBranches(state, repository); + + return { + repository, + loading, + error, + branches + }; +}; + +const mapDispatchToProps = dispatch => { + return { + fetchBranches: (repository: Repository) => { + dispatch(fetchBranches(repository)); + }, + }; +}; + +export default compose( + translate("repos"), + withRouter, + connect( + mapStateToProps, + mapDispatchToProps + ) +)(BranchesOverview); diff --git a/scm-ui/src/repos/containers/RepositoryRoot.js b/scm-ui/src/repos/containers/RepositoryRoot.js index c5be3bd9d0..535d678e12 100644 --- a/scm-ui/src/repos/containers/RepositoryRoot.js +++ b/scm-ui/src/repos/containers/RepositoryRoot.js @@ -22,6 +22,7 @@ import { import { translate } from "react-i18next"; import RepositoryDetails from "../components/RepositoryDetails"; import EditRepo from "./EditRepo"; +import BranchesOverview from "./BranchesOverview"; import CreateBranch from "./CreateBranch"; import Permissions from "../permissions/containers/Permissions"; @@ -171,6 +172,14 @@ class RepositoryRoot extends React.Component { /> )} /> + ( + + )} + /> ( @@ -199,6 +208,14 @@ class RepositoryRoot extends React.Component { icon="fas fa-info-circle" label={t("repositoryRoot.menu.informationNavLink")} /> + Date: Thu, 28 Mar 2019 13:40:12 +0100 Subject: [PATCH 03/37] changed code-branch icon for more clarity over commit icon --- .../src/repos/changesets/ChangesetButtonGroup.js | 2 +- scm-ui/src/repos/components/list/RepositoryEntry.js | 2 +- scm-ui/src/repos/containers/RepositoryRoot.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetButtonGroup.js b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetButtonGroup.js index de05efb46e..971f5bf44a 100644 --- a/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetButtonGroup.js +++ b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetButtonGroup.js @@ -26,7 +26,7 @@ class ChangesetButtonGroup extends React.Component { + + + ); + } +} + +export default translate("repos")(BranchButtonGroup); diff --git a/scm-ui/src/repos/branches/components/BranchDetailTable.js b/scm-ui/src/repos/branches/components/BranchDetailTable.js index 4577bbee72..15a8b6236e 100644 --- a/scm-ui/src/repos/branches/components/BranchDetailTable.js +++ b/scm-ui/src/repos/branches/components/BranchDetailTable.js @@ -2,6 +2,7 @@ import React from "react"; import type { Repository, Branch } from "@scm-manager/ui-types"; import { translate } from "react-i18next"; +import BranchButtonGroup from "./BranchButtonGroup"; type Props = { repository: Repository, @@ -26,6 +27,12 @@ class BranchDetailTable extends React.Component { {repository.name} + + + {t("branch.actions")} + + + ); diff --git a/scm-ui/src/repos/branches/containers/BranchView.js b/scm-ui/src/repos/branches/containers/BranchView.js index a225f0c7fb..459a532b4a 100644 --- a/scm-ui/src/repos/branches/containers/BranchView.js +++ b/scm-ui/src/repos/branches/containers/BranchView.js @@ -3,18 +3,54 @@ import React from "react"; import BranchDetailTable from "../components/BranchDetailTable"; import { ExtensionPoint } from "@scm-manager/ui-extensions"; import type { Repository, Branch } from "@scm-manager/ui-types"; -import {connect} from "react-redux"; -import {translate} from "react-i18next"; -import {getBranch} from "../../modules/branches"; +import { connect } from "react-redux"; +import { translate } from "react-i18next"; +import { withRouter } from "react-router-dom"; +import { + fetchBranchByName, + getFetchBranchFailure, + isFetchBranchPending +} from "../../modules/branches"; +import { ErrorPage, Loading } from "@scm-manager/ui-components"; type Props = { repository: Repository, - branch: Branch // TODO: get branch from props + branchName: string, + loading: boolean, + error: Error, + branch: Branch, + + // dispatch functions + fetchBranchByName: (repository: Repository, branchName: string) => void, + + // context props + t: string => string }; class BranchView extends React.Component { + componentDidMount() { + const { fetchBranchByName, repository, branchName } = this.props; + + fetchBranchByName(repository, branchName); + } + render() { - const { repository, branch } = this.props; + const { loading, error, t, repository, branch } = this.props; + + if (error) { + return ( + + ); + } + + if (!branch || loading) { + return ; + } + return (
@@ -23,7 +59,7 @@ class BranchView extends React.Component {
@@ -33,13 +69,28 @@ class BranchView extends React.Component { const mapStateToProps = (state, ownProps) => { const { repository } = ownProps; - const branch = getBranch(state, repository, "VisualStudio"); // TODO: !!! + const branchName = decodeURIComponent(ownProps.match.params.branch); + const loading = isFetchBranchPending(state, repository, branchName); + const error = getFetchBranchFailure(state, repository, branchName); return { repository, - branch + branchName, + loading, + error }; }; -export default connect( - mapStateToProps -)(translate("repos")(BranchView)); +const mapDispatchToProps = dispatch => { + return { + fetchBranchByName: (repository: string, branchName: string) => { + dispatch(fetchBranchByName(repository, branchName)); + } + }; +}; + +export default withRouter( + connect( + mapStateToProps, + mapDispatchToProps + )(translate("repos")(BranchView)) +); diff --git a/scm-ui/src/repos/containers/RepositoryRoot.js b/scm-ui/src/repos/containers/RepositoryRoot.js index c1b14f4086..8c481f1adc 100644 --- a/scm-ui/src/repos/containers/RepositoryRoot.js +++ b/scm-ui/src/repos/containers/RepositoryRoot.js @@ -77,7 +77,7 @@ class RepositoryRoot extends React.Component { matchesBranches = (route: any) => { const url = this.matchedUrl(); - const regex = new RegExp(`${url}(/branch)?/?[^/]*/info?.*`); + const regex = new RegExp(`${url}/branch/.+/info`); return route.location.pathname.match(regex); }; diff --git a/scm-ui/src/repos/modules/branches.js b/scm-ui/src/repos/modules/branches.js index f819b07700..7d14a189fa 100644 --- a/scm-ui/src/repos/modules/branches.js +++ b/scm-ui/src/repos/modules/branches.js @@ -16,6 +16,10 @@ export const FETCH_BRANCHES_FAILURE = `${FETCH_BRANCHES}_${FAILURE_SUFFIX}`; // Fetching branches +export function fetchBranch(repositroy: Repository, branchName: string) { + +} + export function fetchBranches(repository: Repository) { if (!repository._links.branches) { return { From b7178d33323407054983265c9781f188149f3249 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Fri, 29 Mar 2019 14:24:54 +0100 Subject: [PATCH 13/37] sorted branches and show defaultbranch label --- .../repos/branches/components/BranchRow.js | 10 +++-- .../branches/containers/BranchesOverview.js | 41 +++++++++++++++++-- scm-ui/src/repos/modules/branches.js | 4 +- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/scm-ui/src/repos/branches/components/BranchRow.js b/scm-ui/src/repos/branches/components/BranchRow.js index 2a12e64c9e..411eb383a3 100644 --- a/scm-ui/src/repos/branches/components/BranchRow.js +++ b/scm-ui/src/repos/branches/components/BranchRow.js @@ -9,8 +9,12 @@ type Props = { }; export default class BranchRow extends React.Component { - renderLink(to: string, label: string) { - return {label} Default; + renderLink(to: string, label: string, defaultBranch: boolean) { + let showLabel = null; + if(defaultBranch) { + showLabel = Default; + } + return {label} {showLabel}; } render() { @@ -18,7 +22,7 @@ export default class BranchRow extends React.Component { const to = `${baseUrl}/${encodeURIComponent(branch.name)}/info`; return ( - {this.renderLink(to, branch.name)} + {this.renderLink(to, branch.name, branch.defaultBranch)} ); } diff --git a/scm-ui/src/repos/branches/containers/BranchesOverview.js b/scm-ui/src/repos/branches/containers/BranchesOverview.js index 8589d5565f..71e8452fdb 100644 --- a/scm-ui/src/repos/branches/containers/BranchesOverview.js +++ b/scm-ui/src/repos/branches/containers/BranchesOverview.js @@ -35,16 +35,47 @@ type Props = { match: any, t: string => string }; + +// master, default should always be the first one, +// followed by develop the rest should be ordered by its name +export function orderBranches(branches: Branch[]) { + branches.sort((a, b) => { + if (a.defaultBranch && !b.defaultBranch ) { + return -20; + } else if (!a.defaultBranch && b.defaultBranch ) { + return 20; + } else if (a.name === "master" && b.name !== "master") { + return -10; + } else if (a.name !== "master" && b.name === "master") { + return 10; + } else if (a.name === "default" && b.name !== "default") { + return -10; + } else if (a.name !== "default" && b.name === "default") { + return 10; + } else if (a.name === "develop" && b.name !== "develop") { + return -5; + } else if (a.name !== "develop" && b.name === "develop") { + return 5; + } else if (a.name < b.name) { + return -1; + } else if (a.name > b.name) { + return 1; + } + return 0; + }); +} + class BranchesOverview extends React.Component { componentDidMount() { const { fetchBranches, repository } = this.props; - fetchBranches(repository); } render() { const { baseUrl, loading, error, branches, t } = this.props; + orderBranches(branches); + if (error) { return ; } @@ -64,9 +95,13 @@ class BranchesOverview extends React.Component { renderCreateButton() { const { showCreateButton, t } = this.props; - if (showCreateButton || true ) { // TODO + if (showCreateButton || true) { + // TODO return ( - + ); } return null; diff --git a/scm-ui/src/repos/modules/branches.js b/scm-ui/src/repos/modules/branches.js index 7d14a189fa..a0870a588d 100644 --- a/scm-ui/src/repos/modules/branches.js +++ b/scm-ui/src/repos/modules/branches.js @@ -16,9 +16,7 @@ export const FETCH_BRANCHES_FAILURE = `${FETCH_BRANCHES}_${FAILURE_SUFFIX}`; // Fetching branches -export function fetchBranch(repositroy: Repository, branchName: string) { - -} +export function fetchBranch(repositroy: Repository, branchName: string) {} export function fetchBranches(repository: Repository) { if (!repository._links.branches) { From e6912ef77b2ec1c854caf4a9794ee2d12c1bc2a3 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Fri, 29 Mar 2019 14:54:18 +0100 Subject: [PATCH 14/37] fixed preloading bug for sorting null branches --- scm-ui/src/repos/branches/components/BranchRow.js | 8 ++++++-- .../src/repos/branches/containers/BranchesOverview.js | 10 +++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/scm-ui/src/repos/branches/components/BranchRow.js b/scm-ui/src/repos/branches/components/BranchRow.js index 411eb383a3..873bc066c7 100644 --- a/scm-ui/src/repos/branches/components/BranchRow.js +++ b/scm-ui/src/repos/branches/components/BranchRow.js @@ -11,10 +11,14 @@ type Props = { export default class BranchRow extends React.Component { renderLink(to: string, label: string, defaultBranch: boolean) { let showLabel = null; - if(defaultBranch) { + if (defaultBranch) { showLabel = Default; } - return {label} {showLabel}; + return ( + + {label} {showLabel} + + ); } render() { diff --git a/scm-ui/src/repos/branches/containers/BranchesOverview.js b/scm-ui/src/repos/branches/containers/BranchesOverview.js index 71e8452fdb..b39c821494 100644 --- a/scm-ui/src/repos/branches/containers/BranchesOverview.js +++ b/scm-ui/src/repos/branches/containers/BranchesOverview.js @@ -40,9 +40,9 @@ type Props = { // followed by develop the rest should be ordered by its name export function orderBranches(branches: Branch[]) { branches.sort((a, b) => { - if (a.defaultBranch && !b.defaultBranch ) { + if (a.defaultBranch && !b.defaultBranch) { return -20; - } else if (!a.defaultBranch && b.defaultBranch ) { + } else if (!a.defaultBranch && b.defaultBranch) { return 20; } else if (a.name === "master" && b.name !== "master") { return -10; @@ -74,16 +74,16 @@ class BranchesOverview extends React.Component { render() { const { baseUrl, loading, error, branches, t } = this.props; - orderBranches(branches); - if (error) { return ; } - if (loading) { + if (!branches || loading) { return ; } + orderBranches(branches); + return ( <> From 442e4c4889eb875d6d1f8f7fa37681d5388f397e Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Fri, 29 Mar 2019 15:25:32 +0100 Subject: [PATCH 15/37] first attempt on fetching single branch --- scm-ui/src/repos/modules/branches.js | 71 +++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/scm-ui/src/repos/modules/branches.js b/scm-ui/src/repos/modules/branches.js index a0870a588d..6020ec54de 100644 --- a/scm-ui/src/repos/modules/branches.js +++ b/scm-ui/src/repos/modules/branches.js @@ -14,9 +14,78 @@ export const FETCH_BRANCHES_PENDING = `${FETCH_BRANCHES}_${PENDING_SUFFIX}`; export const FETCH_BRANCHES_SUCCESS = `${FETCH_BRANCHES}_${SUCCESS_SUFFIX}`; export const FETCH_BRANCHES_FAILURE = `${FETCH_BRANCHES}_${FAILURE_SUFFIX}`; +export const FETCH_BRANCH = "scm/repos/FETCH_BRANCH"; +export const FETCH_BRANCH_PENDING = `${FETCH_BRANCH}_${PENDING_SUFFIX}`; +export const FETCH_BRANCH_SUCCESS = `${FETCH_BRANCH}_${SUCCESS_SUFFIX}`; +export const FETCH_BRANCH_FAILURE = `${FETCH_BRANCH}_${FAILURE_SUFFIX}`; + // Fetching branches -export function fetchBranch(repositroy: Repository, branchName: string) {} +export function fetchBranchByName(link: string, name: string) { + const branchUrl = link.endsWith("/") ? link + name : link + "/" + name; + return fetchBranch(branchUrl, name); +} + +export function fetchBranchPending(name: string): Action { + return { + type: FETCH_BRANCH_PENDING, + payload: name, + itemId: name + }; +} + +export function fetchBranchFailure(name: string, error: Error): Action { + return { + type: FETCH_BRANCH_FAILURE, + payload: name, + itemId: name + }; +} + +export function fetchBranch(link: string, name: string) { + return function(dispatch: any) { + dispatch(fetchBranchPending(name)); + return apiClient + .get(link) + .then(response => { + return response.json(); + }) + .then(data => { + dispatch(fetchBranchSuccess(data)); + }) + .catch(error => { + dispatch(fetchBranchFailure(name, error)); + }); + }; +} + +export function getFetchBranchFailure( + state: Object, + repository: string, + branchName: string +) { + return getFailure( + state, + FETCH_BRANCH, + repository + "/branches/" + branchName + ); +} + +export function isFetchBranchPending( + state: Object, + repository: string, + branchName: string +) { + return isPending(state, FETCH_BRANCH, repository + "/branches/" + branchName); +} + +export function fetchBranchSuccess(branch: Branch): Action { + return { + type: FETCH_BRANCH_SUCCESS, + payload: branch, + itemId: branch.name + }; +} export function fetchBranches(repository: Repository) { if (!repository._links.branches) { From bb5e3c9c58b83c6942c0fa3c6bdf2a86ced6a896 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Mon, 1 Apr 2019 09:52:39 +0200 Subject: [PATCH 16/37] added gitbranchinformation binding --- .../src/main/js/CloneInformation.js | 4 +- .../src/main/js/GitBranchInformation.js | 33 +++++++++++++ .../src/main/js/GitConfigurationForm.js | 48 +++++++++---------- .../scm-git-plugin/src/main/js/index.js | 6 +++ .../main/resources/locales/de/plugins.json | 10 ++-- .../main/resources/locales/en/plugins.json | 2 + .../repos/branches/containers/BranchView.js | 4 +- 7 files changed, 74 insertions(+), 33 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/main/js/GitBranchInformation.js diff --git a/scm-plugins/scm-git-plugin/src/main/js/CloneInformation.js b/scm-plugins/scm-git-plugin/src/main/js/CloneInformation.js index 177e662335..cdd08927e4 100644 --- a/scm-plugins/scm-git-plugin/src/main/js/CloneInformation.js +++ b/scm-plugins/scm-git-plugin/src/main/js/CloneInformation.js @@ -8,11 +8,10 @@ type Props = { repository: Repository, // context props - t: (string) => string + t: string => string }; class CloneInformation extends React.Component { - render() { const { url, repository, t } = this.props; @@ -51,7 +50,6 @@ class CloneInformation extends React.Component { ); } - } export default translate("plugins")(CloneInformation); diff --git a/scm-plugins/scm-git-plugin/src/main/js/GitBranchInformation.js b/scm-plugins/scm-git-plugin/src/main/js/GitBranchInformation.js new file mode 100644 index 0000000000..1453d7dd5e --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/js/GitBranchInformation.js @@ -0,0 +1,33 @@ +//@flow +import React from "react"; +import type { Repository } from "@scm-manager/ui-types"; +import { translate } from "react-i18next"; + +type Props = { + repository: Repository, + t: string => string +}; + +class GitBranchInformation extends React.Component { + render() { + const { repository, t } = this.props; + + return ( +
+

{t("scm-git-plugin.information.fetch")}

+
+          git fetch
+        
+

{t("scm-git-plugin.information.checkout")}

+
+          
+            git checkout -placeholder-
+            
+
+
+
+ ); // TODO: Placeholder + } +} + +export default translate("plugins")(GitBranchInformation); diff --git a/scm-plugins/scm-git-plugin/src/main/js/GitConfigurationForm.js b/scm-plugins/scm-git-plugin/src/main/js/GitConfigurationForm.js index 692611510f..bc7e51102a 100644 --- a/scm-plugins/scm-git-plugin/src/main/js/GitConfigurationForm.js +++ b/scm-plugins/scm-git-plugin/src/main/js/GitConfigurationForm.js @@ -10,7 +10,7 @@ type Configuration = { gcExpression?: string, nonFastForwardDisallowed: boolean, _links: Links -} +}; type Props = { initialConfiguration: Configuration, @@ -19,25 +19,24 @@ type Props = { onConfigurationChange: (Configuration, boolean) => void, // context props - t: (string) => string -} + t: string => string +}; -type State = Configuration & { - -} +type State = Configuration & {}; class GitConfigurationForm extends React.Component { - constructor(props: Props) { super(props); this.state = { ...props.initialConfiguration }; } - handleChange = (value: any, name: string) => { - this.setState({ - [name]: value - }, () => this.props.onConfigurationChange(this.state, true)); + this.setState( + { + [name]: value + }, + () => this.props.onConfigurationChange(this.state, true) + ); }; render() { @@ -46,24 +45,25 @@ class GitConfigurationForm extends React.Component { return ( <> - - ); } - } export default translate("plugins")(GitConfigurationForm); 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 43e3950beb..0dafbe4227 100644 --- a/scm-plugins/scm-git-plugin/src/main/js/index.js +++ b/scm-plugins/scm-git-plugin/src/main/js/index.js @@ -6,6 +6,7 @@ import GitAvatar from "./GitAvatar"; import {ConfigurationBinder as cfgBinder} from "@scm-manager/ui-components"; import GitGlobalConfiguration from "./GitGlobalConfiguration"; +import GitBranchInformation from "./GitBranchInformation"; import GitMergeInformation from "./GitMergeInformation"; import RepositoryConfig from "./RepositoryConfig"; @@ -20,6 +21,11 @@ binder.bind( ProtocolInformation, gitPredicate ); +binder.bind( + "repos.branch-details.information", + GitBranchInformation, + gitPredicate +); binder.bind( "repos.repository-merge.information", GitMergeInformation, diff --git a/scm-plugins/scm-git-plugin/src/main/resources/locales/de/plugins.json b/scm-plugins/scm-git-plugin/src/main/resources/locales/de/plugins.json index 578d859c8e..e150ceb42b 100644 --- a/scm-plugins/scm-git-plugin/src/main/resources/locales/de/plugins.json +++ b/scm-plugins/scm-git-plugin/src/main/resources/locales/de/plugins.json @@ -1,9 +1,11 @@ { "scm-git-plugin": { "information": { - "clone" : "Repository klonen", - "create" : "Neues Repository erstellen", - "replace" : "Ein bestehendes Repository aktualisieren", + "clone": "Repository klonen", + "create": "Neues Repository erstellen", + "replace": "Ein bestehendes Repository aktualisieren", + "fetch": "Remote-Änderungen herunterladen", + "checkout": "Branch wechseln", "merge": { "heading": "Merge des Source Branch in den Target Branch", "checkout": "1. Sicherstellen, dass der Workspace aufgeräumt ist und der Target Branch ausgecheckt wurde.", @@ -37,7 +39,7 @@ "success": "Der standard Branch wurde geändert!" } }, - "permissions" : { + "permissions": { "configuration": { "read,write": { "git": { 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 bea0a08dc9..22eb46b9f8 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 @@ -4,6 +4,8 @@ "clone": "Clone the repository", "create": "Create a new repository", "replace": "Push an existing repository", + "fetch": "Get remote changes", + "checkout": "Switch branch", "merge": { "heading": "How to merge source branch into target branch", "checkout": "1. Make sure your workspace is clean and checkout target branch", diff --git a/scm-ui/src/repos/branches/containers/BranchView.js b/scm-ui/src/repos/branches/containers/BranchView.js index 459a532b4a..3fe2985fb5 100644 --- a/scm-ui/src/repos/branches/containers/BranchView.js +++ b/scm-ui/src/repos/branches/containers/BranchView.js @@ -82,8 +82,8 @@ const mapStateToProps = (state, ownProps) => { const mapDispatchToProps = dispatch => { return { - fetchBranchByName: (repository: string, branchName: string) => { - dispatch(fetchBranchByName(repository, branchName)); + fetchBranchByName: (repository: Repository, branchName: string) => { + dispatch(fetchBranchByName(repository._links.branches.href, branchName)); } }; }; From eaf3641d6f6cb64e7775c354808c638661aa2a90 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Mon, 1 Apr 2019 13:12:34 +0200 Subject: [PATCH 17/37] fixed get branch, added tests --- .../repos/branches/containers/BranchView.js | 8 +++- scm-ui/src/repos/modules/branches.js | 45 ++++++++++--------- scm-ui/src/repos/modules/branches.test.js | 43 ++++++++++++++++++ 3 files changed, 72 insertions(+), 24 deletions(-) diff --git a/scm-ui/src/repos/branches/containers/BranchView.js b/scm-ui/src/repos/branches/containers/BranchView.js index 3fe2985fb5..fd65f6eab0 100644 --- a/scm-ui/src/repos/branches/containers/BranchView.js +++ b/scm-ui/src/repos/branches/containers/BranchView.js @@ -8,6 +8,7 @@ import { translate } from "react-i18next"; import { withRouter } from "react-router-dom"; import { fetchBranchByName, + getBranchByName, getFetchBranchFailure, isFetchBranchPending } from "../../modules/branches"; @@ -70,11 +71,14 @@ class BranchView extends React.Component { const mapStateToProps = (state, ownProps) => { const { repository } = ownProps; const branchName = decodeURIComponent(ownProps.match.params.branch); - const loading = isFetchBranchPending(state, repository, branchName); - const error = getFetchBranchFailure(state, repository, branchName); + const branch = getBranchByName(state, branchName); + console.log(branchName + " Branch:",branch); + const loading = isFetchBranchPending(state, branchName); + const error = getFetchBranchFailure(state, branchName); return { repository, branchName, + branch, loading, error }; diff --git a/scm-ui/src/repos/modules/branches.js b/scm-ui/src/repos/modules/branches.js index 6020ec54de..15dfb9c714 100644 --- a/scm-ui/src/repos/modules/branches.js +++ b/scm-ui/src/repos/modules/branches.js @@ -34,6 +34,14 @@ export function fetchBranchPending(name: string): Action { }; } +export function fetchBranchSuccess(branch: Branch): Action { + return { + type: FETCH_BRANCH_SUCCESS, + payload: branch, + itemId: branch.name + }; +} + export function fetchBranchFailure(name: string, error: Error): Action { return { type: FETCH_BRANCH_FAILURE, @@ -59,32 +67,19 @@ export function fetchBranch(link: string, name: string) { }; } -export function getFetchBranchFailure( - state: Object, - repository: string, - branchName: string -) { - return getFailure( - state, - FETCH_BRANCH, - repository + "/branches/" + branchName - ); +export function getBranchByName(state: Object, name: string) { + console.log("State:", state); + if (state.branches) { + return state.branches[name]; + } } -export function isFetchBranchPending( - state: Object, - repository: string, - branchName: string -) { - return isPending(state, FETCH_BRANCH, repository + "/branches/" + branchName); +export function isFetchBranchPending(state: Object, name: string) { + return isPending(state, FETCH_BRANCH, name); } -export function fetchBranchSuccess(branch: Branch): Action { - return { - type: FETCH_BRANCH_SUCCESS, - payload: branch, - itemId: branch.name - }; +export function getFetchBranchFailure(state: Object, name: string) { + return getFailure(state, FETCH_BRANCH, name); } export function fetchBranches(repository: Repository) { @@ -154,6 +149,12 @@ export default function reducer( ...state, [key]: extractBranchesFromPayload(payload.data) }; + case FETCH_BRANCH_SUCCESS: + return { + ...state, + [action.payload.name]: action.payload + }; + default: return state; } diff --git a/scm-ui/src/repos/modules/branches.test.js b/scm-ui/src/repos/modules/branches.test.js index bcbae28611..1f33992b65 100644 --- a/scm-ui/src/repos/modules/branches.test.js +++ b/scm-ui/src/repos/modules/branches.test.js @@ -6,7 +6,14 @@ import reducer, { FETCH_BRANCHES_FAILURE, FETCH_BRANCHES_PENDING, FETCH_BRANCHES_SUCCESS, + FETCH_BRANCH, + FETCH_BRANCH_PENDING, + FETCH_BRANCH_SUCCESS, + FETCH_BRANCH_FAILURE, fetchBranches, + fetchBranchByName, + fetchBranchSuccess, + fetchBranch, getBranch, getBranches, getFetchBranchesFailure, @@ -88,6 +95,32 @@ describe("branches", () => { expect(store.getActions()[1].type).toEqual(FETCH_BRANCHES_FAILURE); }); }); + + it("should successfully fetch single branch", () => { + fetchMock.getOnce(URL + "/branch1", branch1); + + const store = mockStore({}); + return store.dispatch(fetchBranchByName(URL, "branch1")).then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(FETCH_BRANCH_PENDING); + expect(actions[1].type).toEqual(FETCH_BRANCH_SUCCESS); + expect(actions[1].payload).toBeDefined(); + }); + }); + + it("should fail fetching single branch on HTTP 500", () => { + fetchMock.getOnce(URL + "/branch2", { + status: 500 + }); + + const store = mockStore({}); + return store.dispatch(fetchBranchByName(URL, "branch2")).then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(FETCH_BRANCH_PENDING); + expect(actions[1].type).toEqual(FETCH_BRANCH_FAILURE); + expect(actions[1].payload).toBeDefined(); + }); + }); }); describe("branches reducer", () => { @@ -123,6 +156,16 @@ describe("branches", () => { expect(newState["hitchhiker/heartOfGold"]).toContain(branch3); }); + + it("should update state according to FETCH_BRANCH_SUCCESS action", () => { + const newState = reducer({}, fetchBranchSuccess(branch3)); + expect(newState["branch3"]).toBe(branch3); + }); + + it("should update state according to FETCH_BRANCH_SUCCESS action", () => { + const newState = reducer({}, fetchBranch(URL + "/branch1", "branch1")); + expect(newState["branch1"]).toBe(branch1); + }); }); describe("branch selectors", () => { From 5420884f5a2e6a39ad1543afd357464cc2b56094 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Mon, 1 Apr 2019 13:47:41 +0200 Subject: [PATCH 18/37] added hg and git branch manual --- .../src/main/js/GitBranchInformation.js | 13 ++++---- .../src/main/js/HgBranchInformation.js | 30 +++++++++++++++++++ .../scm-hg-plugin/src/main/js/index.js | 19 ++++++++++-- .../main/resources/locales/de/plugins.json | 4 ++- .../main/resources/locales/en/plugins.json | 4 ++- .../branches/components/BranchDetailTable.js | 21 ++++++++++--- 6 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 scm-plugins/scm-hg-plugin/src/main/js/HgBranchInformation.js diff --git a/scm-plugins/scm-git-plugin/src/main/js/GitBranchInformation.js b/scm-plugins/scm-git-plugin/src/main/js/GitBranchInformation.js index 1453d7dd5e..b4c1873e9f 100644 --- a/scm-plugins/scm-git-plugin/src/main/js/GitBranchInformation.js +++ b/scm-plugins/scm-git-plugin/src/main/js/GitBranchInformation.js @@ -1,16 +1,16 @@ //@flow import React from "react"; -import type { Repository } from "@scm-manager/ui-types"; +import type { Branch } from "@scm-manager/ui-types"; import { translate } from "react-i18next"; type Props = { - repository: Repository, + branch: Branch, t: string => string }; class GitBranchInformation extends React.Component { render() { - const { repository, t } = this.props; + const { branch, t } = this.props; return (
@@ -20,13 +20,10 @@ class GitBranchInformation extends React.Component {

{t("scm-git-plugin.information.checkout")}

-          
-            git checkout -placeholder-
-            
-
+ git checkout {branch.name}
- ); // TODO: Placeholder + ); } } diff --git a/scm-plugins/scm-hg-plugin/src/main/js/HgBranchInformation.js b/scm-plugins/scm-hg-plugin/src/main/js/HgBranchInformation.js new file mode 100644 index 0000000000..358a682054 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/js/HgBranchInformation.js @@ -0,0 +1,30 @@ +//@flow +import React from "react"; +import type { Branch } from "@scm-manager/ui-types"; +import { translate } from "react-i18next"; + +type Props = { + branch: Branch, + t: string => string +}; + +class HgBranchInformation extends React.Component { + render() { + const { branch, t } = this.props; + + return ( +
+

{t("scm-hg-plugin.information.fetch")}

+
+          hg pull
+        
+

{t("scm-hg-plugin.information.checkout")}

+
+          hg update {branch.name}
+        
+
+ ); + } +} + +export default translate("plugins")(HgBranchInformation); diff --git a/scm-plugins/scm-hg-plugin/src/main/js/index.js b/scm-plugins/scm-hg-plugin/src/main/js/index.js index a1fa72f5bd..9df4512d10 100644 --- a/scm-plugins/scm-hg-plugin/src/main/js/index.js +++ b/scm-plugins/scm-hg-plugin/src/main/js/index.js @@ -4,14 +4,29 @@ import ProtocolInformation from "./ProtocolInformation"; import HgAvatar from "./HgAvatar"; import { ConfigurationBinder as cfgBinder } from "@scm-manager/ui-components"; import HgGlobalConfiguration from "./HgGlobalConfiguration"; +import HgBranchInformation from "./HgBranchInformation"; const hgPredicate = (props: Object) => { return props.repository && props.repository.type === "hg"; }; -binder.bind("repos.repository-details.information", ProtocolInformation, hgPredicate); +binder.bind( + "repos.repository-details.information", + ProtocolInformation, + hgPredicate +); +binder.bind( + "repos.branch-details.information", + HgBranchInformation, + hgPredicate +); binder.bind("repos.repository-avatar", HgAvatar, hgPredicate); // bind global configuration -cfgBinder.bindGlobal("/hg", "scm-hg-plugin.config.link", "hgConfig", HgGlobalConfiguration); +cfgBinder.bindGlobal( + "/hg", + "scm-hg-plugin.config.link", + "hgConfig", + HgGlobalConfiguration +); diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/locales/de/plugins.json b/scm-plugins/scm-hg-plugin/src/main/resources/locales/de/plugins.json index 63a8cc8a98..d32847a3af 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/locales/de/plugins.json +++ b/scm-plugins/scm-hg-plugin/src/main/resources/locales/de/plugins.json @@ -3,7 +3,9 @@ "information": { "clone" : "Repository klonen", "create" : "Neues Repository erstellen", - "replace" : "Ein bestehendes Repository aktualisieren" + "replace" : "Ein bestehendes Repository aktualisieren", + "fetch": "Remote-Änderungen herunterladen", + "checkout": "Branch wechseln" }, "config": { "link": "Mercurial", diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/locales/en/plugins.json b/scm-plugins/scm-hg-plugin/src/main/resources/locales/en/plugins.json index a5d05d5796..3792bd4a47 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/locales/en/plugins.json +++ b/scm-plugins/scm-hg-plugin/src/main/resources/locales/en/plugins.json @@ -3,7 +3,9 @@ "information": { "clone" : "Clone the repository", "create" : "Create a new repository", - "replace" : "Push an existing repository" + "replace" : "Push an existing repository", + "fetch": "Get remote changes", + "checkout": "Switch branch" }, "config": { "link": "Mercurial", diff --git a/scm-ui/src/repos/branches/components/BranchDetailTable.js b/scm-ui/src/repos/branches/components/BranchDetailTable.js index 15a8b6236e..08935aa26c 100644 --- a/scm-ui/src/repos/branches/components/BranchDetailTable.js +++ b/scm-ui/src/repos/branches/components/BranchDetailTable.js @@ -14,12 +14,15 @@ type Props = { class BranchDetailTable extends React.Component { render() { const { repository, branch, t } = this.props; + return ( - + - + -
{t("branch.name")}branch.name + {branch.name} {this.renderDefaultBranch()} +
@@ -28,15 +31,25 @@ class BranchDetailTable extends React.Component { {repository.name}
- {t("branch.actions")} + {t("branch.actions")} +
); } + + renderDefaultBranch() { + const { branch } = this.props; + + let defaultLabel = null; + if (branch.defaultBranch) { + defaultLabel = Default; + } + return defaultLabel; + } } export default translate("repos")(BranchDetailTable); From 7f1aeb0492879c823745b089374f97e0576dfe96 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Mon, 1 Apr 2019 15:13:44 +0200 Subject: [PATCH 19/37] restyled branches overview tabled, fixed en/decoded branch name --- scm-ui/src/repos/branches/components/BranchDetailTable.js | 8 ++++---- scm-ui/src/repos/branches/containers/BranchView.js | 1 - scm-ui/src/repos/modules/branches.js | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/scm-ui/src/repos/branches/components/BranchDetailTable.js b/scm-ui/src/repos/branches/components/BranchDetailTable.js index 08935aa26c..53718c5b6d 100644 --- a/scm-ui/src/repos/branches/components/BranchDetailTable.js +++ b/scm-ui/src/repos/branches/components/BranchDetailTable.js @@ -19,19 +19,19 @@ class BranchDetailTable extends React.Component { - + - - + diff --git a/scm-ui/src/repos/branches/containers/BranchView.js b/scm-ui/src/repos/branches/containers/BranchView.js index fd65f6eab0..4774e2825a 100644 --- a/scm-ui/src/repos/branches/containers/BranchView.js +++ b/scm-ui/src/repos/branches/containers/BranchView.js @@ -72,7 +72,6 @@ const mapStateToProps = (state, ownProps) => { const { repository } = ownProps; const branchName = decodeURIComponent(ownProps.match.params.branch); const branch = getBranchByName(state, branchName); - console.log(branchName + " Branch:",branch); const loading = isFetchBranchPending(state, branchName); const error = getFetchBranchFailure(state, branchName); return { diff --git a/scm-ui/src/repos/modules/branches.js b/scm-ui/src/repos/modules/branches.js index 15dfb9c714..5c9a63b5d6 100644 --- a/scm-ui/src/repos/modules/branches.js +++ b/scm-ui/src/repos/modules/branches.js @@ -22,7 +22,7 @@ export const FETCH_BRANCH_FAILURE = `${FETCH_BRANCH}_${FAILURE_SUFFIX}`; // Fetching branches export function fetchBranchByName(link: string, name: string) { - const branchUrl = link.endsWith("/") ? link + name : link + "/" + name; + const branchUrl = link.endsWith("/") ? link + encodeURIComponent(name) : link + "/" + encodeURIComponent(name); return fetchBranch(branchUrl, name); } @@ -68,7 +68,6 @@ export function fetchBranch(link: string, name: string) { } export function getBranchByName(state: Object, name: string) { - console.log("State:", state); if (state.branches) { return state.branches[name]; } From d6ead4fa8234f69c4ce631c636f031ec158b71cd Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Mon, 1 Apr 2019 15:25:55 +0200 Subject: [PATCH 20/37] created repo specific xhangeset and sourceslink --- .../branches/components/BranchButtonGroup.js | 5 ++-- scm-ui/src/repos/modules/branches.js | 23 +++++++++++++++++-- scm-ui/src/repos/modules/branches.test.js | 5 ---- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/scm-ui/src/repos/branches/components/BranchButtonGroup.js b/scm-ui/src/repos/branches/components/BranchButtonGroup.js index 2ed49d7b1f..b7c7a843ec 100644 --- a/scm-ui/src/repos/branches/components/BranchButtonGroup.js +++ b/scm-ui/src/repos/branches/components/BranchButtonGroup.js @@ -3,6 +3,7 @@ import React from "react"; import type { Repository, Branch } from "@scm-manager/ui-types"; import { ButtonGroup, Button } from "@scm-manager/ui-components"; import { translate } from "react-i18next"; +import { createChangesetLink, createSourcesLink } from "../../modules/branches"; type Props = { repository: Repository, @@ -16,8 +17,8 @@ class BranchButtonGroup extends React.Component { render() { const { repository, branch, t } = this.props; - const changesetLink = ""; - const sourcesLink = ""; + const changesetLink = createChangesetLink(repository, branch); + const sourcesLink = createSourcesLink(repository, branch); return ( diff --git a/scm-ui/src/repos/modules/branches.js b/scm-ui/src/repos/modules/branches.js index 5c9a63b5d6..8397ac3011 100644 --- a/scm-ui/src/repos/modules/branches.js +++ b/scm-ui/src/repos/modules/branches.js @@ -5,7 +5,12 @@ import { SUCCESS_SUFFIX } from "../../modules/types"; import { apiClient } from "@scm-manager/ui-components"; -import type { Action, Branch, Repository } from "@scm-manager/ui-types"; +import type { + Action, + Branch, + Changeset, + Repository +} from "@scm-manager/ui-types"; import { isPending } from "../../modules/pending"; import { getFailure } from "../../modules/failure"; @@ -22,7 +27,9 @@ export const FETCH_BRANCH_FAILURE = `${FETCH_BRANCH}_${FAILURE_SUFFIX}`; // Fetching branches export function fetchBranchByName(link: string, name: string) { - const branchUrl = link.endsWith("/") ? link + encodeURIComponent(name) : link + "/" + encodeURIComponent(name); + const branchUrl = link.endsWith("/") + ? link + encodeURIComponent(name) + : link + "/" + encodeURIComponent(name); return fetchBranch(branchUrl, name); } @@ -203,3 +210,15 @@ function createKey(repository: Repository): string { const { namespace, name } = repository; return `${namespace}/${name}`; } + +export function createChangesetLink(repository: Repository, branch: Branch) { + return `/repo/${repository.namespace}/${ + repository.name + }/branch/${encodeURIComponent(branch.name)}/changesets/`; +} + +export function createSourcesLink(repository: Repository, branch: Branch) { + return `/repo/${repository.namespace}/${ + repository.name + }/sources/${encodeURIComponent(branch.name)}/`; +} diff --git a/scm-ui/src/repos/modules/branches.test.js b/scm-ui/src/repos/modules/branches.test.js index 1f33992b65..5e9b4e0f1f 100644 --- a/scm-ui/src/repos/modules/branches.test.js +++ b/scm-ui/src/repos/modules/branches.test.js @@ -161,11 +161,6 @@ describe("branches", () => { const newState = reducer({}, fetchBranchSuccess(branch3)); expect(newState["branch3"]).toBe(branch3); }); - - it("should update state according to FETCH_BRANCH_SUCCESS action", () => { - const newState = reducer({}, fetchBranch(URL + "/branch1", "branch1")); - expect(newState["branch1"]).toBe(branch1); - }); }); describe("branch selectors", () => { From 2ba57dc141d29fc564890488e536b35ce20bda3a Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Mon, 1 Apr 2019 15:32:29 +0200 Subject: [PATCH 21/37] small code improvement --- scm-ui/src/repos/modules/branches.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scm-ui/src/repos/modules/branches.js b/scm-ui/src/repos/modules/branches.js index 8397ac3011..62299801d6 100644 --- a/scm-ui/src/repos/modules/branches.js +++ b/scm-ui/src/repos/modules/branches.js @@ -27,10 +27,11 @@ export const FETCH_BRANCH_FAILURE = `${FETCH_BRANCH}_${FAILURE_SUFFIX}`; // Fetching branches export function fetchBranchByName(link: string, name: string) { - const branchUrl = link.endsWith("/") - ? link + encodeURIComponent(name) - : link + "/" + encodeURIComponent(name); - return fetchBranch(branchUrl, name); + let endsWith = ""; + if(!link.endsWith("/")) { + endsWith = "/"; + } + return fetchBranch(link + endsWith + encodeURIComponent(name), name); } export function fetchBranchPending(name: string): Action { From d8a33e0fc219117e7ad39ddf5b21cd83dcfbc19c Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Mon, 1 Apr 2019 15:58:07 +0200 Subject: [PATCH 22/37] vcentered default branch label + more spacing --- .../branches/components/BranchDetailTable.js | 24 +++++++++++++------ .../repos/branches/components/BranchRow.js | 20 +++++++++++++--- scm-ui/src/repos/modules/branches.js | 1 - 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/scm-ui/src/repos/branches/components/BranchDetailTable.js b/scm-ui/src/repos/branches/components/BranchDetailTable.js index 53718c5b6d..27c4907a53 100644 --- a/scm-ui/src/repos/branches/components/BranchDetailTable.js +++ b/scm-ui/src/repos/branches/components/BranchDetailTable.js @@ -2,13 +2,23 @@ import React from "react"; import type { Repository, Branch } from "@scm-manager/ui-types"; import { translate } from "react-i18next"; +import injectSheet from "react-jss"; +import classNames from "classnames"; import BranchButtonGroup from "./BranchButtonGroup"; type Props = { repository: Repository, branch: Branch, // context props - t: string => string + t: string => string, + classes: any +}; + +const styles = { + tag: { + marginLeft: "0.75rem", + verticalAlign: "inherit" + } }; class BranchDetailTable extends React.Component { @@ -25,9 +35,7 @@ class BranchDetailTable extends React.Component { - + @@ -42,14 +50,16 @@ class BranchDetailTable extends React.Component { } renderDefaultBranch() { - const { branch } = this.props; + const { branch, classes } = this.props; let defaultLabel = null; if (branch.defaultBranch) { - defaultLabel = Default; + defaultLabel = ( + Default + ); } return defaultLabel; } } -export default translate("repos")(BranchDetailTable); +export default injectSheet(styles)(translate("repos")(BranchDetailTable)); diff --git a/scm-ui/src/repos/branches/components/BranchRow.js b/scm-ui/src/repos/branches/components/BranchRow.js index 873bc066c7..06cb52c268 100644 --- a/scm-ui/src/repos/branches/components/BranchRow.js +++ b/scm-ui/src/repos/branches/components/BranchRow.js @@ -2,17 +2,29 @@ import React from "react"; import { Link } from "react-router-dom"; import type { Branch } from "@scm-manager/ui-types"; +import injectSheet from "react-jss"; +import classNames from "classnames"; type Props = { baseUrl: string, - branch: Branch + branch: Branch, + classes: any }; -export default class BranchRow extends React.Component { +const styles = { + tag: { + marginLeft: "0.75rem", + verticalAlign: "inherit" + } +}; + +class BranchRow extends React.Component { renderLink(to: string, label: string, defaultBranch: boolean) { + const { classes } = this.props; + let showLabel = null; if (defaultBranch) { - showLabel = Default; + showLabel = Default; } return ( @@ -31,3 +43,5 @@ export default class BranchRow extends React.Component { ); } } + +export default injectSheet(styles)(BranchRow); diff --git a/scm-ui/src/repos/modules/branches.js b/scm-ui/src/repos/modules/branches.js index 62299801d6..9468443fea 100644 --- a/scm-ui/src/repos/modules/branches.js +++ b/scm-ui/src/repos/modules/branches.js @@ -8,7 +8,6 @@ import { apiClient } from "@scm-manager/ui-components"; import type { Action, Branch, - Changeset, Repository } from "@scm-manager/ui-types"; import { isPending } from "../../modules/pending"; From db0a835bca27ea52f03e6cb81d7ae29910b21b03 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Tue, 2 Apr 2019 09:27:34 +0200 Subject: [PATCH 23/37] added create branch trans, fixed branchtable trans, moved branches modules --- scm-ui/public/locales/de/repos.json | 5 ++++- scm-ui/public/locales/en/repos.json | 5 ++++- scm-ui/src/createReduxStore.js | 2 +- .../branches/components/BranchButtonGroup.js | 2 +- .../src/repos/branches/components/BranchForm.js | 16 ++++++++++++++++ .../src/repos/branches/components/BranchTable.js | 2 +- .../src/repos/branches/containers/BranchView.js | 2 +- .../branches/containers/BranchesOverview.js | 2 +- .../src/repos/{ => branches}/modules/branches.js | 6 +++--- .../{ => branches}/modules/branches.test.js | 2 +- scm-ui/src/repos/containers/ChangesetsRoot.js | 2 +- scm-ui/src/repos/sources/containers/Sources.js | 2 +- 12 files changed, 35 insertions(+), 13 deletions(-) create mode 100644 scm-ui/src/repos/branches/components/BranchForm.js rename scm-ui/src/repos/{ => branches}/modules/branches.js (97%) rename scm-ui/src/repos/{ => branches}/modules/branches.test.js (99%) diff --git a/scm-ui/public/locales/de/repos.json b/scm-ui/public/locales/de/repos.json index 8350ecc581..3a90f9080a 100644 --- a/scm-ui/public/locales/de/repos.json +++ b/scm-ui/public/locales/de/repos.json @@ -54,7 +54,10 @@ "branches": "Branches" }, "create": { - "title": "Branch erstellen" + "title": "Branch erstellen", + "source": "Quellbranch", + "name": "Name", + "submit": "Branch erstellen" } }, "branch": { diff --git a/scm-ui/public/locales/en/repos.json b/scm-ui/public/locales/en/repos.json index fef882c90e..6adede7b82 100644 --- a/scm-ui/public/locales/en/repos.json +++ b/scm-ui/public/locales/en/repos.json @@ -54,7 +54,10 @@ "branches": "Branches" }, "create": { - "title": "Create Branch" + "title": "Create Branch", + "source": "Source Branch", + "name": "Name", + "submit": "Create Branch" } }, "branch": { diff --git a/scm-ui/src/createReduxStore.js b/scm-ui/src/createReduxStore.js index cd24f46de2..eb0586d657 100644 --- a/scm-ui/src/createReduxStore.js +++ b/scm-ui/src/createReduxStore.js @@ -19,7 +19,7 @@ import namespaceStrategies from "./config/modules/namespaceStrategies"; import indexResources from "./modules/indexResource"; import type { BrowserHistory } from "history/createBrowserHistory"; -import branches from "./repos/modules/branches"; +import branches from "./repos/branches/modules/branches"; function createReduxStore(history: BrowserHistory) { const composeEnhancers = diff --git a/scm-ui/src/repos/branches/components/BranchButtonGroup.js b/scm-ui/src/repos/branches/components/BranchButtonGroup.js index b7c7a843ec..dc170963e9 100644 --- a/scm-ui/src/repos/branches/components/BranchButtonGroup.js +++ b/scm-ui/src/repos/branches/components/BranchButtonGroup.js @@ -3,7 +3,7 @@ import React from "react"; import type { Repository, Branch } from "@scm-manager/ui-types"; import { ButtonGroup, Button } from "@scm-manager/ui-components"; import { translate } from "react-i18next"; -import { createChangesetLink, createSourcesLink } from "../../modules/branches"; +import { createChangesetLink, createSourcesLink } from "../modules/branches"; type Props = { repository: Repository, diff --git a/scm-ui/src/repos/branches/components/BranchForm.js b/scm-ui/src/repos/branches/components/BranchForm.js new file mode 100644 index 0000000000..614a719338 --- /dev/null +++ b/scm-ui/src/repos/branches/components/BranchForm.js @@ -0,0 +1,16 @@ +//@flow +import React from "react"; + +type Props = {}; + +class CreateBranch extends React.Component { + render() { + return ( + <> +

Form placeholder

+ + ); + } +} + +export default translate("repos")(BranchForm); diff --git a/scm-ui/src/repos/branches/components/BranchTable.js b/scm-ui/src/repos/branches/components/BranchTable.js index e85fa0d625..85dd854f21 100644 --- a/scm-ui/src/repos/branches/components/BranchTable.js +++ b/scm-ui/src/repos/branches/components/BranchTable.js @@ -37,4 +37,4 @@ class BranchTable extends React.Component { } } -export default translate("users")(BranchTable); +export default translate("repos")(BranchTable); diff --git a/scm-ui/src/repos/branches/containers/BranchView.js b/scm-ui/src/repos/branches/containers/BranchView.js index 4774e2825a..5a90812ac9 100644 --- a/scm-ui/src/repos/branches/containers/BranchView.js +++ b/scm-ui/src/repos/branches/containers/BranchView.js @@ -11,7 +11,7 @@ import { getBranchByName, getFetchBranchFailure, isFetchBranchPending -} from "../../modules/branches"; +} from "../modules/branches"; import { ErrorPage, Loading } from "@scm-manager/ui-components"; type Props = { diff --git a/scm-ui/src/repos/branches/containers/BranchesOverview.js b/scm-ui/src/repos/branches/containers/BranchesOverview.js index b39c821494..4f4ca4a75d 100644 --- a/scm-ui/src/repos/branches/containers/BranchesOverview.js +++ b/scm-ui/src/repos/branches/containers/BranchesOverview.js @@ -5,7 +5,7 @@ import { getBranches, getFetchBranchesFailure, isFetchBranchesPending -} from "../../modules/branches"; +} from "../modules/branches"; import { connect } from "react-redux"; import type { Branch, Repository } from "@scm-manager/ui-types"; import { compose } from "redux"; diff --git a/scm-ui/src/repos/modules/branches.js b/scm-ui/src/repos/branches/modules/branches.js similarity index 97% rename from scm-ui/src/repos/modules/branches.js rename to scm-ui/src/repos/branches/modules/branches.js index 9468443fea..03c0c1a9eb 100644 --- a/scm-ui/src/repos/modules/branches.js +++ b/scm-ui/src/repos/branches/modules/branches.js @@ -3,15 +3,15 @@ import { FAILURE_SUFFIX, PENDING_SUFFIX, SUCCESS_SUFFIX -} from "../../modules/types"; +} from "../../../modules/types"; import { apiClient } from "@scm-manager/ui-components"; import type { Action, Branch, Repository } from "@scm-manager/ui-types"; -import { isPending } from "../../modules/pending"; -import { getFailure } from "../../modules/failure"; +import { isPending } from "../../../modules/pending"; +import { getFailure } from "../../../modules/failure"; export const FETCH_BRANCHES = "scm/repos/FETCH_BRANCHES"; export const FETCH_BRANCHES_PENDING = `${FETCH_BRANCHES}_${PENDING_SUFFIX}`; diff --git a/scm-ui/src/repos/modules/branches.test.js b/scm-ui/src/repos/branches/modules/branches.test.js similarity index 99% rename from scm-ui/src/repos/modules/branches.test.js rename to scm-ui/src/repos/branches/modules/branches.test.js index 5e9b4e0f1f..754a3803e9 100644 --- a/scm-ui/src/repos/modules/branches.test.js +++ b/scm-ui/src/repos/branches/modules/branches.test.js @@ -1,5 +1,5 @@ import configureMockStore from "redux-mock-store"; -import thunk from "redux-thunk"; +import thunk from "redux-thunk/index"; import fetchMock from "fetch-mock"; import reducer, { FETCH_BRANCHES, diff --git a/scm-ui/src/repos/containers/ChangesetsRoot.js b/scm-ui/src/repos/containers/ChangesetsRoot.js index f6e0c3d359..c4f40e0d74 100644 --- a/scm-ui/src/repos/containers/ChangesetsRoot.js +++ b/scm-ui/src/repos/containers/ChangesetsRoot.js @@ -16,7 +16,7 @@ import { getBranches, getFetchBranchesFailure, isFetchBranchesPending -} from "../modules/branches"; +} from "../branches/modules/branches"; import { compose } from "redux"; type Props = { diff --git a/scm-ui/src/repos/sources/containers/Sources.js b/scm-ui/src/repos/sources/containers/Sources.js index 05705a61d1..7b87776e73 100644 --- a/scm-ui/src/repos/sources/containers/Sources.js +++ b/scm-ui/src/repos/sources/containers/Sources.js @@ -12,7 +12,7 @@ import { getBranches, getFetchBranchesFailure, isFetchBranchesPending -} from "../../modules/branches"; +} from "../../branches/modules/branches"; import { compose } from "redux"; import Content from "./Content"; import { fetchSources, isDirectory } from "../modules/sources"; From e736add3fd6c8bc1b284dc049247d37dd3e1f54e Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Tue, 2 Apr 2019 10:27:00 +0200 Subject: [PATCH 24/37] added branch reducer tests --- scm-ui/src/repos/branches/modules/branches.js | 2 +- .../repos/branches/modules/branches.test.js | 36 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/scm-ui/src/repos/branches/modules/branches.js b/scm-ui/src/repos/branches/modules/branches.js index 03c0c1a9eb..a080a3877f 100644 --- a/scm-ui/src/repos/branches/modules/branches.js +++ b/scm-ui/src/repos/branches/modules/branches.js @@ -41,7 +41,7 @@ export function fetchBranchPending(name: string): Action { }; } -export function fetchBranchSuccess(branch: Branch): Action { +export function fetchBranchSuccess(repo: Repository, branch: Branch): Action { return { type: FETCH_BRANCH_SUCCESS, payload: branch, diff --git a/scm-ui/src/repos/branches/modules/branches.test.js b/scm-ui/src/repos/branches/modules/branches.test.js index 754a3803e9..cc67aaf33a 100644 --- a/scm-ui/src/repos/branches/modules/branches.test.js +++ b/scm-ui/src/repos/branches/modules/branches.test.js @@ -1,5 +1,5 @@ import configureMockStore from "redux-mock-store"; -import thunk from "redux-thunk/index"; +import thunk from "redux-thunk"; import fetchMock from "fetch-mock"; import reducer, { FETCH_BRANCHES, @@ -161,6 +161,40 @@ describe("branches", () => { const newState = reducer({}, fetchBranchSuccess(branch3)); expect(newState["branch3"]).toBe(branch3); }); + + it("should not delete existing branch from state", () => { + const oldState = { + branch1 + }; + + const newState = reducer(oldState, fetchBranchSuccess(branch2)); + expect(newState["branch1"]).toBe(branch1); + expect(newState["branch2"]).toBe(branch2); + }); + + it("should update required branch from state", () => { + const oldState = { + branch1 + }; + + const newBranch1 = { name: "branch1", revision: "revision2" }; + + const newState = reducer(oldState, fetchBranchSuccess(newBranch1)); + expect(newState["branch1"]).not.toBe(branch1); + expect(newState["branch1"]).toBe(newBranch1); + }); + + it("should update required branch from state and keeps old repo", () => { + const oldState = { + repo1: { + branch1 + } + }; + const repo2 = { repo2: { branch3 } }; + const newState = reducer(oldState, fetchBranchSuccess(repo2, branch2)); + expect(newState["repo1"]).toBe({ branch1 }); + expect(newState["repo2"]).toBe({ branch2, branch3 }); + }); }); describe("branch selectors", () => { From 7c61efb20bcc1b67921840da9e543b7e3982ca50 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Tue, 2 Apr 2019 17:31:32 +0200 Subject: [PATCH 25/37] added defaultBranch to Branches type, changed ui-bundler version for better testing experience in intellij, corrected fetchBranch functionality, wrote reducer for single branch and unit tests --- .../packages/ui-types/src/Branches.js | 1 + scm-ui/package.json | 2 +- .../repos/branches/components/BranchRow.js | 12 +-- .../repos/branches/containers/BranchView.js | 16 ++-- scm-ui/src/repos/branches/modules/branches.js | 90 ++++++++++++------- .../repos/branches/modules/branches.test.js | 60 +++++++------ scm-ui/yarn.lock | 7 +- 7 files changed, 112 insertions(+), 76 deletions(-) diff --git a/scm-ui-components/packages/ui-types/src/Branches.js b/scm-ui-components/packages/ui-types/src/Branches.js index f209de34a0..2dee365424 100644 --- a/scm-ui-components/packages/ui-types/src/Branches.js +++ b/scm-ui-components/packages/ui-types/src/Branches.js @@ -4,5 +4,6 @@ import type {Links} from "./hal"; export type Branch = { name: string, revision: string, + defaultBranch?: boolean, _links: Links } diff --git a/scm-ui/package.json b/scm-ui/package.json index 6844ea3ec7..78c7b0e684 100644 --- a/scm-ui/package.json +++ b/scm-ui/package.json @@ -52,7 +52,7 @@ "pre-commit": "jest && flow && eslint src" }, "devDependencies": { - "@scm-manager/ui-bundler": "^0.0.26", + "@scm-manager/ui-bundler": "^0.0.27", "concat": "^1.0.3", "copyfiles": "^2.0.0", "enzyme": "^3.3.0", diff --git a/scm-ui/src/repos/branches/components/BranchRow.js b/scm-ui/src/repos/branches/components/BranchRow.js index 06cb52c268..d8f70575b3 100644 --- a/scm-ui/src/repos/branches/components/BranchRow.js +++ b/scm-ui/src/repos/branches/components/BranchRow.js @@ -19,7 +19,7 @@ const styles = { }; class BranchRow extends React.Component { - renderLink(to: string, label: string, defaultBranch: boolean) { + renderLink(to: string, label: string, defaultBranch?: boolean) { const { classes } = this.props; let showLabel = null; @@ -36,11 +36,11 @@ class BranchRow extends React.Component { render() { const { baseUrl, branch } = this.props; const to = `${baseUrl}/${encodeURIComponent(branch.name)}/info`; - return ( -
- - - ); + return ( + + + + ); } } diff --git a/scm-ui/src/repos/branches/containers/BranchView.js b/scm-ui/src/repos/branches/containers/BranchView.js index 5a90812ac9..959c4519d0 100644 --- a/scm-ui/src/repos/branches/containers/BranchView.js +++ b/scm-ui/src/repos/branches/containers/BranchView.js @@ -7,8 +7,8 @@ import { connect } from "react-redux"; import { translate } from "react-i18next"; import { withRouter } from "react-router-dom"; import { - fetchBranchByName, - getBranchByName, + fetchBranch, + getBranch, getFetchBranchFailure, isFetchBranchPending } from "../modules/branches"; @@ -22,7 +22,7 @@ type Props = { branch: Branch, // dispatch functions - fetchBranchByName: (repository: Repository, branchName: string) => void, + fetchBranch: (repository: Repository, branchName: string) => void, // context props t: string => string @@ -30,9 +30,9 @@ type Props = { class BranchView extends React.Component { componentDidMount() { - const { fetchBranchByName, repository, branchName } = this.props; + const { fetchBranch, repository, branchName } = this.props; - fetchBranchByName(repository, branchName); + fetchBranch(repository, branchName); } render() { @@ -71,7 +71,7 @@ class BranchView extends React.Component { const mapStateToProps = (state, ownProps) => { const { repository } = ownProps; const branchName = decodeURIComponent(ownProps.match.params.branch); - const branch = getBranchByName(state, branchName); + const branch = getBranch(state, repository, branchName); const loading = isFetchBranchPending(state, branchName); const error = getFetchBranchFailure(state, branchName); return { @@ -85,8 +85,8 @@ const mapStateToProps = (state, ownProps) => { const mapDispatchToProps = dispatch => { return { - fetchBranchByName: (repository: Repository, branchName: string) => { - dispatch(fetchBranchByName(repository._links.branches.href, branchName)); + fetchBranch: (repository: Repository, branchName: string) => { + dispatch(fetchBranch(repository, branchName)); } }; }; diff --git a/scm-ui/src/repos/branches/modules/branches.js b/scm-ui/src/repos/branches/modules/branches.js index a080a3877f..dd542d0183 100644 --- a/scm-ui/src/repos/branches/modules/branches.js +++ b/scm-ui/src/repos/branches/modules/branches.js @@ -5,11 +5,7 @@ import { SUCCESS_SUFFIX } from "../../../modules/types"; import { apiClient } from "@scm-manager/ui-components"; -import type { - Action, - Branch, - Repository -} from "@scm-manager/ui-types"; +import type { Action, Branch, Repository } from "@scm-manager/ui-types"; import { isPending } from "../../../modules/pending"; import { getFailure } from "../../../modules/failure"; @@ -25,61 +21,69 @@ export const FETCH_BRANCH_FAILURE = `${FETCH_BRANCH}_${FAILURE_SUFFIX}`; // Fetching branches -export function fetchBranchByName(link: string, name: string) { - let endsWith = ""; - if(!link.endsWith("/")) { - endsWith = "/"; - } - return fetchBranch(link + endsWith + encodeURIComponent(name), name); +function createIdentifier(repository: Repository) { + return repository.namespace + "/" + repository.name; } -export function fetchBranchPending(name: string): Action { +export function fetchBranchPending( + repository: Repository, + name: string +): Action { return { type: FETCH_BRANCH_PENDING, - payload: name, - itemId: name + payload: { repository, name }, + itemId: createIdentifier(repository) + "/" + name }; } -export function fetchBranchSuccess(repo: Repository, branch: Branch): Action { +export function fetchBranchSuccess( + repository: Repository, + branch: Branch +): Action { return { type: FETCH_BRANCH_SUCCESS, - payload: branch, - itemId: branch.name + payload: { repository, branch }, + itemId: createIdentifier(repository) + "/" + branch.name }; } -export function fetchBranchFailure(name: string, error: Error): Action { +export function fetchBranchFailure( + repository: Repository, + name: string, + error: Error +): Action { return { type: FETCH_BRANCH_FAILURE, - payload: name, - itemId: name + payload: { error, repository, name }, + itemId: createIdentifier(repository) + "/" + name }; } -export function fetchBranch(link: string, name: string) { +export function fetchBranch( + repository: Repository, + name: string +) { + let link = repository._links.branches.href; + if (!link.endsWith("/")) { + link += "/"; + } + link += encodeURIComponent(name); return function(dispatch: any) { - dispatch(fetchBranchPending(name)); + dispatch(fetchBranchPending(repository, name)); return apiClient .get(link) .then(response => { return response.json(); }) .then(data => { - dispatch(fetchBranchSuccess(data)); + dispatch(fetchBranchSuccess(repository, data)); }) .catch(error => { - dispatch(fetchBranchFailure(name, error)); + dispatch(fetchBranchFailure(repository, name, error)); }); }; } -export function getBranchByName(state: Object, name: string) { - if (state.branches) { - return state.branches[name]; - } -} - export function isFetchBranchPending(state: Object, name: string) { return isPending(state, FETCH_BRANCH, name); } @@ -138,6 +142,24 @@ export function fetchBranchesFailure(repository: Repository, error: Error) { // Reducers +function reduceBranchSuccess(state, repositoryName, newBranch) { + const newBranches = []; + // we do not use filter, because we try to keep the current order + let found = false; + for (const branch of state[repositoryName] || []) { + if (branch.name === newBranch.name) { + newBranches.push(newBranch); + found = true; + } else { + newBranches.push(branch); + } + } + if (!found) { + newBranches.push(newBranch); + } + return newBranches; +} + type State = { [string]: Branch[] }; export default function reducer( @@ -156,11 +178,15 @@ export default function reducer( [key]: extractBranchesFromPayload(payload.data) }; case FETCH_BRANCH_SUCCESS: + if (!action.payload.repository || !action.payload.branch) { + return state; + } + const newBranch = action.payload.branch; + const repositoryName = createIdentifier(action.payload.repository); return { ...state, - [action.payload.name]: action.payload + [repositoryName]: reduceBranchSuccess(state, repositoryName, newBranch) }; - default: return state; } diff --git a/scm-ui/src/repos/branches/modules/branches.test.js b/scm-ui/src/repos/branches/modules/branches.test.js index cc67aaf33a..30b81975d6 100644 --- a/scm-ui/src/repos/branches/modules/branches.test.js +++ b/scm-ui/src/repos/branches/modules/branches.test.js @@ -11,9 +11,8 @@ import reducer, { FETCH_BRANCH_SUCCESS, FETCH_BRANCH_FAILURE, fetchBranches, - fetchBranchByName, - fetchBranchSuccess, fetchBranch, + fetchBranchSuccess, getBranch, getBranches, getFetchBranchesFailure, @@ -100,7 +99,7 @@ describe("branches", () => { fetchMock.getOnce(URL + "/branch1", branch1); const store = mockStore({}); - return store.dispatch(fetchBranchByName(URL, "branch1")).then(() => { + return store.dispatch(fetchBranch(repository, "branch1")).then(() => { const actions = store.getActions(); expect(actions[0].type).toEqual(FETCH_BRANCH_PENDING); expect(actions[1].type).toEqual(FETCH_BRANCH_SUCCESS); @@ -114,7 +113,7 @@ describe("branches", () => { }); const store = mockStore({}); - return store.dispatch(fetchBranchByName(URL, "branch2")).then(() => { + return store.dispatch(fetchBranch(repository, "branch2")).then(() => { const actions = store.getActions(); expect(actions[0].type).toEqual(FETCH_BRANCH_PENDING); expect(actions[1].type).toEqual(FETCH_BRANCH_FAILURE); @@ -149,51 +148,60 @@ describe("branches", () => { const oldState = { "hitchhiker/heartOfGold": [branch3] }; - const newState = reducer(oldState, action); expect(newState[key]).toContain(branch1); expect(newState[key]).toContain(branch2); - expect(newState["hitchhiker/heartOfGold"]).toContain(branch3); }); it("should update state according to FETCH_BRANCH_SUCCESS action", () => { - const newState = reducer({}, fetchBranchSuccess(branch3)); - expect(newState["branch3"]).toBe(branch3); + const newState = reducer({}, fetchBranchSuccess(repository, branch3)); + expect(newState["foo/bar"]).toEqual([branch3]); }); it("should not delete existing branch from state", () => { const oldState = { - branch1 + "foo/bar": [branch1] }; - - const newState = reducer(oldState, fetchBranchSuccess(branch2)); - expect(newState["branch1"]).toBe(branch1); - expect(newState["branch2"]).toBe(branch2); + const newState = reducer(oldState, fetchBranchSuccess(repository, branch2)); + expect(newState["foo/bar"]).toEqual([branch1, branch2]); }); it("should update required branch from state", () => { const oldState = { - branch1 + "foo/bar": [branch1] }; - const newBranch1 = { name: "branch1", revision: "revision2" }; - - const newState = reducer(oldState, fetchBranchSuccess(newBranch1)); - expect(newState["branch1"]).not.toBe(branch1); - expect(newState["branch1"]).toBe(newBranch1); + const newState = reducer(oldState, fetchBranchSuccess(repository, newBranch1)); + expect(newState["foo/bar"]).toEqual([newBranch1]); }); it("should update required branch from state and keeps old repo", () => { const oldState = { - repo1: { - branch1 - } + "ns/one": [branch1] }; - const repo2 = { repo2: { branch3 } }; - const newState = reducer(oldState, fetchBranchSuccess(repo2, branch2)); - expect(newState["repo1"]).toBe({ branch1 }); - expect(newState["repo2"]).toBe({ branch2, branch3 }); + const newState = reducer(oldState, fetchBranchSuccess(repository, branch3)); + expect(newState["ns/one"]).toEqual([branch1]); + expect(newState["foo/bar"]).toEqual([branch3]); + }); + + it("should return the oldState, if action has no payload", () => { + const state = {}; + const newState = reducer(state, {type: FETCH_BRANCH_SUCCESS}); + expect(newState).toBe(state); + }); + + it("should return the oldState, if payload has no branch", () => { + const action = { + type: FETCH_BRANCH_SUCCESS, + payload: { + repository + }, + itemId: "foo/bar/" + }; + const state = {}; + const newState = reducer(state, action); + expect(newState).toBe(state); }); }); diff --git a/scm-ui/yarn.lock b/scm-ui/yarn.lock index 5b6ec89ef3..4440b28f6c 100644 --- a/scm-ui/yarn.lock +++ b/scm-ui/yarn.lock @@ -698,9 +698,10 @@ version "0.0.2" resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85" -"@scm-manager/ui-bundler@^0.0.26": - version "0.0.26" - resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.26.tgz#4676a7079b781b33fa1989c6643205c3559b1f66" +"@scm-manager/ui-bundler@^0.0.27": + version "0.0.27" + resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.27.tgz#3ed2c7826780b9a1a9ea90464332640cfb5d54b5" + integrity sha512-cBU1xq6gDy1Vw9AGOzsR763+JmBeraTaC/KQfxT3I6XyZJ2brIfG1m5QYcAcHWvDxq3mYMogpI5rfShw14L4/w== dependencies: "@babel/core" "^7.0.0" "@babel/plugin-proposal-class-properties" "^7.0.0" From 81d25e74eb4dca5a9c5c89ab5ce19823a9e7cfca Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Tue, 2 Apr 2019 17:45:25 +0200 Subject: [PATCH 26/37] applied simplified brunchdetail design --- scm-ui/public/locales/de/repos.json | 4 +-- scm-ui/public/locales/en/repos.json | 4 +-- .../{BranchDetailTable.js => BranchDetail.js} | 30 +++++-------------- .../repos/branches/containers/BranchView.js | 4 +-- 4 files changed, 12 insertions(+), 30 deletions(-) rename scm-ui/src/repos/branches/components/{BranchDetailTable.js => BranchDetail.js} (59%) diff --git a/scm-ui/public/locales/de/repos.json b/scm-ui/public/locales/de/repos.json index 3a90f9080a..f3fe2d162e 100644 --- a/scm-ui/public/locales/de/repos.json +++ b/scm-ui/public/locales/de/repos.json @@ -61,9 +61,7 @@ } }, "branch": { - "name": "Name", - "repository": "Repository", - "actions": "Aktionen", + "name": "Name:", "commits": "Commits", "sources": "Sources" }, diff --git a/scm-ui/public/locales/en/repos.json b/scm-ui/public/locales/en/repos.json index 6adede7b82..ac5cbfe6e1 100644 --- a/scm-ui/public/locales/en/repos.json +++ b/scm-ui/public/locales/en/repos.json @@ -61,9 +61,7 @@ } }, "branch": { - "name": "Name", - "repository": "Repository", - "actions": "Actions", + "name": "Name:", "commits": "Commits", "sources": "Sources" }, diff --git a/scm-ui/src/repos/branches/components/BranchDetailTable.js b/scm-ui/src/repos/branches/components/BranchDetail.js similarity index 59% rename from scm-ui/src/repos/branches/components/BranchDetailTable.js rename to scm-ui/src/repos/branches/components/BranchDetail.js index 27c4907a53..8941e0abef 100644 --- a/scm-ui/src/repos/branches/components/BranchDetailTable.js +++ b/scm-ui/src/repos/branches/components/BranchDetail.js @@ -21,31 +21,17 @@ const styles = { } }; -class BranchDetailTable extends React.Component { +class BranchDetail extends React.Component { render() { const { repository, branch, t } = this.props; return ( -
{t("branch.name")}{t("branch.name")} {branch.name} {this.renderDefaultBranch()}
+ {t("branch.repository")} - + {repository.name}
{t("branch.actions")}{t("branch.actions")}
- {t("branch.repository")} - {t("branch.repository")} {repository.name}
{this.renderLink(to, branch.name, branch.defaultBranch)}
{this.renderLink(to, branch.name, branch.defaultBranch)}
- - - - - - - - - - - - - - -
{t("branch.name")} - {branch.name} {this.renderDefaultBranch()} -
{t("branch.repository")}{repository.name}
{t("branch.actions")} - -
+
+
{t("branch.name")} {branch.name} {this.renderDefaultBranch()}
+
+ +
+
); } @@ -62,4 +48,4 @@ class BranchDetailTable extends React.Component { } } -export default injectSheet(styles)(translate("repos")(BranchDetailTable)); +export default injectSheet(styles)(translate("repos")(BranchDetail)); diff --git a/scm-ui/src/repos/branches/containers/BranchView.js b/scm-ui/src/repos/branches/containers/BranchView.js index 959c4519d0..542cbd67d2 100644 --- a/scm-ui/src/repos/branches/containers/BranchView.js +++ b/scm-ui/src/repos/branches/containers/BranchView.js @@ -1,6 +1,6 @@ // @flow import React from "react"; -import BranchDetailTable from "../components/BranchDetailTable"; +import BranchDetail from "../components/BranchDetail"; import { ExtensionPoint } from "@scm-manager/ui-extensions"; import type { Repository, Branch } from "@scm-manager/ui-types"; import { connect } from "react-redux"; @@ -54,7 +54,7 @@ class BranchView extends React.Component { return (
- +
Date: Wed, 3 Apr 2019 08:52:29 +0200 Subject: [PATCH 27/37] added defaultbranchtag component --- scm-ui/public/locales/de/repos.json | 3 +- scm-ui/public/locales/en/repos.json | 3 +- .../repos/branches/components/BranchDetail.js | 32 ++++------------- .../repos/branches/components/BranchRow.js | 33 +++++------------ .../branches/components/DefaultBranchTag.js | 35 +++++++++++++++++++ 5 files changed, 55 insertions(+), 51 deletions(-) create mode 100644 scm-ui/src/repos/branches/components/DefaultBranchTag.js diff --git a/scm-ui/public/locales/de/repos.json b/scm-ui/public/locales/de/repos.json index f3fe2d162e..6170c9021f 100644 --- a/scm-ui/public/locales/de/repos.json +++ b/scm-ui/public/locales/de/repos.json @@ -63,7 +63,8 @@ "branch": { "name": "Name:", "commits": "Commits", - "sources": "Sources" + "sources": "Sources", + "defaultTag": "Default" }, "changesets": { "errorTitle": "Fehler", diff --git a/scm-ui/public/locales/en/repos.json b/scm-ui/public/locales/en/repos.json index ac5cbfe6e1..4eeddea8b2 100644 --- a/scm-ui/public/locales/en/repos.json +++ b/scm-ui/public/locales/en/repos.json @@ -63,7 +63,8 @@ "branch": { "name": "Name:", "commits": "Commits", - "sources": "Sources" + "sources": "Sources", + "defaultTag": "Default" }, "changesets": { "errorTitle": "Error", diff --git a/scm-ui/src/repos/branches/components/BranchDetail.js b/scm-ui/src/repos/branches/components/BranchDetail.js index 8941e0abef..86b142d9da 100644 --- a/scm-ui/src/repos/branches/components/BranchDetail.js +++ b/scm-ui/src/repos/branches/components/BranchDetail.js @@ -2,23 +2,14 @@ import React from "react"; import type { Repository, Branch } from "@scm-manager/ui-types"; import { translate } from "react-i18next"; -import injectSheet from "react-jss"; -import classNames from "classnames"; import BranchButtonGroup from "./BranchButtonGroup"; +import DefaultBranchTag from "./DefaultBranchTag"; type Props = { repository: Repository, branch: Branch, // context props - t: string => string, - classes: any -}; - -const styles = { - tag: { - marginLeft: "0.75rem", - verticalAlign: "inherit" - } + t: string => string }; class BranchDetail extends React.Component { @@ -27,25 +18,16 @@ class BranchDetail extends React.Component { return (
-
{t("branch.name")} {branch.name} {this.renderDefaultBranch()}
+
+ {t("branch.name")} {branch.name}{" "} + +
); } - - renderDefaultBranch() { - const { branch, classes } = this.props; - - let defaultLabel = null; - if (branch.defaultBranch) { - defaultLabel = ( - Default - ); - } - return defaultLabel; - } } -export default injectSheet(styles)(translate("repos")(BranchDetail)); +export default translate("repos")(BranchDetail); diff --git a/scm-ui/src/repos/branches/components/BranchRow.js b/scm-ui/src/repos/branches/components/BranchRow.js index d8f70575b3..025e8f2742 100644 --- a/scm-ui/src/repos/branches/components/BranchRow.js +++ b/scm-ui/src/repos/branches/components/BranchRow.js @@ -2,33 +2,18 @@ import React from "react"; import { Link } from "react-router-dom"; import type { Branch } from "@scm-manager/ui-types"; -import injectSheet from "react-jss"; -import classNames from "classnames"; +import DefaultBranchTag from "./DefaultBranchTag"; type Props = { baseUrl: string, - branch: Branch, - classes: any -}; - -const styles = { - tag: { - marginLeft: "0.75rem", - verticalAlign: "inherit" - } + branch: Branch }; class BranchRow extends React.Component { renderLink(to: string, label: string, defaultBranch?: boolean) { - const { classes } = this.props; - - let showLabel = null; - if (defaultBranch) { - showLabel = Default; - } return ( - {label} {showLabel} + {label} ); } @@ -36,12 +21,12 @@ class BranchRow extends React.Component { render() { const { baseUrl, branch } = this.props; const to = `${baseUrl}/${encodeURIComponent(branch.name)}/info`; - return ( - - {this.renderLink(to, branch.name, branch.defaultBranch)} - - ); + return ( + + {this.renderLink(to, branch.name, branch.defaultBranch)} + + ); } } -export default injectSheet(styles)(BranchRow); +export default BranchRow; diff --git a/scm-ui/src/repos/branches/components/DefaultBranchTag.js b/scm-ui/src/repos/branches/components/DefaultBranchTag.js new file mode 100644 index 0000000000..18be6d21f8 --- /dev/null +++ b/scm-ui/src/repos/branches/components/DefaultBranchTag.js @@ -0,0 +1,35 @@ +//@flow +import React from "react"; +import injectSheet from "react-jss"; +import classNames from "classnames"; +import { translate } from "react-i18next"; + +type Props = { + defaultBranch?: boolean, + classes: any, + t: string => string +}; + +const styles = { + tag: { + marginLeft: "0.75rem", + verticalAlign: "inherit" + } +}; + +class DefaultBranchTag extends React.Component { + render() { + const { defaultBranch, classes, t } = this.props; + + if (defaultBranch) { + return ( + + {t("branch.defaultTag")} + + ); + } + return null; + } +} + +export default injectSheet(styles)(translate("repos")(DefaultBranchTag)); From 148f05daeeb3eeb5087923c70af90f515bb6922e Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Wed, 3 Apr 2019 10:11:43 +0200 Subject: [PATCH 28/37] review changes have been implemented: integrated createLink functionalities in BranchButtonGroup, outsourced orderBraches and wrote unit tests --- .../branches/components/BranchButtonGroup.js | 9 +- .../repos/branches/containers/BranchView.js | 8 +- .../branches/containers/BranchesOverview.js | 32 +-- scm-ui/src/repos/branches/modules/branches.js | 235 +++++++++--------- .../repos/branches/modules/branches.test.js | 59 ++++- 5 files changed, 189 insertions(+), 154 deletions(-) diff --git a/scm-ui/src/repos/branches/components/BranchButtonGroup.js b/scm-ui/src/repos/branches/components/BranchButtonGroup.js index dc170963e9..424d4fd156 100644 --- a/scm-ui/src/repos/branches/components/BranchButtonGroup.js +++ b/scm-ui/src/repos/branches/components/BranchButtonGroup.js @@ -3,7 +3,6 @@ import React from "react"; import type { Repository, Branch } from "@scm-manager/ui-types"; import { ButtonGroup, Button } from "@scm-manager/ui-components"; import { translate } from "react-i18next"; -import { createChangesetLink, createSourcesLink } from "../modules/branches"; type Props = { repository: Repository, @@ -17,8 +16,12 @@ class BranchButtonGroup extends React.Component { render() { const { repository, branch, t } = this.props; - const changesetLink = createChangesetLink(repository, branch); - const sourcesLink = createSourcesLink(repository, branch); + const changesetLink = `/repo/${repository.namespace}/${ + repository.name + }/branch/${encodeURIComponent(branch.name)}/changesets/`; + const sourcesLink = `/repo/${repository.namespace}/${ + repository.name + }/sources/${encodeURIComponent(branch.name)}/`; return ( diff --git a/scm-ui/src/repos/branches/containers/BranchView.js b/scm-ui/src/repos/branches/containers/BranchView.js index 542cbd67d2..5e7fa9610a 100644 --- a/scm-ui/src/repos/branches/containers/BranchView.js +++ b/scm-ui/src/repos/branches/containers/BranchView.js @@ -18,8 +18,8 @@ type Props = { repository: Repository, branchName: string, loading: boolean, - error: Error, - branch: Branch, + error?: Error, + branch?: Branch, // dispatch functions fetchBranch: (repository: Repository, branchName: string) => void, @@ -72,8 +72,8 @@ const mapStateToProps = (state, ownProps) => { const { repository } = ownProps; const branchName = decodeURIComponent(ownProps.match.params.branch); const branch = getBranch(state, repository, branchName); - const loading = isFetchBranchPending(state, branchName); - const error = getFetchBranchFailure(state, branchName); + const loading = isFetchBranchPending(state, repository, branchName); + const error = getFetchBranchFailure(state, repository, branchName); return { repository, branchName, diff --git a/scm-ui/src/repos/branches/containers/BranchesOverview.js b/scm-ui/src/repos/branches/containers/BranchesOverview.js index 4f4ca4a75d..3bc92deab4 100644 --- a/scm-ui/src/repos/branches/containers/BranchesOverview.js +++ b/scm-ui/src/repos/branches/containers/BranchesOverview.js @@ -4,7 +4,8 @@ import { fetchBranches, getBranches, getFetchBranchesFailure, - isFetchBranchesPending + isFetchBranchesPending, + orderBranches } from "../modules/branches"; import { connect } from "react-redux"; import type { Branch, Repository } from "@scm-manager/ui-types"; @@ -36,35 +37,6 @@ type Props = { t: string => string }; -// master, default should always be the first one, -// followed by develop the rest should be ordered by its name -export function orderBranches(branches: Branch[]) { - branches.sort((a, b) => { - if (a.defaultBranch && !b.defaultBranch) { - return -20; - } else if (!a.defaultBranch && b.defaultBranch) { - return 20; - } else if (a.name === "master" && b.name !== "master") { - return -10; - } else if (a.name !== "master" && b.name === "master") { - return 10; - } else if (a.name === "default" && b.name !== "default") { - return -10; - } else if (a.name !== "default" && b.name === "default") { - return 10; - } else if (a.name === "develop" && b.name !== "develop") { - return -5; - } else if (a.name !== "develop" && b.name === "develop") { - return 5; - } else if (a.name < b.name) { - return -1; - } else if (a.name > b.name) { - return 1; - } - return 0; - }); -} - class BranchesOverview extends React.Component { componentDidMount() { const { fetchBranches, repository } = this.props; diff --git a/scm-ui/src/repos/branches/modules/branches.js b/scm-ui/src/repos/branches/modules/branches.js index dd542d0183..a5f676eced 100644 --- a/scm-ui/src/repos/branches/modules/branches.js +++ b/scm-ui/src/repos/branches/modules/branches.js @@ -21,41 +21,26 @@ export const FETCH_BRANCH_FAILURE = `${FETCH_BRANCH}_${FAILURE_SUFFIX}`; // Fetching branches -function createIdentifier(repository: Repository) { - return repository.namespace + "/" + repository.name; -} +export function fetchBranches(repository: Repository) { + if (!repository._links.branches) { + return { + type: FETCH_BRANCHES_SUCCESS, + payload: { repository, data: {} }, + itemId: createKey(repository) + }; + } -export function fetchBranchPending( - repository: Repository, - name: string -): Action { - return { - type: FETCH_BRANCH_PENDING, - payload: { repository, name }, - itemId: createIdentifier(repository) + "/" + name - }; -} - -export function fetchBranchSuccess( - repository: Repository, - branch: Branch -): Action { - return { - type: FETCH_BRANCH_SUCCESS, - payload: { repository, branch }, - itemId: createIdentifier(repository) + "/" + branch.name - }; -} - -export function fetchBranchFailure( - repository: Repository, - name: string, - error: Error -): Action { - return { - type: FETCH_BRANCH_FAILURE, - payload: { error, repository, name }, - itemId: createIdentifier(repository) + "/" + name + return function(dispatch: any) { + dispatch(fetchBranchesPending(repository)); + return apiClient + .get(repository._links.branches.href) + .then(response => response.json()) + .then(data => { + dispatch(fetchBranchesSuccess(data, repository)); + }) + .catch(error => { + dispatch(fetchBranchesFailure(repository, error)); + }); }; } @@ -84,38 +69,48 @@ export function fetchBranch( }; } -export function isFetchBranchPending(state: Object, name: string) { - return isPending(state, FETCH_BRANCH, name); -} +// Selectors -export function getFetchBranchFailure(state: Object, name: string) { - return getFailure(state, FETCH_BRANCH, name); -} - -export function fetchBranches(repository: Repository) { - if (!repository._links.branches) { - return { - type: FETCH_BRANCHES_SUCCESS, - payload: { repository, data: {} }, - itemId: createKey(repository) - }; +export function getBranches(state: Object, repository: Repository) { + const key = createKey(repository); + if (state.branches[key]) { + return state.branches[key]; } + return null; +} - return function(dispatch: any) { - dispatch(fetchBranchesPending(repository)); - return apiClient - .get(repository._links.branches.href) - .then(response => response.json()) - .then(data => { - dispatch(fetchBranchesSuccess(data, repository)); - }) - .catch(error => { - dispatch(fetchBranchesFailure(repository, error)); - }); - }; +export function getBranch( + state: Object, + repository: Repository, + name: string +): ?Branch { + const key = createKey(repository); + if (state.branches[key]) { + return state.branches[key].find((b: Branch) => b.name === name); + } + return null; } // Action creators +export function isFetchBranchesPending( + state: Object, + repository: Repository +): boolean { + return isPending(state, FETCH_BRANCHES, createKey(repository)); +} + +export function getFetchBranchesFailure(state: Object, repository: Repository) { + return getFailure(state, FETCH_BRANCHES, createKey(repository)); +} + +export function isFetchBranchPending(state: Object, repository: Repository, name: string) { + return isPending(state, FETCH_BRANCH, createKey(repository) + "/" + name); +} + +export function getFetchBranchFailure(state: Object, repository: Repository, name: string) { + return getFailure(state, FETCH_BRANCH, createKey(repository) + "/" + name); +} + export function fetchBranchesPending(repository: Repository) { return { type: FETCH_BRANCHES_PENDING, @@ -140,8 +135,49 @@ export function fetchBranchesFailure(repository: Repository, error: Error) { }; } +export function fetchBranchPending( + repository: Repository, + name: string +): Action { + return { + type: FETCH_BRANCH_PENDING, + payload: { repository, name }, + itemId: createKey(repository) + "/" + name + }; +} + +export function fetchBranchSuccess( + repository: Repository, + branch: Branch +): Action { + return { + type: FETCH_BRANCH_SUCCESS, + payload: { repository, branch }, + itemId: createKey(repository) + "/" + branch.name + }; +} + +export function fetchBranchFailure( + repository: Repository, + name: string, + error: Error +): Action { + return { + type: FETCH_BRANCH_FAILURE, + payload: { error, repository, name }, + itemId: createKey(repository) + "/" + name + }; +} + // Reducers +function extractBranchesFromPayload(payload: any) { + if (payload._embedded && payload._embedded.branches) { + return payload._embedded.branches; + } + return []; +} + function reduceBranchSuccess(state, repositoryName, newBranch) { const newBranches = []; // we do not use filter, because we try to keep the current order @@ -182,7 +218,7 @@ export default function reducer( return state; } const newBranch = action.payload.branch; - const repositoryName = createIdentifier(action.payload.repository); + const repositoryName = createKey(action.payload.repository); return { ...state, [repositoryName]: reduceBranchSuccess(state, repositoryName, newBranch) @@ -192,59 +228,36 @@ export default function reducer( } } -function extractBranchesFromPayload(payload: any) { - if (payload._embedded && payload._embedded.branches) { - return payload._embedded.branches; - } - return []; -} - -// Selectors - -export function getBranches(state: Object, repository: Repository) { - const key = createKey(repository); - if (state.branches[key]) { - return state.branches[key]; - } - return null; -} - -export function getBranch( - state: Object, - repository: Repository, - name: string -): ?Branch { - const key = createKey(repository); - if (state.branches[key]) { - return state.branches[key].find((b: Branch) => b.name === name); - } - return null; -} - -export function isFetchBranchesPending( - state: Object, - repository: Repository -): boolean { - return isPending(state, FETCH_BRANCHES, createKey(repository)); -} - -export function getFetchBranchesFailure(state: Object, repository: Repository) { - return getFailure(state, FETCH_BRANCHES, createKey(repository)); -} - function createKey(repository: Repository): string { const { namespace, name } = repository; return `${namespace}/${name}`; } -export function createChangesetLink(repository: Repository, branch: Branch) { - return `/repo/${repository.namespace}/${ - repository.name - }/branch/${encodeURIComponent(branch.name)}/changesets/`; -} - -export function createSourcesLink(repository: Repository, branch: Branch) { - return `/repo/${repository.namespace}/${ - repository.name - }/sources/${encodeURIComponent(branch.name)}/`; +// master, default should always be the first one, +// followed by develop the rest should be ordered by its name +export function orderBranches(branches: Branch[]) { + branches.sort((a, b) => { + if (a.defaultBranch && !b.defaultBranch) { + return -20; + } else if (!a.defaultBranch && b.defaultBranch) { + return 20; + } else if (a.name === "master" && b.name !== "master") { + return -10; + } else if (a.name !== "master" && b.name === "master") { + return 10; + } else if (a.name === "default" && b.name !== "default") { + return -10; + } else if (a.name !== "default" && b.name === "default") { + return 10; + } else if (a.name === "develop" && b.name !== "develop") { + return -5; + } else if (a.name !== "develop" && b.name === "develop") { + return 5; + } else if (a.name < b.name) { + return -1; + } else if (a.name > b.name) { + return 1; + } + return 0; + }); } diff --git a/scm-ui/src/repos/branches/modules/branches.test.js b/scm-ui/src/repos/branches/modules/branches.test.js index 30b81975d6..8db4f6f83a 100644 --- a/scm-ui/src/repos/branches/modules/branches.test.js +++ b/scm-ui/src/repos/branches/modules/branches.test.js @@ -16,7 +16,8 @@ import reducer, { getBranch, getBranches, getFetchBranchesFailure, - isFetchBranchesPending + isFetchBranchesPending, + orderBranches } from "./branches"; const namespace = "foo"; @@ -34,7 +35,18 @@ const repository = { const branch1 = { name: "branch1", revision: "revision1" }; const branch2 = { name: "branch2", revision: "revision2" }; -const branch3 = { name: "branch3", revision: "revision3" }; +const branch3 = { name: "branch3", revision: "revision3", defaultBranch: true }; +const defaultBranch = { + name: "default", + revision: "revision4", + defaultBranch: false +}; +const developBranch = { + name: "develop", + revision: "revision5", + defaultBranch: false +}; +const masterBranch = { name: "master", revision: "revision6", defaultBranch: false }; describe("branches", () => { describe("fetch branches", () => { @@ -163,7 +175,10 @@ describe("branches", () => { const oldState = { "foo/bar": [branch1] }; - const newState = reducer(oldState, fetchBranchSuccess(repository, branch2)); + const newState = reducer( + oldState, + fetchBranchSuccess(repository, branch2) + ); expect(newState["foo/bar"]).toEqual([branch1, branch2]); }); @@ -172,7 +187,10 @@ describe("branches", () => { "foo/bar": [branch1] }; const newBranch1 = { name: "branch1", revision: "revision2" }; - const newState = reducer(oldState, fetchBranchSuccess(repository, newBranch1)); + const newState = reducer( + oldState, + fetchBranchSuccess(repository, newBranch1) + ); expect(newState["foo/bar"]).toEqual([newBranch1]); }); @@ -180,14 +198,17 @@ describe("branches", () => { const oldState = { "ns/one": [branch1] }; - const newState = reducer(oldState, fetchBranchSuccess(repository, branch3)); + const newState = reducer( + oldState, + fetchBranchSuccess(repository, branch3) + ); expect(newState["ns/one"]).toEqual([branch1]); expect(newState["foo/bar"]).toEqual([branch3]); }); it("should return the oldState, if action has no payload", () => { const state = {}; - const newState = reducer(state, {type: FETCH_BRANCH_SUCCESS}); + const newState = reducer(state, { type: FETCH_BRANCH_SUCCESS }); expect(newState).toBe(state); }); @@ -272,4 +293,30 @@ describe("branches", () => { expect(getFetchBranchesFailure({}, repository)).toBeUndefined(); }); }); + + describe("sort branches", () => { + it("should return branches", () => { + let branches = [branch1, branch2]; + orderBranches(branches); + expect(branches).toEqual([branch1, branch2]); + }); + + it("should return defaultBranch first", () => { + let branches = [branch1, branch2, branch3]; + orderBranches(branches); + expect(branches).toEqual([branch3, branch1, branch2]); + }); + + it("should order special branches as follows: master > default > develop", () => { + let branches = [defaultBranch, developBranch, masterBranch]; + orderBranches(branches); + expect(branches).toEqual([masterBranch, defaultBranch, developBranch]); + }); + + it("should order special branches but starting with defaultBranch", () => { + let branches = [masterBranch, developBranch, defaultBranch, branch3]; + orderBranches(branches); + expect(branches).toEqual([branch3, masterBranch, defaultBranch, developBranch]); + }); + }); }); From 3e2cb0b2125191c093f6d42909d4169059a29a55 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Wed, 3 Apr 2019 13:24:41 +0200 Subject: [PATCH 29/37] moved orderbranches function and tests in seperate file --- .../branches/containers/BranchesOverview.js | 4 +- .../branches/containers/OrderBranches.js | 32 ++++++++++++ .../branches/containers/OrderBranches.test.js | 51 +++++++++++++++++++ scm-ui/src/repos/branches/modules/branches.js | 29 ----------- .../repos/branches/modules/branches.test.js | 43 +--------------- 5 files changed, 87 insertions(+), 72 deletions(-) create mode 100644 scm-ui/src/repos/branches/containers/OrderBranches.js create mode 100644 scm-ui/src/repos/branches/containers/OrderBranches.test.js diff --git a/scm-ui/src/repos/branches/containers/BranchesOverview.js b/scm-ui/src/repos/branches/containers/BranchesOverview.js index 3bc92deab4..bc7405f416 100644 --- a/scm-ui/src/repos/branches/containers/BranchesOverview.js +++ b/scm-ui/src/repos/branches/containers/BranchesOverview.js @@ -4,9 +4,9 @@ import { fetchBranches, getBranches, getFetchBranchesFailure, - isFetchBranchesPending, - orderBranches + isFetchBranchesPending } from "../modules/branches"; +import { orderBranches } from "./OrderBranches"; import { connect } from "react-redux"; import type { Branch, Repository } from "@scm-manager/ui-types"; import { compose } from "redux"; diff --git a/scm-ui/src/repos/branches/containers/OrderBranches.js b/scm-ui/src/repos/branches/containers/OrderBranches.js new file mode 100644 index 0000000000..a1c2f5e460 --- /dev/null +++ b/scm-ui/src/repos/branches/containers/OrderBranches.js @@ -0,0 +1,32 @@ +// @flow + +// master, default should always be the first one, +// followed by develop the rest should be ordered by its name +import type {Branch} from "@scm-manager/ui-types"; + +export function orderBranches(branches: Branch[]) { + branches.sort((a, b) => { + if (a.defaultBranch && !b.defaultBranch) { + return -20; + } else if (!a.defaultBranch && b.defaultBranch) { + return 20; + } else if (a.name === "master" && b.name !== "master") { + return -10; + } else if (a.name !== "master" && b.name === "master") { + return 10; + } else if (a.name === "default" && b.name !== "default") { + return -10; + } else if (a.name !== "default" && b.name === "default") { + return 10; + } else if (a.name === "develop" && b.name !== "develop") { + return -5; + } else if (a.name !== "develop" && b.name === "develop") { + return 5; + } else if (a.name < b.name) { + return -1; + } else if (a.name > b.name) { + return 1; + } + return 0; + }); +} diff --git a/scm-ui/src/repos/branches/containers/OrderBranches.test.js b/scm-ui/src/repos/branches/containers/OrderBranches.test.js new file mode 100644 index 0000000000..76c4de0c4a --- /dev/null +++ b/scm-ui/src/repos/branches/containers/OrderBranches.test.js @@ -0,0 +1,51 @@ +import { orderBranches } from "./OrderBranches"; + +const branch1 = { name: "branch1", revision: "revision1" }; +const branch2 = { name: "branch2", revision: "revision2" }; +const branch3 = { name: "branch3", revision: "revision3", defaultBranch: true }; +const defaultBranch = { + name: "default", + revision: "revision4", + defaultBranch: false +}; +const developBranch = { + name: "develop", + revision: "revision5", + defaultBranch: false +}; +const masterBranch = { + name: "master", + revision: "revision6", + defaultBranch: false +}; + +describe("order branches", () => { + it("should return branches", () => { + let branches = [branch1, branch2]; + orderBranches(branches); + expect(branches).toEqual([branch1, branch2]); + }); + + it("should return defaultBranch first", () => { + let branches = [branch1, branch2, branch3]; + orderBranches(branches); + expect(branches).toEqual([branch3, branch1, branch2]); + }); + + it("should order special branches as follows: master > default > develop", () => { + let branches = [defaultBranch, developBranch, masterBranch]; + orderBranches(branches); + expect(branches).toEqual([masterBranch, defaultBranch, developBranch]); + }); + + it("should order special branches but starting with defaultBranch", () => { + let branches = [masterBranch, developBranch, defaultBranch, branch3]; + orderBranches(branches); + expect(branches).toEqual([ + branch3, + masterBranch, + defaultBranch, + developBranch + ]); + }); +}); diff --git a/scm-ui/src/repos/branches/modules/branches.js b/scm-ui/src/repos/branches/modules/branches.js index a5f676eced..44543106ca 100644 --- a/scm-ui/src/repos/branches/modules/branches.js +++ b/scm-ui/src/repos/branches/modules/branches.js @@ -232,32 +232,3 @@ function createKey(repository: Repository): string { const { namespace, name } = repository; return `${namespace}/${name}`; } - -// master, default should always be the first one, -// followed by develop the rest should be ordered by its name -export function orderBranches(branches: Branch[]) { - branches.sort((a, b) => { - if (a.defaultBranch && !b.defaultBranch) { - return -20; - } else if (!a.defaultBranch && b.defaultBranch) { - return 20; - } else if (a.name === "master" && b.name !== "master") { - return -10; - } else if (a.name !== "master" && b.name === "master") { - return 10; - } else if (a.name === "default" && b.name !== "default") { - return -10; - } else if (a.name !== "default" && b.name === "default") { - return 10; - } else if (a.name === "develop" && b.name !== "develop") { - return -5; - } else if (a.name !== "develop" && b.name === "develop") { - return 5; - } else if (a.name < b.name) { - return -1; - } else if (a.name > b.name) { - return 1; - } - return 0; - }); -} diff --git a/scm-ui/src/repos/branches/modules/branches.test.js b/scm-ui/src/repos/branches/modules/branches.test.js index 8db4f6f83a..99c9bba60a 100644 --- a/scm-ui/src/repos/branches/modules/branches.test.js +++ b/scm-ui/src/repos/branches/modules/branches.test.js @@ -6,7 +6,6 @@ import reducer, { FETCH_BRANCHES_FAILURE, FETCH_BRANCHES_PENDING, FETCH_BRANCHES_SUCCESS, - FETCH_BRANCH, FETCH_BRANCH_PENDING, FETCH_BRANCH_SUCCESS, FETCH_BRANCH_FAILURE, @@ -16,8 +15,7 @@ import reducer, { getBranch, getBranches, getFetchBranchesFailure, - isFetchBranchesPending, - orderBranches + isFetchBranchesPending } from "./branches"; const namespace = "foo"; @@ -35,18 +33,7 @@ const repository = { const branch1 = { name: "branch1", revision: "revision1" }; const branch2 = { name: "branch2", revision: "revision2" }; -const branch3 = { name: "branch3", revision: "revision3", defaultBranch: true }; -const defaultBranch = { - name: "default", - revision: "revision4", - defaultBranch: false -}; -const developBranch = { - name: "develop", - revision: "revision5", - defaultBranch: false -}; -const masterBranch = { name: "master", revision: "revision6", defaultBranch: false }; +const branch3 = { name: "branch3", revision: "revision3" }; describe("branches", () => { describe("fetch branches", () => { @@ -293,30 +280,4 @@ describe("branches", () => { expect(getFetchBranchesFailure({}, repository)).toBeUndefined(); }); }); - - describe("sort branches", () => { - it("should return branches", () => { - let branches = [branch1, branch2]; - orderBranches(branches); - expect(branches).toEqual([branch1, branch2]); - }); - - it("should return defaultBranch first", () => { - let branches = [branch1, branch2, branch3]; - orderBranches(branches); - expect(branches).toEqual([branch3, branch1, branch2]); - }); - - it("should order special branches as follows: master > default > develop", () => { - let branches = [defaultBranch, developBranch, masterBranch]; - orderBranches(branches); - expect(branches).toEqual([masterBranch, defaultBranch, developBranch]); - }); - - it("should order special branches but starting with defaultBranch", () => { - let branches = [masterBranch, developBranch, defaultBranch, branch3]; - orderBranches(branches); - expect(branches).toEqual([branch3, masterBranch, defaultBranch, developBranch]); - }); - }); }); From 9a8fd459f875c5a582b8e8b4a755914744c140cd Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Wed, 3 Apr 2019 13:39:16 +0200 Subject: [PATCH 30/37] renamed orderBranches path --- scm-ui/src/repos/branches/containers/BranchRoot.js | 0 scm-ui/src/repos/branches/containers/BranchesOverview.js | 2 +- .../{containers/OrderBranches.js => util/orderBranches.js} | 0 .../OrderBranches.test.js => util/orderBranches.test.js} | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 scm-ui/src/repos/branches/containers/BranchRoot.js rename scm-ui/src/repos/branches/{containers/OrderBranches.js => util/orderBranches.js} (100%) rename scm-ui/src/repos/branches/{containers/OrderBranches.test.js => util/orderBranches.test.js} (96%) diff --git a/scm-ui/src/repos/branches/containers/BranchRoot.js b/scm-ui/src/repos/branches/containers/BranchRoot.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/scm-ui/src/repos/branches/containers/BranchesOverview.js b/scm-ui/src/repos/branches/containers/BranchesOverview.js index bc7405f416..f8c8be7529 100644 --- a/scm-ui/src/repos/branches/containers/BranchesOverview.js +++ b/scm-ui/src/repos/branches/containers/BranchesOverview.js @@ -6,7 +6,7 @@ import { getFetchBranchesFailure, isFetchBranchesPending } from "../modules/branches"; -import { orderBranches } from "./OrderBranches"; +import { orderBranches } from "../util/orderBranches"; import { connect } from "react-redux"; import type { Branch, Repository } from "@scm-manager/ui-types"; import { compose } from "redux"; diff --git a/scm-ui/src/repos/branches/containers/OrderBranches.js b/scm-ui/src/repos/branches/util/orderBranches.js similarity index 100% rename from scm-ui/src/repos/branches/containers/OrderBranches.js rename to scm-ui/src/repos/branches/util/orderBranches.js diff --git a/scm-ui/src/repos/branches/containers/OrderBranches.test.js b/scm-ui/src/repos/branches/util/orderBranches.test.js similarity index 96% rename from scm-ui/src/repos/branches/containers/OrderBranches.test.js rename to scm-ui/src/repos/branches/util/orderBranches.test.js index 76c4de0c4a..557cc8a4c5 100644 --- a/scm-ui/src/repos/branches/containers/OrderBranches.test.js +++ b/scm-ui/src/repos/branches/util/orderBranches.test.js @@ -1,4 +1,4 @@ -import { orderBranches } from "./OrderBranches"; +import { orderBranches } from "./orderBranches"; const branch1 = { name: "branch1", revision: "revision1" }; const branch2 = { name: "branch2", revision: "revision2" }; From f940af3369d7907c81c6427a83ef519c3bac7e71 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Wed, 3 Apr 2019 15:19:54 +0200 Subject: [PATCH 31/37] outsourced single branch routing to branchroot --- .../repos/branches/components/BranchView.js | 32 +++++ .../repos/branches/containers/BranchRoot.js | 117 ++++++++++++++++++ .../repos/branches/containers/BranchView.js | 99 --------------- scm-ui/src/repos/containers/ChangesetsRoot.js | 4 +- scm-ui/src/repos/containers/RepositoryRoot.js | 13 +- 5 files changed, 157 insertions(+), 108 deletions(-) create mode 100644 scm-ui/src/repos/branches/components/BranchView.js delete mode 100644 scm-ui/src/repos/branches/containers/BranchView.js diff --git a/scm-ui/src/repos/branches/components/BranchView.js b/scm-ui/src/repos/branches/components/BranchView.js new file mode 100644 index 0000000000..a7dd7dbd4b --- /dev/null +++ b/scm-ui/src/repos/branches/components/BranchView.js @@ -0,0 +1,32 @@ +// @flow +import React from "react"; +import BranchDetail from "./BranchDetail"; +import { ExtensionPoint } from "@scm-manager/ui-extensions"; +import type { Repository, Branch } from "@scm-manager/ui-types"; + +type Props = { + repository: Repository, + branch: Branch +}; + +class BranchView extends React.Component { + render() { + const { repository, branch } = this.props; + + return ( +
+ +
+
+ +
+
+ ); + } +} + +export default BranchView; diff --git a/scm-ui/src/repos/branches/containers/BranchRoot.js b/scm-ui/src/repos/branches/containers/BranchRoot.js index e69de29bb2..22b7011968 100644 --- a/scm-ui/src/repos/branches/containers/BranchRoot.js +++ b/scm-ui/src/repos/branches/containers/BranchRoot.js @@ -0,0 +1,117 @@ +//@flow +import React from "react"; +import BranchView from "../components/BranchView"; +import { connect } from "react-redux"; +import { Redirect, Route, Switch, withRouter } from "react-router-dom"; +import { translate } from "react-i18next"; +import type { Repository, Branch } from "@scm-manager/ui-types"; +import { + fetchBranch, + getBranch, + getFetchBranchFailure, + isFetchBranchPending +} from "../modules/branches"; +import { ErrorPage, Loading } from "@scm-manager/ui-components"; +import CreateBranch from "./CreateBranch"; +import type { History } from "history"; + +type Props = { + repository: Repository, + branchName: string, + branch: Branch, + loading: boolean, + error?: Error, + + // context props + t: string => string, + history: History, + match: any, + + // dispatch functions + fetchBranch: (repository: Repository, branchName: string) => void +}; + +class BranchRoot extends React.Component { + componentDidMount() { + const { fetchBranch, repository, branchName } = this.props; + + fetchBranch(repository, branchName); + } + + stripEndingSlash = (url: string) => { + if (url.endsWith("/")) { + return url.substring(0, url.length - 1); + } + return url; + }; + + matchedUrl = () => { + return this.stripEndingSlash(this.props.match.url); + }; + + render() { + const { repository, branch, loading, error, t } = this.props; + + if (error) { + return ( + + ); + } + + if (loading || !branch) { + return ; + } + + const url = this.matchedUrl(); + + return ( + + + ( + + )} + /> + } + /> + + ); + } +} + +const mapStateToProps = (state, ownProps) => { + const { repository } = ownProps; + const branchName = decodeURIComponent(ownProps.match.params.branch); + const branch = getBranch(state, repository, branchName); + const loading = isFetchBranchPending(state, repository, branchName); + const error = getFetchBranchFailure(state, repository, branchName); + return { + repository, + branchName, + branch, + loading, + error + }; +}; + +const mapDispatchToProps = dispatch => { + return { + fetchBranch: (repository: Repository, branchName: string) => { + dispatch(fetchBranch(repository, branchName)); + } + }; +}; + +export default withRouter( + connect( + mapStateToProps, + mapDispatchToProps + )(translate("repos")(BranchRoot)) +); diff --git a/scm-ui/src/repos/branches/containers/BranchView.js b/scm-ui/src/repos/branches/containers/BranchView.js deleted file mode 100644 index 5e7fa9610a..0000000000 --- a/scm-ui/src/repos/branches/containers/BranchView.js +++ /dev/null @@ -1,99 +0,0 @@ -// @flow -import React from "react"; -import BranchDetail from "../components/BranchDetail"; -import { ExtensionPoint } from "@scm-manager/ui-extensions"; -import type { Repository, Branch } from "@scm-manager/ui-types"; -import { connect } from "react-redux"; -import { translate } from "react-i18next"; -import { withRouter } from "react-router-dom"; -import { - fetchBranch, - getBranch, - getFetchBranchFailure, - isFetchBranchPending -} from "../modules/branches"; -import { ErrorPage, Loading } from "@scm-manager/ui-components"; - -type Props = { - repository: Repository, - branchName: string, - loading: boolean, - error?: Error, - branch?: Branch, - - // dispatch functions - fetchBranch: (repository: Repository, branchName: string) => void, - - // context props - t: string => string -}; - -class BranchView extends React.Component { - componentDidMount() { - const { fetchBranch, repository, branchName } = this.props; - - fetchBranch(repository, branchName); - } - - render() { - const { loading, error, t, repository, branch } = this.props; - - if (error) { - return ( - - ); - } - - if (!branch || loading) { - return ; - } - - return ( -
- -
-
- -
-
- ); - } -} - -const mapStateToProps = (state, ownProps) => { - const { repository } = ownProps; - const branchName = decodeURIComponent(ownProps.match.params.branch); - const branch = getBranch(state, repository, branchName); - const loading = isFetchBranchPending(state, repository, branchName); - const error = getFetchBranchFailure(state, repository, branchName); - return { - repository, - branchName, - branch, - loading, - error - }; -}; - -const mapDispatchToProps = dispatch => { - return { - fetchBranch: (repository: Repository, branchName: string) => { - dispatch(fetchBranch(repository, branchName)); - } - }; -}; - -export default withRouter( - connect( - mapStateToProps, - mapDispatchToProps - )(translate("repos")(BranchView)) -); diff --git a/scm-ui/src/repos/containers/ChangesetsRoot.js b/scm-ui/src/repos/containers/ChangesetsRoot.js index c4f40e0d74..c4c310d94d 100644 --- a/scm-ui/src/repos/containers/ChangesetsRoot.js +++ b/scm-ui/src/repos/containers/ChangesetsRoot.js @@ -40,7 +40,7 @@ type Props = { t: string => string }; -class BranchRoot extends React.Component { +class ChangesetsRoot extends React.Component { componentDidMount() { this.props.fetchBranches(this.props.repository); } @@ -146,4 +146,4 @@ export default compose( mapStateToProps, mapDispatchToProps ) -)(BranchRoot); +)(ChangesetsRoot); diff --git a/scm-ui/src/repos/containers/RepositoryRoot.js b/scm-ui/src/repos/containers/RepositoryRoot.js index 8c481f1adc..418b43d144 100644 --- a/scm-ui/src/repos/containers/RepositoryRoot.js +++ b/scm-ui/src/repos/containers/RepositoryRoot.js @@ -24,14 +24,13 @@ import { translate } from "react-i18next"; import RepositoryDetails from "../components/RepositoryDetails"; import EditRepo from "./EditRepo"; import BranchesOverview from "../branches/containers/BranchesOverview"; -import BranchView from "../branches/containers/BranchView"; import CreateBranch from "../branches/containers/CreateBranch"; import Permissions from "../permissions/containers/Permissions"; import type { History } from "history"; import EditRepoNavLink from "../components/EditRepoNavLink"; - -import BranchRoot from "./ChangesetsRoot"; +import BranchRoot from "../branches/containers/BranchRoot"; +import ChangesetsRoot from "./ChangesetsRoot"; import ChangesetView from "./ChangesetView"; import PermissionsNavLink from "../components/PermissionsNavLink"; import Sources from "../sources/containers/Sources"; @@ -168,7 +167,7 @@ class RepositoryRoot extends React.Component { ( - { )} /> ( - @@ -187,7 +186,7 @@ class RepositoryRoot extends React.Component { ( - Date: Wed, 3 Apr 2019 16:28:54 +0200 Subject: [PATCH 32/37] added create branch redirect --- .../repos/branches/containers/BranchRoot.js | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/scm-ui/src/repos/branches/containers/BranchRoot.js b/scm-ui/src/repos/branches/containers/BranchRoot.js index 22b7011968..f1570735e2 100644 --- a/scm-ui/src/repos/branches/containers/BranchRoot.js +++ b/scm-ui/src/repos/branches/containers/BranchRoot.js @@ -12,7 +12,6 @@ import { isFetchBranchPending } from "../modules/branches"; import { ErrorPage, Loading } from "@scm-manager/ui-components"; -import CreateBranch from "./CreateBranch"; import type { History } from "history"; type Props = { @@ -26,6 +25,7 @@ type Props = { t: string => string, history: History, match: any, + location: any, // dispatch functions fetchBranch: (repository: Repository, branchName: string) => void @@ -50,9 +50,23 @@ class BranchRoot extends React.Component { }; render() { - const { repository, branch, loading, error, t } = this.props; + const { + repository, + branch, + loading, + error, + t, + match, + location + } = this.props; + + const url = this.matchedUrl(); if (error) { + if(location.search.indexOf("?create=true") > -1) { + return ; + } + return ( { return ; } - const url = this.matchedUrl(); - return ( - ( - - )} - /> } + component={() => ( + + )} /> ); From c8fa40d5200dce82ebe91d848a90e7154b936363 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Wed, 3 Apr 2019 16:46:28 +0200 Subject: [PATCH 33/37] added specific check for errortype for create newbranch redirect --- scm-ui/src/repos/branches/containers/BranchRoot.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scm-ui/src/repos/branches/containers/BranchRoot.js b/scm-ui/src/repos/branches/containers/BranchRoot.js index f1570735e2..8d4774c23b 100644 --- a/scm-ui/src/repos/branches/containers/BranchRoot.js +++ b/scm-ui/src/repos/branches/containers/BranchRoot.js @@ -13,6 +13,7 @@ import { } from "../modules/branches"; import { ErrorPage, Loading } from "@scm-manager/ui-components"; import type { History } from "history"; +import { NotFoundError } from "./errors"; type Props = { repository: Repository, @@ -63,7 +64,7 @@ class BranchRoot extends React.Component { const url = this.matchedUrl(); if (error) { - if(location.search.indexOf("?create=true") > -1) { + if(error instanceof NotFoundError && location.search.indexOf("?create=true") > -1) { return ; } From 3122ec5fb0e530e2de42436e611fe47a0cfffd8d Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 3 Apr 2019 17:09:31 +0200 Subject: [PATCH 34/37] fixes wrong import of NotFoundError --- scm-ui/src/repos/branches/containers/BranchRoot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-ui/src/repos/branches/containers/BranchRoot.js b/scm-ui/src/repos/branches/containers/BranchRoot.js index 8d4774c23b..2e8f910275 100644 --- a/scm-ui/src/repos/branches/containers/BranchRoot.js +++ b/scm-ui/src/repos/branches/containers/BranchRoot.js @@ -13,7 +13,7 @@ import { } from "../modules/branches"; import { ErrorPage, Loading } from "@scm-manager/ui-components"; import type { History } from "history"; -import { NotFoundError } from "./errors"; +import { NotFoundError } from "@scm-manager/ui-components"; type Props = { repository: Repository, From 7bbafee1ed325f0e579ee6970331792608c9543c Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 3 Apr 2019 17:10:22 +0200 Subject: [PATCH 35/37] the branch endpoint should return a not found error with context, if the branch does not exists --- .../sonia/scm/api/v2/resources/BranchRootResource.java | 7 ++++--- .../sonia/scm/api/v2/resources/BranchRootResourceTest.java | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BranchRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BranchRootResource.java index f0edbf79fb..9e7353b4b7 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BranchRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BranchRootResource.java @@ -79,15 +79,16 @@ public class BranchRootResource { @ResponseCode(code = 500, condition = "internal server error") }) public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("branch") String branchName) throws IOException { - try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) { + NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name); + try (RepositoryService repositoryService = serviceFactory.create(namespaceAndName)) { Branches branches = repositoryService.getBranchesCommand().getBranches(); return branches.getBranches() .stream() .filter(branch -> branchName.equals(branch.getName())) .findFirst() - .map(branch -> branchToDtoMapper.map(branch, new NamespaceAndName(namespace, name))) + .map(branch -> branchToDtoMapper.map(branch, namespaceAndName)) .map(Response::ok) - .orElse(Response.status(Response.Status.NOT_FOUND)) + .orElseThrow(() -> notFound(entity("branch", branchName).in(namespaceAndName))) .build(); } catch (CommandNotSupportedException ex) { return Response.status(Response.Status.BAD_REQUEST).build(); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java index 9fb20c0922..2c83d5e3e1 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java @@ -129,6 +129,7 @@ public class BranchRootResourceTest extends RepositoryTestBase { dispatcher.invoke(request, response); assertEquals(404, response.getStatus()); + assertEquals("application/vnd.scmm-error+json;v=2", response.getOutputHeaders().getFirst("Content-Type")); } @Test From ea986e3b093f32238001bf1e4e1b6d2c55faacda Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 3 Apr 2019 17:17:58 +0200 Subject: [PATCH 36/37] use ErrorNotification instead of ErrorPage, because we are already wrapped by a Page --- scm-ui/public/locales/de/repos.json | 2 -- scm-ui/public/locales/en/repos.json | 2 -- scm-ui/src/repos/branches/containers/BranchRoot.js | 13 +++---------- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/scm-ui/public/locales/de/repos.json b/scm-ui/public/locales/de/repos.json index 6170c9021f..6f7846df72 100644 --- a/scm-ui/public/locales/de/repos.json +++ b/scm-ui/public/locales/de/repos.json @@ -44,8 +44,6 @@ "subtitle": "Erstellen eines neuen Repository" }, "branches": { - "errorTitle": "Fehler", - "errorSubtitle": "Unbekannter Branch Fehler", "overview": { "title": "Übersicht aller verfügbaren Branches", "createButton": "Branch erstellen" diff --git a/scm-ui/public/locales/en/repos.json b/scm-ui/public/locales/en/repos.json index 4eeddea8b2..89492f427d 100644 --- a/scm-ui/public/locales/en/repos.json +++ b/scm-ui/public/locales/en/repos.json @@ -44,8 +44,6 @@ "subtitle": "Create a new repository" }, "branches": { - "errorTitle": "Error", - "errorSubtitle": "Unknown branch error", "overview": { "title": "Overview of all branches", "createButton": "Create Branch" diff --git a/scm-ui/src/repos/branches/containers/BranchRoot.js b/scm-ui/src/repos/branches/containers/BranchRoot.js index 2e8f910275..2e9fb10f73 100644 --- a/scm-ui/src/repos/branches/containers/BranchRoot.js +++ b/scm-ui/src/repos/branches/containers/BranchRoot.js @@ -3,7 +3,6 @@ import React from "react"; import BranchView from "../components/BranchView"; import { connect } from "react-redux"; import { Redirect, Route, Switch, withRouter } from "react-router-dom"; -import { translate } from "react-i18next"; import type { Repository, Branch } from "@scm-manager/ui-types"; import { fetchBranch, @@ -11,7 +10,7 @@ import { getFetchBranchFailure, isFetchBranchPending } from "../modules/branches"; -import { ErrorPage, Loading } from "@scm-manager/ui-components"; +import { ErrorNotification, Loading } from "@scm-manager/ui-components"; import type { History } from "history"; import { NotFoundError } from "@scm-manager/ui-components"; @@ -23,7 +22,6 @@ type Props = { error?: Error, // context props - t: string => string, history: History, match: any, location: any, @@ -56,7 +54,6 @@ class BranchRoot extends React.Component { branch, loading, error, - t, match, location } = this.props; @@ -69,11 +66,7 @@ class BranchRoot extends React.Component { } return ( - + ); } @@ -122,5 +115,5 @@ export default withRouter( connect( mapStateToProps, mapDispatchToProps - )(translate("repos")(BranchRoot)) + )(BranchRoot) ); From a38f89d8f49ddcb423a4cec50c3600332c4ff31d Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 3 Apr 2019 15:54:45 +0000 Subject: [PATCH 37/37] Close branch feature/branch-overview