fix routes for sources and changesets // fix typing errors

This commit is contained in:
Eduard Heimbuch
2020-01-08 10:31:43 +01:00
parent 20c00e7222
commit c73e85e3d6
13 changed files with 130 additions and 257 deletions

View File

@@ -1,7 +1,15 @@
import React, { FormEvent } from "react";
import { WithTranslation, withTranslation } from "react-i18next";
import { Branch, Repository, Link } from "@scm-manager/ui-types";
import { apiClient, BranchSelector, ErrorPage, Loading, Subtitle, Level, SubmitButton } from "@scm-manager/ui-components";
import {
apiClient,
BranchSelector,
ErrorPage,
Loading,
Subtitle,
Level,
SubmitButton
} from "@scm-manager/ui-components";
type Props = WithTranslation & {
repository: Repository;
@@ -13,7 +21,7 @@ type State = {
submitPending: boolean;
error?: Error;
branches: Branch[];
selectedBranchName?: string;
selectedBranchName: string;
defaultBranchChanged: boolean;
disabled: boolean;
};
@@ -29,6 +37,7 @@ class RepositoryConfig extends React.Component<Props, State> {
loadingDefaultBranch: true,
submitPending: false,
branches: [],
selectedBranchName: "",
defaultBranchChanged: false,
disabled: true
};
@@ -87,16 +96,16 @@ class RepositoryConfig extends React.Component<Props, State> {
if (!branch) {
this.setState({
...this.state,
selectedBranchName: undefined,
selectedBranchName: "",
defaultBranchChanged: false
});
return;
}
} else {
this.setState({
...this.state,
selectedBranchName: branch.name,
defaultBranchChanged: false
});
}
};
submit = (event: FormEvent) => {
@@ -164,7 +173,7 @@ class RepositoryConfig extends React.Component<Props, State> {
<BranchSelector
label={t("scm-git-plugin.repo-config.default-branch")}
branches={this.state.branches}
selected={this.branchSelected}
onSelectBranch={this.branchSelected}
selectedBranch={this.state.selectedBranchName}
disabled={disabled}
/>

View File

@@ -1,4 +1,4 @@
import React from "react";
import React, { FC } from "react";
import classNames from "classnames";
import styled from "styled-components";
import { Branch } from "@scm-manager/ui-types";
@@ -6,16 +6,12 @@ import DropDown from "./forms/DropDown";
type Props = {
branches: Branch[];
selected: (branch: Branch) => void;
onSelectBranch: (branch: Branch | undefined) => void;
selectedBranch?: string;
label: string;
disabled?: boolean;
};
type State = {
selectedBranch?: Branch;
};
const ZeroflexFieldLabel = styled.div`
flex-basis: inherit;
flex-grow: 0;
@@ -29,25 +25,7 @@ const NoBottomMarginField = styled.div`
margin-bottom: 0 !important;
`;
export default class BranchSelector extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {};
}
componentDidMount() {
const { branches } = this.props;
if (branches) {
const selectedBranch = branches.find(branch => branch.name === this.props.selectedBranch);
this.setState({
selectedBranch
});
}
}
render() {
const { branches, label, disabled } = this.props;
const BranchSelector: FC<Props> = ({ branches, onSelectBranch, selectedBranch, label, disabled }) => {
if (branches) {
return (
<div className={classNames("field", "is-horizontal")}>
@@ -60,9 +38,9 @@ export default class BranchSelector extends React.Component<Props, State> {
<DropDown
className="is-fullwidth"
options={branches.map(b => b.name)}
optionSelected={this.branchSelected}
optionSelected={branch => onSelectBranch(branches.filter(b => b.name === branch)[0])}
disabled={!!disabled}
preselectedOption={this.state.selectedBranch ? this.state.selectedBranch.name : ""}
preselectedOption={selectedBranch && selectedBranch}
/>
</MinWidthControl>
</NoBottomMarginField>
@@ -72,23 +50,6 @@ export default class BranchSelector extends React.Component<Props, State> {
} else {
return null;
}
}
};
branchSelected = (branchName: string) => {
const { branches, selected } = this.props;
if (!branchName) {
this.setState({
selectedBranch: undefined
});
selected(undefined);
return;
}
const branch = branches.find(b => b.name === branchName);
selected(branch);
this.setState({
selectedBranch: branch
});
};
}
export default BranchSelector;

View File

@@ -6,7 +6,7 @@ export type Description = {
};
export function createChangesetLink(repository: Repository, changeset: Changeset) {
return `/repo/${repository.namespace}/${repository.name}/changeset/${changeset.id}`;
return `/repo/${repository.namespace}/${repository.name}/code/changeset/${changeset.id}`;
}
export function createSourcesLink(repository: Repository, changeset: Changeset) {

View File

@@ -73,7 +73,7 @@ class BranchRoot extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { repository } = ownProps;
const branchName = decodeURIComponent(ownProps.match.params.branch);
const branch = getBranch(state, repository, branchName);
@@ -88,7 +88,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchBranch: (repository: Repository, branchName: string) => {
dispatch(fetchBranch(repository, branchName));

View File

@@ -18,6 +18,7 @@ import {
isFetchBranchesPending,
getFetchBranchesFailure
} from "../modules/branches";
import { compose } from "redux";
type Props = WithTranslation & {
loading?: boolean;
@@ -92,7 +93,7 @@ class CreateBranch extends React.Component<Props> {
}
}
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchBranches: (repository: Repository) => {
dispatch(fetchBranches(repository));
@@ -111,7 +112,7 @@ const mapDispatchToProps = dispatch => {
};
};
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { repository } = ownProps;
const loading = isFetchBranchesPending(state, repository) || isCreateBranchPending(state, repository);
const error = getFetchBranchesFailure(state, repository) || getCreateBranchFailure(state, repository);
@@ -126,9 +127,8 @@ const mapStateToProps = (state, ownProps) => {
};
};
export default withRouter(
connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation("repos")(CreateBranch))
);
export default compose(
withTranslation("repos"),
connect(mapStateToProps, mapDispatchToProps),
withRouter
)(CreateBranch);

View File

@@ -17,19 +17,25 @@ type Props = {
const CodeViewSwitcher: FC<Props> = ({ url }) => {
const [t] = useTranslation("repos");
const createDestinationUrl = (destination: string) => {
let splittedUrl = url.split("/");
splittedUrl[5] = destination;
return splittedUrl.join("/")
};
return (
<ButtonAddons>
<SmallButton
label={t("code.commits")}
icon="fa fa-exchange-alt"
color={url.includes("/code/changeset") ? "link is-selected" : undefined}
link={url.replace("/code/sources", "/code/changesets")}
color={url.includes("/code/changesets/") ? "link is-selected" : undefined}
link={createDestinationUrl("changesets")}
/>
<SmallButton
label={t("code.sources")}
icon="fa fa-code"
color={url.includes("/code/sources") ? "link is-selected" : undefined}
link={url.replace("/code/changesets", "/code/sources")}
color={url.includes("/code/sources/") ? "link is-selected" : undefined}
link={createDestinationUrl("sources")}
/>
</ButtonAddons>
);

View File

@@ -1,11 +1,9 @@
import React from "react";
import styled from "styled-components";
import { Route, withRouter, RouteComponentProps } from "react-router-dom";
import ChangesetView from "../../containers/ChangesetView";
import { Route, RouteComponentProps, withRouter } from "react-router-dom";
import Sources from "../../sources/containers/Sources";
import SourceExtensions from "../../sources/containers/SourceExtensions";
import ChangesetsRoot from "../../containers/ChangesetsRoot";
import { Repository, Branch } from "@scm-manager/ui-types";
import { Branch, Repository } from "@scm-manager/ui-types";
import { BranchSelector, Level } from "@scm-manager/ui-components";
import CodeViewSwitcher from "../components/CodeViewSwitcher";
import { compose } from "redux";
@@ -34,7 +32,7 @@ type Props = RouteComponentProps &
fetchBranches: (p: Repository) => void;
};
const CodeSectionActionBar = styled.div.attrs(() => ({}))`
const CodeActionBar = styled.div.attrs(() => ({}))`
background-color: whitesmoke;
border: 1px solid #dbdbdb;
border-radius: 4px;
@@ -46,10 +44,17 @@ const CodeSectionActionBar = styled.div.attrs(() => ({}))`
margin-bottom: 1em;
`;
class CodeSectionOverview extends React.Component<Props> {
class CodeOverview extends React.Component<Props> {
componentDidMount() {
const { repository } = this.props;
const { repository, branches } = this.props;
new Promise(() => {
this.props.fetchBranches(repository);
}).then(() => {
if (branches?.length > 0) {
const defaultBranch = branches.filter((branch: Branch) => branch.defaultBranch === true)[0];
this.branchSelected(defaultBranch);
}
});
}
findSelectedBranch = () => {
@@ -58,13 +63,11 @@ class CodeSectionOverview extends React.Component<Props> {
};
branchSelected = (branch?: Branch) => {
let url;
let splittedUrl = this.props.location.pathname.split("/");
if (branch) {
url = `${this.props.baseUrl}/${this.props.selectedView}/${encodeURIComponent(branch.name)}`;
} else {
url = `${this.props.baseUrl}/${this.props.selectedView}/`;
splittedUrl[6] = encodeURIComponent(branch.name);
}
this.props.history.push(url);
this.props.history.push(splittedUrl.join("/"));
};
render() {
@@ -73,24 +76,19 @@ class CodeSectionOverview extends React.Component<Props> {
return (
<div>
<CodeSectionActionBar>
<CodeActionBar>
<Level
left={
branches?.length > 0 && (
<BranchSelector
label={t("code.branchSelector")}
branches={branches}
selectedBranch={this.props.selectedBranch}
selected={(b: Branch) => {
this.branchSelected(b);
}}
onSelectBranch={this.branchSelected}
/>
)
}
right={<CodeViewSwitcher url={this.props.location.pathname} />}
/>
</CodeSectionActionBar>
<Route exact path={`${url}/changeset/:id`} render={() => <ChangesetView repository={repository} />} />
</CodeActionBar>
<Route
path={`${url}/sources`}
exact={true}
@@ -100,15 +98,6 @@ class CodeSectionOverview extends React.Component<Props> {
path={`${url}/sources/:revision/:path*`}
render={() => <Sources repository={repository} baseUrl={`${url}/sources`} />}
/>
<Route
path={`${url}/sourceext/:extension`}
exact={true}
render={() => <SourceExtensions repository={repository} />}
/>
<Route
path={`${url}/sourceext/:extension/:revision/:path*`}
render={() => <SourceExtensions repository={repository} />}
/>
<Route
path={`${url}/changesets`}
exact={true}
@@ -123,7 +112,7 @@ class CodeSectionOverview extends React.Component<Props> {
}
}
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchBranches: (repo: Repository) => {
dispatch(fetchBranches(repo));
@@ -152,4 +141,4 @@ export default compose(
withRouter,
withTranslation("repos"),
connect(mapStateToProps, mapDispatchToProps)
)(CodeSectionOverview);
)(CodeOverview);

View File

@@ -41,7 +41,6 @@ type Props = WithTranslation & {
class Changesets extends React.Component<Props> {
componentDidMount() {
const { fetchChangesets, repository, branch, page } = this.props;
fetchChangesets(repository, branch, page);
}

View File

@@ -1,59 +1,20 @@
import React from "react";
import { compose } from "redux";
import { connect } from "react-redux";
import { Route, withRouter } from "react-router-dom";
import { WithTranslation, withTranslation } from "react-i18next";
import { Branch, Repository } from "@scm-manager/ui-types";
import { BranchSelector, ErrorNotification, Loading } from "@scm-manager/ui-components";
import { Repository } from "@scm-manager/ui-types";
import Changesets from "./Changesets";
import {
fetchBranches,
getBranches,
getFetchBranchesFailure,
isFetchBranchesPending
} from "../branches/modules/branches";
type Props = WithTranslation & {
repository: Repository;
selected: string;
selectedBranch: string;
baseUrl: string;
// State props
branches: Branch[];
loading: boolean;
error: Error;
// Dispatch props
fetchBranches: (p: Repository) => void;
// Context props
history: any; // TODO flow type
match: any;
};
class ChangesetsRoot extends React.Component<Props> {
componentDidMount() {
this.props.fetchBranches(this.props.repository);
this.redirectToDefaultBranch();
}
redirectToDefaultBranch = () => {
if (this.shouldRedirectToDefaultBranch()) {
const defaultBranches = this.props.branches.filter(b => b.defaultBranch === true);
if (defaultBranches.length > 0) {
this.branchSelected(defaultBranches[0]);
}
}
};
shouldRedirectToDefaultBranch = () => {
return (
this.props.branches &&
this.props.branches.length > 0 &&
this.props.branches.filter(b => b.name === this.props.selected).length === 0
);
};
stripEndingSlash = (url: string) => {
if (url.endsWith("/")) {
return url.substring(0, url.length - 1);
@@ -61,92 +22,24 @@ class ChangesetsRoot extends React.Component<Props> {
return url;
};
branchSelected = (branch?: Branch) => {
let url;
if (branch) {
url = `${this.props.baseUrl}/${encodeURIComponent(branch.name)}`;
} else {
url = `${this.props.baseUrl}/`;
}
this.props.history.push(url);
};
findSelectedBranch = () => {
const { selected, branches } = this.props;
return branches.find((branch: Branch) => branch.name === selected);
};
render() {
const { repository, error, loading, match, branches } = this.props;
if (error) {
return <ErrorNotification error={error} />;
}
if (loading) {
return <Loading />;
}
const { repository, match, selectedBranch } = this.props;
if (!repository) {
return null;
}
const url = this.stripEndingSlash(match.url);
const branch = branches ? this.findSelectedBranch() : null;
const changesets = <Changesets repository={repository} branch={branch} />;
return (
<div className="panel">
<Route path={`${url}/:page?`} component={() => changesets} />
</div>
);
}
renderBranchSelector = () => {
const { repository, branches, selected, t } = this.props;
if (repository._links.branches) {
return (
<div className="panel-heading">
<BranchSelector
label={t("changesets.branchSelectorLabel")}
branches={branches}
selectedBranch={selected}
selected={(b: Branch) => {
this.branchSelected(b);
}}
<Route
path={`${url}/:page?`}
component={() => <Changesets repository={repository} branch={selectedBranch} />}
/>
</div>
);
}
return null;
};
}
const mapDispatchToProps = (dispatch: any) => {
return {
fetchBranches: (repo: Repository) => {
dispatch(fetchBranches(repo));
}
};
};
const mapStateToProps = (state: any, ownProps: Props) => {
const { repository, match } = ownProps;
const loading = isFetchBranchesPending(state, repository);
const error = getFetchBranchesFailure(state, repository);
const branches = getBranches(state, repository);
const selected = decodeURIComponent(match.params.branch);
return {
loading,
error,
branches,
selected
};
};
export default compose(
withRouter,
withTranslation("repos"),
connect(mapStateToProps, mapDispatchToProps)
)(ChangesetsRoot);
export default withRouter(withTranslation("repos")(ChangesetsRoot));

View File

@@ -17,7 +17,9 @@ import BranchRoot from "../branches/containers/BranchRoot";
import PermissionsNavLink from "../components/PermissionsNavLink";
import RepositoryNavLink from "../components/RepositoryNavLink";
import { getLinks, getRepositoriesLink } from "../../modules/indexResource";
import CodeSectionOverview from "../codeSection/containers/CodeSectionOverview";
import CodeOverview from "../codeSection/containers/CodeOverview";
import ChangesetView from "./ChangesetView";
import SourceExtensions from "../sources/containers/SourceExtensions";
type Props = WithTranslation & {
namespace: string;
@@ -128,9 +130,23 @@ class RepositoryRoot extends React.Component<Props> {
<Permissions namespace={this.props.repository.namespace} repoName={this.props.repository.name} />
)}
/>
<Route
exact
path={`${url}/code/changeset/:id`}
render={() => <ChangesetView repository={repository} />}
/>
<Route
path={`${url}/code/sourceext/:extension`}
exact={true}
render={() => <SourceExtensions repository={repository} />}
/>
<Route
path={`${url}/code/sourceext/:extension/:revision/:path*`}
render={() => <SourceExtensions repository={repository} />}
/>
<Route
path={`${url}/code`}
render={() => <CodeSectionOverview baseUrl={`${url}/code`} repository={repository} />}
render={() => <CodeOverview baseUrl={`${url}/code`} repository={repository} />}
/>
<Route
path={`${url}/branch/:branch`}
@@ -187,7 +203,7 @@ class RepositoryRoot extends React.Component<Props> {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { namespace, name } = ownProps.match.params;
const repository = getRepository(state, namespace, name);
const loading = isFetchRepoPending(state, namespace, name);
@@ -205,7 +221,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchRepoByName: (link: string, namespace: string, name: string) => {
dispatch(fetchRepoByName(link, namespace, name));

View File

@@ -24,7 +24,7 @@ type Props = WithTranslation &
sources?: File | null;
// dispatch props
fetchSources: (repository: Repository, revision: string, path: string) => void;
fetchSources: (repository: Repository, revision: string | undefined, path: string | undefined) => void;
};
const extensionPointName = "repos.sources.extensions";
@@ -33,7 +33,7 @@ class SourceExtensions extends React.Component<Props> {
componentDidMount() {
const { fetchSources, repository, revision, path } = this.props;
// TODO get typing right
fetchSources(repository, revision || "", path || "");
fetchSources(repository, revision, path);
}
render() {

View File

@@ -1,9 +1,9 @@
import React from "react";
import { connect } from "react-redux";
import { connect, Dispatch, DispatchProp, MapDispatchToProps } from "react-redux";
import { withRouter } from "react-router-dom";
import { WithTranslation, withTranslation } from "react-i18next";
import { Branch, Repository } from "@scm-manager/ui-types";
import { BranchSelector, Breadcrumb, ErrorNotification, Loading } from "@scm-manager/ui-components";
import { Breadcrumb, ErrorNotification, Loading } from "@scm-manager/ui-components";
import FileTree from "../components/FileTree";
import {
fetchBranches,
@@ -58,7 +58,7 @@ class Sources extends React.Component<Props, State> {
this.redirectToDefaultBranch();
}
componentDidUpdate(prevProps) {
componentDidUpdate(prevProps: Props) {
const { fetchSources, repository, revision, path } = this.props;
if (prevProps.revision !== revision || prevProps.path !== path) {
fetchSources(repository, this.decodeRevision(revision), path);
@@ -147,7 +147,7 @@ class Sources extends React.Component<Props, State> {
};
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: Props) => {
const { repository, match } = ownProps;
const { revision, path } = match.params;
const decodedRevision = revision ? decodeURIComponent(revision) : undefined;
@@ -171,7 +171,7 @@ const mapStateToProps = (state, ownProps) => {
};
};
const mapDispatchToProps = dispatch => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchBranches: (repository: Repository) => {
dispatch(fetchBranches(repository));

View File

@@ -84,7 +84,7 @@ export function fetchSourcesFailure(repository: Repository, revision: string, pa
};
}
function createItemId(repository: Repository, revision: string, path: string) {
function createItemId(repository: Repository, revision: string | undefined, path: string) {
const revPart = revision ? revision : "_";
const pathPart = path ? path : "";
return `${repository.namespace}/${repository.name}/${decodeURIComponent(revPart)}/${pathPart}`;
@@ -121,7 +121,7 @@ export function isDirectory(state: any, repository: Repository, revision: string
export function getSources(
state: any,
repository: Repository,
revision: string,
revision: string | undefined,
path: string
): File | null | undefined {
if (state.sources) {