mirror of
				https://github.com/scm-manager/scm-manager.git
				synced 2025-10-31 18:46:07 +01:00 
			
		
		
		
	Introduced dumb BranchSelector; moved fetching of branches to BranchRoot
This commit is contained in:
		| @@ -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); | ||||
|   }; | ||||
| } | ||||
|   | ||||
| @@ -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)); | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
							
								
								
									
										46
									
								
								scm-ui/src/repos/containers/BranchSelector.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								scm-ui/src/repos/containers/BranchSelector.js
									
									
									
									
									
										Normal 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; | ||||
| @@ -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 ( | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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}`; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user