diff --git a/scm-plugins/scm-git-plugin/src/main/js/RepositoryConfig.tsx b/scm-plugins/scm-git-plugin/src/main/js/RepositoryConfig.tsx index a23fc5040a..7d30bb58b4 100644 --- a/scm-plugins/scm-git-plugin/src/main/js/RepositoryConfig.tsx +++ b/scm-plugins/scm-git-plugin/src/main/js/RepositoryConfig.tsx @@ -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 { loadingDefaultBranch: true, submitPending: false, branches: [], + selectedBranchName: "", defaultBranchChanged: false, disabled: true }; @@ -87,16 +96,16 @@ class RepositoryConfig extends React.Component { if (!branch) { this.setState({ ...this.state, - selectedBranchName: undefined, + selectedBranchName: "", + defaultBranchChanged: false + }); + } else { + this.setState({ + ...this.state, + selectedBranchName: branch.name, defaultBranchChanged: false }); - return; } - this.setState({ - ...this.state, - selectedBranchName: branch.name, - defaultBranchChanged: false - }); }; submit = (event: FormEvent) => { @@ -164,7 +173,7 @@ class RepositoryConfig extends React.Component { diff --git a/scm-ui/ui-components/src/BranchSelector.tsx b/scm-ui/ui-components/src/BranchSelector.tsx index 95cb95189e..2e4972e592 100644 --- a/scm-ui/ui-components/src/BranchSelector.tsx +++ b/scm-ui/ui-components/src/BranchSelector.tsx @@ -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,66 +25,31 @@ const NoBottomMarginField = styled.div` margin-bottom: 0 !important; `; -export default class BranchSelector extends React.Component { - 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; - - if (branches) { - return ( -
- - - -
- - - b.name)} - optionSelected={this.branchSelected} - disabled={!!disabled} - preselectedOption={this.state.selectedBranch ? this.state.selectedBranch.name : ""} - /> - - -
+const BranchSelector: FC = ({ branches, onSelectBranch, selectedBranch, label, disabled }) => { + if (branches) { + return ( +
+ + + +
+ + + b.name)} + optionSelected={branch => onSelectBranch(branches.filter(b => b.name === branch)[0])} + disabled={!!disabled} + preselectedOption={selectedBranch && selectedBranch} + /> + +
- ); - } else { - return null; - } +
+ ); + } 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; diff --git a/scm-ui/ui-components/src/repos/changesets/changesets.ts b/scm-ui/ui-components/src/repos/changesets/changesets.ts index 1ffc2b5db6..c095e30e27 100644 --- a/scm-ui/ui-components/src/repos/changesets/changesets.ts +++ b/scm-ui/ui-components/src/repos/changesets/changesets.ts @@ -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) { diff --git a/scm-ui/ui-webapp/src/repos/branches/containers/BranchRoot.tsx b/scm-ui/ui-webapp/src/repos/branches/containers/BranchRoot.tsx index efc3ae1a50..34ada822b6 100644 --- a/scm-ui/ui-webapp/src/repos/branches/containers/BranchRoot.tsx +++ b/scm-ui/ui-webapp/src/repos/branches/containers/BranchRoot.tsx @@ -73,7 +73,7 @@ class BranchRoot extends React.Component { } } -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)); diff --git a/scm-ui/ui-webapp/src/repos/branches/containers/CreateBranch.tsx b/scm-ui/ui-webapp/src/repos/branches/containers/CreateBranch.tsx index 36fe6746e3..a5948c1d36 100644 --- a/scm-ui/ui-webapp/src/repos/branches/containers/CreateBranch.tsx +++ b/scm-ui/ui-webapp/src/repos/branches/containers/CreateBranch.tsx @@ -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 { } } -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); diff --git a/scm-ui/ui-webapp/src/repos/codeSection/components/CodeViewSwitcher.tsx b/scm-ui/ui-webapp/src/repos/codeSection/components/CodeViewSwitcher.tsx index d7fa275dd7..69e94e3024 100644 --- a/scm-ui/ui-webapp/src/repos/codeSection/components/CodeViewSwitcher.tsx +++ b/scm-ui/ui-webapp/src/repos/codeSection/components/CodeViewSwitcher.tsx @@ -17,19 +17,25 @@ type Props = { const CodeViewSwitcher: FC = ({ url }) => { const [t] = useTranslation("repos"); + const createDestinationUrl = (destination: string) => { + let splittedUrl = url.split("/"); + splittedUrl[5] = destination; + return splittedUrl.join("/") + }; + return ( ); diff --git a/scm-ui/ui-webapp/src/repos/codeSection/containers/CodeSectionOverview.tsx b/scm-ui/ui-webapp/src/repos/codeSection/containers/CodeOverview.tsx similarity index 66% rename from scm-ui/ui-webapp/src/repos/codeSection/containers/CodeSectionOverview.tsx rename to scm-ui/ui-webapp/src/repos/codeSection/containers/CodeOverview.tsx index 3d8b69cfb5..9dbd517175 100644 --- a/scm-ui/ui-webapp/src/repos/codeSection/containers/CodeSectionOverview.tsx +++ b/scm-ui/ui-webapp/src/repos/codeSection/containers/CodeOverview.tsx @@ -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 { +class CodeOverview extends React.Component { componentDidMount() { - const { repository } = this.props; - this.props.fetchBranches(repository); + 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 { }; 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 { return (
- + 0 && ( - { - this.branchSelected(b); - }} - /> - ) + } right={} /> - - } /> + { path={`${url}/sources/:revision/:path*`} render={() => } /> - } - /> - } - /> { } } -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); diff --git a/scm-ui/ui-webapp/src/repos/containers/Changesets.tsx b/scm-ui/ui-webapp/src/repos/containers/Changesets.tsx index 3b7b85d1b5..9bce6006e5 100644 --- a/scm-ui/ui-webapp/src/repos/containers/Changesets.tsx +++ b/scm-ui/ui-webapp/src/repos/containers/Changesets.tsx @@ -41,7 +41,6 @@ type Props = WithTranslation & { class Changesets extends React.Component { componentDidMount() { const { fetchChangesets, repository, branch, page } = this.props; - fetchChangesets(repository, branch, page); } diff --git a/scm-ui/ui-webapp/src/repos/containers/ChangesetsRoot.tsx b/scm-ui/ui-webapp/src/repos/containers/ChangesetsRoot.tsx index 4eaeaf26eb..13129af208 100644 --- a/scm-ui/ui-webapp/src/repos/containers/ChangesetsRoot.tsx +++ b/scm-ui/ui-webapp/src/repos/containers/ChangesetsRoot.tsx @@ -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 { - 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 { 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 ; - } - - if (loading) { - return ; - } + const { repository, match, selectedBranch } = this.props; if (!repository) { return null; } const url = this.stripEndingSlash(match.url); - const branch = branches ? this.findSelectedBranch() : null; - const changesets = ; return (
- changesets} /> + } + />
); } - - renderBranchSelector = () => { - const { repository, branches, selected, t } = this.props; - if (repository._links.branches) { - return ( -
- { - this.branchSelected(b); - }} - /> -
- ); - } - 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)); diff --git a/scm-ui/ui-webapp/src/repos/containers/RepositoryRoot.tsx b/scm-ui/ui-webapp/src/repos/containers/RepositoryRoot.tsx index a0a8ad8b95..56b705881c 100644 --- a/scm-ui/ui-webapp/src/repos/containers/RepositoryRoot.tsx +++ b/scm-ui/ui-webapp/src/repos/containers/RepositoryRoot.tsx @@ -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 { )} /> + } + /> + } + /> + } + /> } + render={() => } /> { } } -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)); diff --git a/scm-ui/ui-webapp/src/repos/sources/containers/SourceExtensions.tsx b/scm-ui/ui-webapp/src/repos/sources/containers/SourceExtensions.tsx index 2ea57a65ba..613bf51828 100644 --- a/scm-ui/ui-webapp/src/repos/sources/containers/SourceExtensions.tsx +++ b/scm-ui/ui-webapp/src/repos/sources/containers/SourceExtensions.tsx @@ -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 { componentDidMount() { const { fetchSources, repository, revision, path } = this.props; // TODO get typing right - fetchSources(repository, revision || "", path || ""); + fetchSources(repository, revision, path); } render() { diff --git a/scm-ui/ui-webapp/src/repos/sources/containers/Sources.tsx b/scm-ui/ui-webapp/src/repos/sources/containers/Sources.tsx index 8b75cbe903..83f68ea2f6 100644 --- a/scm-ui/ui-webapp/src/repos/sources/containers/Sources.tsx +++ b/scm-ui/ui-webapp/src/repos/sources/containers/Sources.tsx @@ -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 { 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 { }; } -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)); diff --git a/scm-ui/ui-webapp/src/repos/sources/modules/sources.ts b/scm-ui/ui-webapp/src/repos/sources/modules/sources.ts index 7387c3d57f..ae51a1c55e 100644 --- a/scm-ui/ui-webapp/src/repos/sources/modules/sources.ts +++ b/scm-ui/ui-webapp/src/repos/sources/modules/sources.ts @@ -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) {