diff --git a/scm-ui/src/repos/components/DropDown.js b/scm-ui/src/repos/components/DropDown.js index bd44e30f59..d68ec9ce35 100644 --- a/scm-ui/src/repos/components/DropDown.js +++ b/scm-ui/src/repos/components/DropDown.js @@ -5,7 +5,7 @@ import React from "react"; type Props = { options: string[], optionSelected: string => void, - preselectedOption: string + preselectedOption?: string }; class DropDown extends React.Component { @@ -13,7 +13,10 @@ class DropDown extends React.Component { const { options, preselectedOption } = this.props; return (
-
); } - branchSelected = (branch: string) => { + branchSelected = (branch: string, changed: boolean) => { for (let b of this.props.branches) { if (b.name === branch) { - this.setState({ selectedBranch: b }); - this.props.branchSelected(b.name); + this.updateBranch(branch, b, changed); break; } } }; + + updateBranch = (branchName: string, branch: Branch, changed: boolean) => { + this.setState( + prevState => { + if ( + !prevState.selectedBranch || + branchName !== prevState.selectedBranch.name + ) { + return { selectedBranch: branch }; + } + }, + () => { + if (changed) { + this.props.onChange(branch.name); + } + } + ); + }; } const mapDispatchToProps = dispatch => { @@ -127,26 +148,19 @@ const mapDispatchToProps = dispatch => { }; const mapStateToProps = (state: any, ownProps: Props) => { - const { repository, match } = ownProps; + const { repository } = ownProps; const loading = isFetchBranchesPending(state, repository); const error = getFetchBranchesFailure(state, repository); - const selectedBranch = getBranch( - state, - repository, - decodeURIComponent(match.params.branch) - ); + const branches = getBranches(state, repository); return { - // loading, - selectedBranch, - // error, + loading, + error, branches }; }; -export default withRouter( - connect( - mapStateToProps, - mapDispatchToProps - )(translate("repos")(BranchChooser)) -); +export default connect( + mapStateToProps, + mapDispatchToProps +)(translate("repos")(BranchChooser)); diff --git a/scm-ui/src/repos/containers/BranchRoot.js b/scm-ui/src/repos/containers/BranchRoot.js index 4d98dbde29..b7ac0a45ca 100644 --- a/scm-ui/src/repos/containers/BranchRoot.js +++ b/scm-ui/src/repos/containers/BranchRoot.js @@ -2,82 +2,145 @@ import React from "react"; import type { Repository, Branch } from "@scm-manager/ui-types"; -import BranchChooser from "./BranchChooser"; -import { Route, withRouter } from "react-router-dom"; +import { Route, Switch, withRouter } from "react-router-dom"; import Changesets from "./Changesets"; +import BranchSelector from "./BranchSelector"; +import { connect } from "react-redux"; +import { ErrorPage, Loading } from "@scm-manager/ui-components"; +import { + fetchBranches, + getBranches, + getFetchBranchesFailure, + isFetchBranchesPending +} from "../modules/branches"; +import { compose } from "redux"; type Props = { repository: Repository, + baseUrl: string, + + // State props + branches: Branch[], + loading: boolean, + + // Dispatch props + fetchBranches: Repository => void, + + // Context props history: History, match: any }; -class BranchRoot extends React.Component { +type State = { + selectedBranch?: Branch +}; + +class BranchRoot extends React.PureComponent { + constructor(props: Props) { + super(props); + this.state = {}; + } + + componentDidMount() { + this.props.fetchBranches(this.props.repository); + } + + componentDidUpdate(prevProps: Props) { + const { branches, match, loading } = this.props; + console.log("BR did update"); + const branchName = decodeURIComponent(match.params.branch); + if (branches) { + if ( + (!loading && prevProps.loading) || + match.url !== prevProps.match.url + ) { + this.setState({ + selectedBranch: branches.find(b => b.name === branchName) + }); + } + } + } + stripEndingSlash = (url: string) => { if (url.endsWith("/")) { - return url.substring(0, url.length - 2); + return url.substring(0, url.length - 1); } return url; }; matchedUrl = () => { - return this.stripEndingSlash(this.props.match.url); + return this.stripEndingSlash(this.props.baseUrl); }; - branchSelected = (branchName: string) => { + branchSelected = (branch: Branch) => { const url = this.matchedUrl(); - if (branchName === "") { - this.props.history.push(`${url}/changesets/`); - } else { - this.props.history.push( - `${url}/${encodeURIComponent(branchName)}/changesets/` - ); - } + this.props.history.push( + `${url}/${encodeURIComponent(branch.name)}/changesets/` + ); }; render() { - const { repository } = this.props; - const url = this.matchedUrl(); - if (!repository) { + const { repository, match, branches, loading } = this.props; + const url = this.stripEndingSlash(match.url); + + if (loading) { + return ; + } + + if (!repository || !branches) { return null; } + + return ( - - - + <> + { + this.branchSelected(b); + }} + /> + ( + + )} + /> + + ); } } -type RDProps = { - repository: Repository, - branch: Branch, - url: string + +const mapDispatchToProps = dispatch => { + return { + fetchBranches: (repo: Repository) => { + dispatch(fetchBranches(repo)); + } + }; }; -class RouteDelegate extends React.Component { - shouldComponentUpdate(nextProps: RDProps, nextState: any) { - return ( - nextProps.repository !== this.props.repository || - nextProps.branch !== this.props.branch || - nextProps.url !== this.props.url - ); - } +const mapStateToProps = (state: any, ownProps: Props) => { + const { repository } = ownProps; + const loading = isFetchBranchesPending(state, repository); + const error = getFetchBranchesFailure(state, repository); - render() { - const { url, repository, branch } = this.props; - return ( - } - /> - ); - } -} + const branches = getBranches(state, repository); + return { + loading, + error, + branches + }; +}; -export default withRouter(BranchRoot); +export default compose( + connect( + mapStateToProps, + mapDispatchToProps + ), + withRouter +)(BranchRoot); diff --git a/scm-ui/src/repos/containers/BranchSelector.js b/scm-ui/src/repos/containers/BranchSelector.js new file mode 100644 index 0000000000..bec66ca143 --- /dev/null +++ b/scm-ui/src/repos/containers/BranchSelector.js @@ -0,0 +1,46 @@ +// @flow + +import React from "react"; +import type { Branch } from "@scm-manager/ui-types"; +import DropDown from "../components/DropDown"; + +type Props = { + branches: Branch[], // TODO: Use generics? + selected?: Branch => void +}; + +type State = { selectedBranch?: Branch }; +class BranchSelector extends React.Component { + constructor(props: Props) { + super(props); + this.state = {}; + } + render() { + const { branches } = this.props; + if (branches) { + return ( + <> + b.name)} + optionSelected={this.branchSelected} + preselectedOption={ + this.state.selectedBranch ? this.state.selectedBranch.name : "" + } + /> + + ); + } + } + + branchSelected = (branchName: string) => { + const { branches, selected } = this.props; + const branch = branches.find(b => b.name === branchName); + + if (branch) { + selected(branch); + this.setState({ selectedBranch: branch }); + } + }; +} + +export default BranchSelector; diff --git a/scm-ui/src/repos/containers/Changesets.js b/scm-ui/src/repos/containers/Changesets.js index 4d26ea04a1..6fd6cac825 100644 --- a/scm-ui/src/repos/containers/Changesets.js +++ b/scm-ui/src/repos/containers/Changesets.js @@ -46,9 +46,31 @@ class Changesets extends React.Component { match } = this.props; - console.log("branch"); - console.log(branch); const { page } = match.params; + if (!branch) { + return; + } + if (!page) { + fetchChangesetsByBranch(repository, branch); + } else { + fetchChangesetsByBranchAndPage(repository, branch, page); + } + } + + componentDidUpdate(prevProps: Props) { + const { + match, + repository, + branch, + fetchChangesetsByBranch, + fetchChangesetsByBranchAndPage + } = this.props; + const { page } = match.params; + + if (branch === prevProps.branch) { + return; + } + if (!page) { fetchChangesetsByBranch(repository, branch); } else { @@ -57,11 +79,7 @@ class Changesets extends React.Component { } render() { - const { repository, branch, changesets, loading, error, t } = this.props; - - if (!repository || !branch) { - return null; - } + const { changesets, loading, error, t } = this.props; if (error) { return ( diff --git a/scm-ui/src/repos/containers/RepositoryRoot.js b/scm-ui/src/repos/containers/RepositoryRoot.js index 7acf3188b0..f248bd07eb 100644 --- a/scm-ui/src/repos/containers/RepositoryRoot.js +++ b/scm-ui/src/repos/containers/RepositoryRoot.js @@ -8,7 +8,7 @@ import { isFetchRepoPending } from "../modules/repos"; import { connect } from "react-redux"; -import { Route } from "react-router-dom"; +import { Route, Switch } from "react-router-dom"; import type { Repository } from "@scm-manager/ui-types"; import { ErrorPage, @@ -98,36 +98,32 @@ class RepositoryRoot extends React.Component { } const url = this.matchedUrl(); - // TODO: Changesets need to be adjusted (i.e. sub-routes need to be handled in sub-components) + // todo: default branch return (
- } - /> - } - /> - {/* (*/} - {/**/} - {/**/} - {/**/} - {/*)}*/} - {/*/>*/} - } - /> + + } + /> + } + /> + + ( + + )} + /> +
diff --git a/scm-ui/src/repos/modules/changesets.js b/scm-ui/src/repos/modules/changesets.js index 191de7b37d..925f37af2e 100644 --- a/scm-ui/src/repos/modules/changesets.js +++ b/scm-ui/src/repos/modules/changesets.js @@ -1,11 +1,21 @@ // @flow -import {FAILURE_SUFFIX, PENDING_SUFFIX, SUCCESS_SUFFIX} from "../../modules/types"; -import {apiClient} from "@scm-manager/ui-components"; -import {isPending} from "../../modules/pending"; -import {getFailure} from "../../modules/failure"; -import {combineReducers} from "redux"; -import type {Action, Branch, Changeset, PagedCollection, Repository} from "@scm-manager/ui-types"; +import { + FAILURE_SUFFIX, + PENDING_SUFFIX, + SUCCESS_SUFFIX +} from "../../modules/types"; +import { apiClient } from "@scm-manager/ui-components"; +import { isPending } from "../../modules/pending"; +import { getFailure } from "../../modules/failure"; +import { combineReducers } from "redux"; +import type { + Action, + Branch, + Changeset, + PagedCollection, + Repository +} from "@scm-manager/ui-types"; export const FETCH_CHANGESETS = "scm/repos/FETCH_CHANGESETS"; export const FETCH_CHANGESETS_PENDING = `${FETCH_CHANGESETS}_${PENDING_SUFFIX}`;