Introduced dumb BranchSelector; moved fetching of branches to BranchRoot

This commit is contained in:
Philipp Czora
2018-10-16 17:04:28 +02:00
parent 53fe671a27
commit e6fb2a8de7
7 changed files with 275 additions and 125 deletions

View File

@@ -5,7 +5,7 @@ import React from "react";
type Props = {
options: string[],
optionSelected: string => void,
preselectedOption: string
preselectedOption?: string
};
class DropDown extends React.Component<Props> {
@@ -13,7 +13,10 @@ class DropDown extends React.Component<Props> {
const { options, preselectedOption } = this.props;
return (
<div className="select">
<select value={preselectedOption} onChange={this.change}>
<select
value={preselectedOption ? preselectedOption : ""}
onChange={this.change}
>
<option key="" />
{options.map(option => {
return (
@@ -27,7 +30,7 @@ class DropDown extends React.Component<Props> {
);
}
change = event => {
change = (event: Event) => {
this.props.optionSelected(event.target.value);
};
}

View File

@@ -4,30 +4,31 @@ import type { Branch, Repository } from "@scm-manager/ui-types";
import { connect } from "react-redux";
import {
fetchBranches,
getBranch,
getBranches,
getBranchNames,
getFetchBranchesFailure,
isFetchBranchesPending
} from "../modules/branches";
import DropDown from "../components/DropDown";
import type { History } from "history";
import { withRouter } from "react-router-dom";
import { ErrorPage, Loading } from "@scm-manager/ui-components";
import { translate } from "react-i18next";
type Props = {
repository: Repository,
branches: Branch[],
fetchBranches: Repository => void,
history: History,
match: any,
selectedBranch?: Branch,
label: string, //TODO: Should this be here?
loading: boolean,
branchSelected: string => void,
error: Error,
onChange: string => void,
children: React.Node,
selected?: string,
// State props
branches: Branch[],
error: Error,
loading: boolean,
// Dispatch props
fetchBranches: Repository => void,
// Context props
t: string => string
};
type State = {
@@ -41,12 +42,10 @@ class BranchChooser extends React.Component<Props, State> {
}
componentDidMount() {
console.log("BC CDM");
this.props.fetchBranches(this.props.repository);
}
render() {
console.log("Branch chooser render");
const { loading, error, t, repository } = this.props;
@@ -88,8 +87,7 @@ class BranchChooser extends React.Component<Props, State> {
}
renderBranchChooser() {
const { label, match, branches } = this.props;
const selectedBranchName = match.params.branch;
const { label, branches, selected } = this.props;
if (!branches || branches.length === 0) {
return null;
@@ -100,22 +98,45 @@ class BranchChooser extends React.Component<Props, State> {
<label className="label">{label}</label>
<DropDown
options={branches.map(b => b.name)}
preselectedOption={selectedBranchName}
optionSelected={this.branchSelected}
preselectedOption={
this.state.selectedBranch
? this.state.selectedBranch.name
: selected
}
optionSelected={(branchName: string) => {
this.branchSelected(branchName, true);
}}
/>
</div>
);
}
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(
export default connect(
mapStateToProps,
mapDispatchToProps
)(translate("repos")(BranchChooser))
);
)(translate("repos")(BranchChooser));

View File

@@ -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<Props> {
type State = {
selectedBranch?: Branch
};
class BranchRoot extends React.PureComponent<Props, State> {
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/`
`${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 <Loading />;
}
if (!repository || !branches) {
return null;
}
return (
<BranchChooser
repository={this.props.repository}
label={"Branches"}
branchSelected={this.branchSelected}
>
<RouteDelegate repository={this.props.repository} url={url} />
</BranchChooser>
<>
<BranchSelector
branches={branches}
selected={(b: Branch) => {
this.branchSelected(b);
}}
/>
<Route
path={`${url}/changesets/:page?`}
component={() => (
<Changesets
repository={repository}
branch={this.state.selectedBranch}
/>
)}
/>
</>
);
}
}
type RDProps = {
repository: Repository,
branch: Branch,
url: string
const mapDispatchToProps = dispatch => {
return {
fetchBranches: (repo: Repository) => {
dispatch(fetchBranches(repo));
}
};
};
class RouteDelegate extends React.Component<RDProps> {
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 (
<Route
exact
path={`${url}/:branch/changesets/:page?`}
component={() => <Changesets repository={repository} branch={branch} />}
/>
);
}
}
const branches = getBranches(state, repository);
return {
loading,
error,
branches
};
};
export default withRouter(BranchRoot);
export default compose(
connect(
mapStateToProps,
mapDispatchToProps
),
withRouter
)(BranchRoot);

View File

@@ -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<Props, State> {
constructor(props: Props) {
super(props);
this.state = {};
}
render() {
const { branches } = this.props;
if (branches) {
return (
<>
<DropDown
options={branches.map(b => 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;

View File

@@ -46,9 +46,31 @@ class Changesets extends React.Component<Props, State> {
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<Props, State> {
}
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 (

View File

@@ -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,11 +98,12 @@ class RepositoryRoot extends React.Component<Props> {
}
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 (
<Page title={repository.namespace + "/" + repository.name}>
<div className="columns">
<div className="column is-three-quarters">
<Switch>
<Route
path={url}
exact
@@ -112,22 +113,17 @@ class RepositoryRoot extends React.Component<Props> {
path={`${url}/edit`}
component={() => <Edit repository={repository} />}
/>
{/*<Route*/}
{/*path={`${url}/changesets/:page?`}*/}
{/*component={() => (*/}
{/*<BranchChooser*/}
{/*repository={repository}*/}
{/*label={"Branches"}*/}
{/*branchSelected={this.branchSelected}*/}
{/*>*/}
{/*<Changesets repository={repository} />*/}
{/*</BranchChooser>*/}
{/*)}*/}
{/*/>*/}
<Route
path={`${url}/branches`}
render={() => <BranchRoot repository={repository} />}
path={`${url}/branches/:branch`}
render={() => (
<BranchRoot
repository={repository}
baseUrl={`${url}/branches`}
/>
)}
/>
</Switch>
</div>
<div className="column">
<Navigation>

View File

@@ -1,11 +1,21 @@
// @flow
import {FAILURE_SUFFIX, PENDING_SUFFIX, SUCCESS_SUFFIX} from "../../modules/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";
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}`;