fixed branch selection urls and styles branch selector

This commit is contained in:
Sebastian Sdorra
2018-10-17 11:33:40 +02:00
parent e841c06934
commit e6c16c3fc5
7 changed files with 92 additions and 208 deletions

View File

@@ -3,16 +3,16 @@ import React from "react";
import {translate} from "react-i18next"; import {translate} from "react-i18next";
import type {PagedCollection} from "@scm-manager/ui-types"; import type {PagedCollection} from "@scm-manager/ui-types";
import {Button} from "./buttons"; import {Button} from "./buttons";
import {withRouter} from "react-router-dom";
type Props = { type Props = {
collection: PagedCollection, collection: PagedCollection,
t: string => string, page: number,
match: any
// context props
t: string => string
}; };
class LinkPaginator extends React.Component<Props> { class LinkPaginator extends React.Component<Props> {
//TODO: HATEOAS-Links verwenden
renderFirstButton() { renderFirstButton() {
return ( return (
@@ -26,30 +26,32 @@ class LinkPaginator extends React.Component<Props> {
} }
renderPreviousButton(label?: string) { renderPreviousButton(label?: string) {
const { match } = this.props; const { page } = this.props;
const page = parseInt(match.params.page) || 1;
const previousPage = page - 1; const previousPage = page - 1;
return ( return (
<Button <Button
className={"pagination-previous"} className={"pagination-previous"}
label={label ? label : previousPage.toString()} label={label ? label : previousPage.toString()}
disabled={previousPage < 1} disabled={!this.hasLink("prev")}
link={`${previousPage}`} link={`${previousPage}`}
/> />
); );
} }
renderNextButton(label?: string) { hasLink(name: string) {
const { match, collection } = this.props; const { collection } = this.props;
let page = parseInt(match.params.page) || 1; return collection._links[name];
}
renderNextButton(label?: string) {
const { page } = this.props;
const nextPage = page + 1; const nextPage = page + 1;
return ( return (
<Button <Button
className={"pagination-next"} className={"pagination-next"}
label={label ? label : nextPage.toString()} label={label ? label : nextPage.toString()}
disabled={nextPage >= collection.pageTotal + 1} disabled={!this.hasLink("next")}
link={`${nextPage}`} link={`${nextPage}`}
/> />
); );
@@ -128,4 +130,4 @@ class LinkPaginator extends React.Component<Props> {
} }
} }
export default withRouter(translate("commons")(LinkPaginator)); export default translate("commons")(LinkPaginator);

View File

@@ -59,6 +59,9 @@
"mail": "Mail" "mail": "Mail"
} }
}, },
"branch-selector": {
"label": "Branches"
},
"branch-chooser": { "branch-chooser": {
"error-title": "Error", "error-title": "Error",
"error-subtitle": "Could not fetch branches" "error-subtitle": "Could not fetch branches"

View File

@@ -1,18 +1,20 @@
// @flow // @flow
import React from "react"; import React from "react";
import classNames from "classnames";
type Props = { type Props = {
options: string[], options: string[],
optionSelected: string => void, optionSelected: string => void,
preselectedOption?: string preselectedOption?: string,
className: any
}; };
class DropDown extends React.Component<Props> { class DropDown extends React.Component<Props> {
render() { render() {
const { options, preselectedOption } = this.props; const { options, preselectedOption, className } = this.props;
return ( return (
<div className="select"> <div className={classNames(className, "select")}>
<select <select
value={preselectedOption ? preselectedOption : ""} value={preselectedOption ? preselectedOption : ""}
onChange={this.change} onChange={this.change}

View File

@@ -1,166 +0,0 @@
// @flow
import * as React from "react";
import type { Branch, Repository } from "@scm-manager/ui-types";
import { connect } from "react-redux";
import {
fetchBranches,
getBranches,
getFetchBranchesFailure,
isFetchBranchesPending
} from "../modules/branches";
import DropDown from "../components/DropDown";
import type { History } from "history";
import { ErrorPage, Loading } from "@scm-manager/ui-components";
import { translate } from "react-i18next";
type Props = {
repository: Repository,
label: string, //TODO: Should this be here?
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 = {
selectedBranch?: Branch
};
class BranchChooser extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {};
}
componentDidMount() {
this.props.fetchBranches(this.props.repository);
}
render() {
const { loading, error, t, repository } = this.props;
if (error) {
return (
<ErrorPage
title={t("branch-chooser.error-title")}
subtitle={t("branch-chooser.error-subtitle")}
error={error}
/>
);
}
if (!repository) {
return null;
}
if (loading) {
return <Loading />;
}
const { selectedBranch } = this.state;
const childrenWithBranch = React.Children.map(
this.props.children,
child => {
return React.cloneElement(child, {
branch: selectedBranch
});
}
);
return (
<>
{this.renderBranchChooser()}
{childrenWithBranch}
</>
);
}
renderBranchChooser() {
const { label, branches, selected } = this.props;
if (!branches || branches.length === 0) {
return null;
}
return (
<div className={"box"}>
<label className="label">{label}</label>
<DropDown
options={branches.map(b => b.name)}
preselectedOption={
this.state.selectedBranch
? this.state.selectedBranch.name
: selected
}
optionSelected={(branchName: string) => {
this.branchSelected(branchName, true);
}}
/>
</div>
);
}
branchSelected = (branch: string, changed: boolean) => {
for (let b of this.props.branches) {
if (b.name === branch) {
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 => {
return {
fetchBranches: (repo: Repository) => {
dispatch(fetchBranches(repo));
}
};
};
const mapStateToProps = (state: any, ownProps: Props) => {
const { repository } = ownProps;
const loading = isFetchBranchesPending(state, repository);
const error = getFetchBranchesFailure(state, repository);
const branches = getBranches(state, repository);
return {
loading,
error,
branches
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(translate("repos")(BranchChooser));

View File

@@ -19,6 +19,8 @@ type Props = {
repository: Repository, repository: Repository,
baseUrl: string, baseUrl: string,
selected: string, selected: string,
baseUrlWithBranch: string,
baseUrlWithoutBranch: string,
// State props // State props
branches: Branch[], branches: Branch[],
@@ -49,15 +51,16 @@ class BranchRoot extends React.Component<Props> {
return url; return url;
}; };
matchedUrl = () => { branchSelected = (branch?: Branch) => {
return this.stripEndingSlash(this.props.baseUrl); let url;
}; if (branch) {
url = `${this.props.baseUrlWithBranch}/${encodeURIComponent(
branchSelected = (branch: Branch) => { branch.name
const url = this.matchedUrl(); )}/changesets/`;
this.props.history.push( } else {
`${url}/${encodeURIComponent(branch.name)}/changesets/` url = `${this.props.baseUrlWithoutBranch}/`;
); }
this.props.history.push(url);
}; };
findSelectedBranch = () => { findSelectedBranch = () => {

View File

@@ -3,10 +3,24 @@
import React from "react"; import React from "react";
import type { Branch } from "@scm-manager/ui-types"; import type { Branch } from "@scm-manager/ui-types";
import DropDown from "../components/DropDown"; import DropDown from "../components/DropDown";
import { translate } from "react-i18next";
import injectSheet from "react-jss";
import { compose } from "redux";
import classNames from "classnames";
const styles = {
zeroflex: {
flexGrow: 0
}
};
type Props = { type Props = {
branches: Branch[], // TODO: Use generics? branches: Branch[], // TODO: Use generics?
selected?: Branch => void selected?: Branch => void,
// context props
classes: Object,
t: string => string
}; };
type State = { selectedBranch?: Branch }; type State = { selectedBranch?: Branch };
@@ -18,19 +32,33 @@ class BranchSelector extends React.Component<Props, State> {
} }
render() { render() {
const { branches } = this.props; const { branches, classes, t } = this.props;
if (branches) { if (branches) {
return ( return (
<> <div className="box field is-horizontal">
<DropDown <div
options={branches.map(b => b.name)} className={classNames("field-label", "is-normal", classes.zeroflex)}
optionSelected={this.branchSelected} >
preselectedOption={ <label className="label">{t("branch-selector.label")}</label>
this.state.selectedBranch ? this.state.selectedBranch.name : "" </div>
} <div className="field-body">
/> <div className="field is-narrow">
</> <div className="control">
<DropDown
className="is-fullwidth"
options={branches.map(b => b.name)}
optionSelected={this.branchSelected}
preselectedOption={
this.state.selectedBranch
? this.state.selectedBranch.name
: ""
}
/>
</div>
</div>
</div>
</div>
); );
} }
} }
@@ -39,11 +67,12 @@ class BranchSelector extends React.Component<Props, State> {
const { branches, selected } = this.props; const { branches, selected } = this.props;
const branch = branches.find(b => b.name === branchName); const branch = branches.find(b => b.name === branchName);
if (branch) { selected(branch);
selected(branch); this.setState({ selectedBranch: branch });
this.setState({ selectedBranch: branch });
}
}; };
} }
export default BranchSelector; export default compose(
injectSheet(styles),
translate("repos")
)(BranchSelector);

View File

@@ -111,12 +111,23 @@ class RepositoryRoot extends React.Component<Props> {
path={`${url}/edit`} path={`${url}/edit`}
component={() => <Edit repository={repository} />} component={() => <Edit repository={repository} />}
/> />
<Route
path={`${url}/changesets`}
render={() => (
<BranchRoot
repository={repository}
baseUrlWithBranch={`${url}/branches`}
baseUrlWithoutBranch={`${url}/changesets`}
/>
)}
/>
<Route <Route
path={`${url}/branches/:branch/changesets`} path={`${url}/branches/:branch/changesets`}
render={() => ( render={() => (
<BranchRoot <BranchRoot
repository={repository} repository={repository}
baseUrl={`${url}/branches`} baseUrlWithBranch={`${url}/branches`}
baseUrlWithoutBranch={`${url}/changesets`}
/> />
)} )}
/> />
@@ -128,7 +139,7 @@ class RepositoryRoot extends React.Component<Props> {
<NavLink to={url} label={t("repository-root.information")} /> <NavLink to={url} label={t("repository-root.information")} />
<NavLink <NavLink
activeOnlyWhenExact={false} activeOnlyWhenExact={false}
to={`${url}/branches/master/changesets/1`} to={`${url}/changesets/`}
label={t("repository-root.history")} label={t("repository-root.history")}
activeWhenMatch={this.matches} activeWhenMatch={this.matches}
/> />