Merge pull request '合并请求路由改造' (#147) from yuzhantian/forgeplus-react:feature_pull_routers into feature_router_v2

This commit is contained in:
baladiwei 2021-10-12 16:39:12 +08:00
commit 279d358be9
16 changed files with 745 additions and 203 deletions

View File

@ -97,10 +97,10 @@ const ProjectIndex = Loadable({
loading: Loading, loading: Loading,
}); });
const CreateMerge = Loadable({ // const CreateMerge = Loadable({
loader: () => import('./forge/Merge/NewMerge'), // loader: () => import('./forge/Merge/NewMerge'),
loading: Loading, // loading: Loading,
}) // })
// 此处仅维护前端可能的一级路由,不用进行项目或者组织判断的字段。 // 此处仅维护前端可能的一级路由,不用进行项目或者组织判断的字段。
const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize"]; const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize"];
@ -279,7 +279,7 @@ class App extends Component {
} /> } />
{/* 项目PR */} {/* 项目PR */}
<Route path="/:owner/:projectsId/pulls/new" <Route path="/:owner/:projectsId/compare"
render={ render={
(props) => (<ProjectDetail {...this.props} {...props} {...this.state} />) (props) => (<ProjectDetail {...this.props} {...props} {...this.state} />)
} }

View File

@ -27,7 +27,7 @@ class ActivityItem extends Component {
: :
// 如果是合并请求 // 如果是合并请求
<p className="itemLine"> <p className="itemLine">
<Link to={`/${owner}/${projectsId}/pulls/${item.trend_id}/Messagecount`} className="color-blue font-16">{item.name}</Link> <Link to={`/${owner}/${projectsId}/pulls/${item.trend_id}`} className="color-blue font-16">{item.name}</Link>
<span className="activity_type">{item.trend_type}</span> <span className="activity_type">{item.trend_type}</span>
</p > </p >
} }

View File

@ -426,7 +426,7 @@ function CoderDepot(props){
<div className="addOptionBtn"> <div className="addOptionBtn">
{ {
baseOperate && baseOperate &&
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/pulls/new/${branchName || defaultBranch}`)} >+ 合并请求</CheckProfile> <CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/compare/${branchName || defaultBranch}`)} >+ 合并请求</CheckProfile>
} }
{ {
baseOper && baseOper &&

View File

@ -70,7 +70,7 @@ const MergeIndexDetail = Loadable({
}) })
const CreateMerge = Loadable({ const CreateMerge = Loadable({
loader: () => import('../Merge/NewMerge'), loader: () => import('../Merge/CreateMerge'),
loading: Loading, loading: Loading,
}) })
@ -150,7 +150,9 @@ function checkPathname(projectsId, owner, pathname) {
name = "about" name = "about"
} else if (url.indexOf("/issues") > -1 || url.indexOf("Milepost") > 0) { } else if (url.indexOf("/issues") > -1 || url.indexOf("Milepost") > 0) {
name = "issues"; name = "issues";
} else if (url.indexOf("/pulls") > -1) { } else if (url.indexOf("/pulls") > -1 || url.indexOf("/compare") > -1) {
// /pulls合并请求除新建合并请求外
// /compare新建合并请求
name = "pulls" name = "pulls"
} else if (url.indexOf("/milestones") > -1) { } else if (url.indexOf("/milestones") > -1) {
name = "milestones" name = "milestones"
@ -713,22 +715,32 @@ class Detail extends Component {
} }
></Route> ></Route>
{/* 新建合并请求 */} {/* 新建合并请求 */}
<Route path="/:owner/:projectsId/pulls/new/:branch" {/* <Route path="/:owner/:projectsId/compare/:branch"
render={
(props) => (<CreateMerge {...this.props} {...props} {...this.state} {...common} is_fork={true} />)
}
></Route> */}
<Route path="/:owner/:projectsId/compare"
render={ render={
(props) => (<CreateMerge {...this.props} {...props} {...this.state} {...common} is_fork={true} />) (props) => (<CreateMerge {...this.props} {...props} {...this.state} {...common} is_fork={true} />)
} }
></Route> ></Route>
<Route path="/:owner/:projectsId/pulls/new" <Route path="/:owner/:projectsId/pulls/:mergeId/updatemerge"
render={
(props) => (<CreateMerge {...this.props} {...props} {...this.state} {...common} is_fork={true} />)
}
></Route>
<Route path="/:owner/:projectsId/pulls/:mergeId/UpdateMerge"
render={ render={
(props) => (<UpdateMerge {...this.props} {...props} {...this.state} {...common} />) (props) => (<UpdateMerge {...this.props} {...props} {...this.state} {...common} />)
} }
></Route> ></Route>
<Route path="/:owner/:projectsId/pulls/:mergeId/Messagecount" <Route path="/:owner/:projectsId/pulls/:mergeId"
render={
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
<Route path="/:owner/:projectsId/pulls/:mergeId/commits"
render={
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
<Route path="/:owner/:projectsId/pulls/:mergeId/files"
render={ render={
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />) (props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
} }

View File

@ -91,7 +91,7 @@ function Index(props) {
<div className="treeabout"> <div className="treeabout">
{ {
(isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) && (isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) &&
<Link to={`/${owner}/${projectsId}/pulls/new/${i.name}`} className="btn-83">+ 合并请求</Link> <Link to={`/${owner}/${projectsId}/compare/${i.name}`} className="btn-83">+ 合并请求</Link>
} }
<Dropdown overlay={menu(i.zip_url,i.tar_url)} trigger={['click']} placement="bottomRight"> <Dropdown overlay={menu(i.zip_url,i.tar_url)} trigger={['click']} placement="bottomRight">
<a className="btn-83 ml15">下载<i className="iconfont icon-sanjiaoxing-down font-14"></i></a> <a className="btn-83 ml15">下载<i className="iconfont icon-sanjiaoxing-down font-14"></i></a>

View File

@ -0,0 +1,413 @@
import React, { Component } from 'react';
import { Input, Select, Spin, Alert } from 'antd';
import axios from 'axios';
import MergeForm from './merge_form';
import MergeFooter from './merge_footer';
import '../Order/order.css';
import './merge.css';
/**
* 根据url获取目标仓库目标分支源仓库源分支
* 路由规则owner/projectId/compare/merge...pullowner:pullBranch
* 可能存在的情况
* 1代码库首页跳转仓库相同目标分支为默认分支owner/projectId/compare/pullBranch
* 2代码库分支列表仓库相同目标分支为默认分支owner/projectId/compare/pullBranch
* 3合并请求列表页新建无数据时的提示仓库相同目标都为默认分支owner/projectId/compare
* 4新建页面切换分支切换目标仓库刷新页面等存在所有可能情况
*/
function getBranchParams(pathname) {
const result = {
// 目标仓库所有者
mergeOwner: undefined,
// 目标分支
mergeBranch: 'master',
// 源仓库所有者
pullOwner: undefined,
// 源分支
pullBranch: 'master',
// 仓库名称
projectId: undefined,
};
// 去掉第一个字符/
const _pathname = pathname.slice(1);
const [ownerProject, branchUrl] = _pathname.split('/compare');
const [mergeOwner, projectId] = ownerProject.split('/');
// 同仓库时
result.mergeOwner = mergeOwner;
result.pullOwner = mergeOwner;
result.projectId = projectId;
if (branchUrl) {
// 如果存在具体的分支
const _branchUrl = branchUrl.slice(1);
if (_branchUrl.indexOf('...') > -1) {
// 存在源分支与目标分支
const [mergeBranch, pullObj] = _branchUrl.split('...');
result.mergeBranch = mergeBranch;
if (pullObj.indexOf(':') > -1) {
// 存在源仓库
const [pullOwner, pullBranch] = pullObj.split(':');
result.pullOwner = pullOwner;
result.pullBranch = pullBranch;
} else {
result.pullBranch = pullObj;
}
} else {
result.pullBranch = _branchUrl;
}
}
return result;
}
const Option = Select.Option;
class CreateMerge extends Component {
constructor(props) {
super(props);
const { pullBranch, mergeBranch } = getBranchParams(
this.props.location.pathname
);
this.state = {
data: undefined,
pullBranches: undefined,
mergeBranches: undefined,
mergeProjects: undefined,
merge: mergeBranch || 'master',
pull: pullBranch || 'master',
id: undefined,
// isFork: false,
projects_names: undefined,
isSpin: true,
showMessage: false,
merge_head: false, // 是否向fork后的源项目发起合并请求
defaultMessage: '必须选择不同的分支',
project_id: undefined, // 当前项目的id也即开始发送合并请求的源项目id
merge_project_user: undefined,
comparesData: undefined, //提交和文件的内容保存compare接口返回的数据
// 比较分支时的加载效果
isCompareSpin: true,
// 是否是初次加载用这个字段来控制提示组件和文件组件的显示、隐藏比直接用isCompareSpin交互友好些
isFirstLoading: true,
};
}
componentDidMount = () => {
// 初始化时根据url获取目标仓库、分支源仓库、分支
// 再获取对应的仓库列表、分支列表
// 再调用比较接口
const branchParams = getBranchParams(this.props.location.pathname);
console.log('componentDidMount branchParams', branchParams);
this.getMergeInfo(branchParams);
};
componentDidUpdate = (preProps) => {
// url变化触发时切换源分支、切换目标仓库、切换目标分支回退
const oldPathname = preProps.location.pathname;
const newPathname = this.props.location.pathname;
if (oldPathname !== newPathname) {
const branchParams = getBranchParams(newPathname);
console.log('componentDidUpdate branchParams', branchParams);
this.getMergeInfo(branchParams);
}
};
//获取新建合并请求数据
getMergeInfo = (branchParams) => {
this.setState({ isSpin: true });
const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId } =
branchParams;
const url = `/${pullOwner}/${projectId}/pulls/new.json`;
axios
.get(url)
.then((result) => {
if (result) {
this.setState({
// isFork: result.data.is_fork,
projects_names: result.data.projects_names,
mergeProjects: result.data.merge_projects,
pullBranches: result.data.branches,
mergeBranches: result.data.branches,
project_id: result.data.project_id,
id: result.data.id,
merge: mergeBranch,
pull: pullBranch,
});
}
if (pullOwner !== mergeOwner) {
this.getBranchList(mergeOwner, projectId);
}
this.compareProject(result.data.id, branchParams);
this.setState({ isSpin: false });
})
.catch((error) => {
this.setState({ isSpin: false });
console.log(error);
});
};
// compare接口获取分支对比信息
compareProject = (baseid, branchParams) => {
// const { project } = this.props;
// const { owner, projectsId } = this.props.match.params;
const projectObj = this.props.project;
const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId } =
branchParams;
let url = `/${mergeOwner}/${projectId}/compare`;
if (projectObj) {
if (baseid === projectObj.id) {
url += `/${pullBranch}...${mergeBranch}.json`;
} else {
url += `/${mergeBranch}...${pullOwner}/${projectId}:${pullBranch}.json`;
}
this.setState({ isSpin: false, isCompareSpin: true });
axios
.get(url)
.then((result) => {
if (result) {
if (result.data.status === 0) {
this.setState({
showMessage: false,
});
} else {
this.setState({
showMessage: true,
defaultMessage: result.data.message,
});
}
this.setState({
comparesData: result.data,
});
}
this.setState({
isFirstLoading: false,
isSpin: false,
isCompareSpin: false,
});
})
.catch((error) => {
this.setState({ isSpin: false, isCompareSpin: false });
});
}
};
// 根据所有者、仓库名,获取分支列表,目前仅涉及目标仓库分支查询
getBranchList = (login, projectId) => {
this.setState({ isSpin: true });
const url = `/${login}/${projectId}/pulls/get_branches.json`;
axios
.get(url)
.then((result) => {
if (result) {
this.setState({
mergeBranches: result.data,
});
}
this.setState({ isSpin: false });
})
.catch((error) => {
this.setState({ isSpin: false });
console.log(error);
});
};
// 切换分支事件
selectBrach = (type, value) => {
const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId } =
getBranchParams(this.props.location.pathname);
let _url = `/${mergeOwner}/${projectId}/compare/`;
// type为pull时pullBranch取value否则取原有值
// type为pull时mergeBranch取原有值否则取value
let _pullBranch = type === 'pull' ? value : pullBranch;
let _mergeBranch = type === 'pull' ? mergeBranch : value;
if (pullOwner === mergeOwner) {
// 如果仓库相同, compare/目标分支...源分支
_url += `${_mergeBranch}...${_pullBranch}`;
} else {
// 如果仓库不同, compare/目标分支...源分支
_url += `${_mergeBranch}...${pullOwner}:${_pullBranch}`;
}
this.props.history.push(_url);
};
// 切换仓库响应事件,目前仅目标分支可切换仓库
selectProjectName = (value) => {
const { projects_names, id } = this.state;
const { pullOwner, pullBranch } = getBranchParams(
this.props.location.pathname
);
let arr =
projects_names && projects_names.filter((item) => item.id === value);
let identifier = arr && arr[0].project_id;
let login = arr && arr[0].project_user_login;
// 目标仓库与源仓库不是一个仓库
let is_fork = parseInt(value, 10) !== parseInt(id, 10);
this.setState({
isSpin: true,
// merge_head: is_fork,
data: {
is_original: is_fork,
fork_project_id: is_fork ? id : '',
merge_user_login: is_fork
? projects_names[0].project_user_login
: undefined,
},
});
if (login === pullOwner) {
// 如果切换后, 仓库与源仓库一致了
this.props.history.push(
`/${login}/${identifier}/compare/master...${pullBranch}`
);
} else {
this.props.history.push(
`/${login}/${identifier}/compare/master...${pullOwner}:${pullBranch}`
);
}
// this.newMergelist(login, identifier);
};
// 渲染分支列表
renderBrances = (list) => {
if (list && list.length > 0) {
return list.map((item, key) => {
return (
<Option key={key + 1} value={item.name}>
{item.name}
</Option>
);
});
}
};
// 渲染项目列表
renderProjectNames = (list) => {
if (list && list.length > 0) {
return list.map((item, key) => {
return (
<Option key={key + 1} value={item.id}>
{item.project_name}
</Option>
);
});
}
};
// 渲染html内容
withHtml = (html) => {
return <div dangerouslySetInnerHTML={{ __html: html }}></div>;
};
render() {
const {
data,
pullBranches,
mergeBranches,
mergeProjects,
pull,
merge,
isSpin,
isCompareSpin,
isFirstLoading,
showMessage,
defaultMessage,
projects_names,
id,
comparesData,
} = this.state;
let { project } = this.props;
return (
<div>
<Spin spinning={isSpin}>
<div className="main">
<div className="merge-header width100 inline-block">
<div className="width40 pull-left">
<div className="color-grey-3 mb10 fwb">源分支:</div>
<Input.Group compact className="display-flex">
<Select
value={id}
className="hide-1 task-hide flex1"
disabled
>
{this.renderProjectNames(projects_names)}
</Select>
<Select
value={pull}
onSelect={(e) => this.selectBrach('pull', e)}
showSearch
className="merge-flex1 flex1"
>
{this.renderBrances(pullBranches)}
</Select>
</Input.Group>
</div>
<div className="width10 pull-left text-center mt25">
<i
className={'iconfont icon-youjiang color-grey-c font-32'}
></i>
</div>
<div className="width40 pull-left">
<div>
<div className="color-grey-3 mb10 fwb">目标分支:</div>
<Input.Group compact className="display-flex">
<Select
value={project && project.id}
className="hide-1 task-hide flex1"
onSelect={(e) => this.selectProjectName(e)}
>
{this.renderProjectNames(mergeProjects)}
</Select>
<Select
value={merge}
onSelect={(e) => this.selectBrach('merge', e)}
showSearch
className="merge-flex1 flex1"
>
{this.renderBrances(mergeBranches)}
</Select>
</Input.Group>
</div>
</div>
</div>
{/* 非加载状态且有提示 */}
{!isCompareSpin && showMessage && (
<div className="mb20">
<Alert
description={this.withHtml(defaultMessage)}
type="error"
/>
</div>
)}
{/* 非加载状态且可以提交 */}
{!isCompareSpin && !showMessage && (
<MergeForm
{...this.props}
merge_type="new"
data={data}
merge={merge}
pull={pull}
files_count={
comparesData &&
comparesData.diff &&
comparesData.diff.files_count
}
commits_count={comparesData && comparesData.commits_count}
></MergeForm>
)}
</div>
{!isFirstLoading && (
<MergeFooter
{...this.props}
merge={merge}
pull={pull}
comparesData={comparesData}
></MergeFooter>
)}
</Spin>
</div>
);
}
}
export default CreateMerge;

View File

@ -62,7 +62,7 @@ class MergeItem extends Component {
<p className="mb15 df" style={{ alignItems: "center" }}> <p className="mb15 df" style={{ alignItems: "center" }}>
<i className={`iconfont icon-hebingqingqiu1 font-14 mr3 i_${status}`}></i> <i className={`iconfont icon-hebingqingqiu1 font-14 mr3 i_${status}`}></i>
<Link <Link
to={`/${owner}/${projectsId}/pulls/${item.pull_request_id}/Messagecount`} to={`/${owner}/${projectsId}/pulls/${item.pull_request_id}`}
className="hide-1 font-15 color-grey-3 fwb lineh-30 mr10" className="hide-1 font-15 color-grey-3 fwb lineh-30 mr10"
style={{ maxWidth: "300px" }} style={{ maxWidth: "300px" }}
> >
@ -175,7 +175,7 @@ class MergeItem extends Component {
{item.journals_count ? ( {item.journals_count ? (
<Link <Link
className="mr5 color-grey-8" className="mr5 color-grey-8"
to={`/${owner}/${projectsId}/pulls/${item.pull_request_id}/Messagecount`} to={`/${owner}/${projectsId}/pulls/${item.pull_request_id}`}
> >
<i className="iconfont icon-huifu1 font-15 mr5 ver-middle"></i> <i className="iconfont icon-huifu1 font-15 mr5 ver-middle"></i>
{item.journals_count} {item.journals_count}

View File

@ -0,0 +1,192 @@
import React, { Component } from 'react';
import { Tabs, Spin } from 'antd';
import { Link } from 'react-router-dom';
import axios from 'axios';
import Commits from './Commits';
import Comments from '../comments/comments';
import Files from './Files';
import '../Order/order.css';
import './merge.css';
const { TabPane } = Tabs;
class MergeFooter extends Component {
constructor(props) {
super(props);
this.state = {
commitsData: undefined,
filesData: undefined,
isSpin: false,
activeKey: '1',
commitCount: 0,
filesCount: 0,
//
commentsTotalCount: 0,
};
}
componentDidMount() {
this.Init();
}
componentDidUpdate(prevProps) {
// tab退taburltab
const newPathname = this.props.location.pathname;
const prevPathname = prevProps.location.pathname;
if (newPathname !== prevPathname) {
this.Init();
}
}
Init = () => {
const { data, location, match } = this.props;
const { pathname } = location;
const { projectsId, owner, mergeId } = match.params;
let activeKey = '1';
if (pathname.indexOf('commits') > -1) {
activeKey = '2';
this.getCommit(owner, projectsId, mergeId);
} else if (pathname.indexOf('files') > -1) {
activeKey = '3';
this.getFile(owner, projectsId, mergeId);
}
this.setState({
activeKey: activeKey,
commitCount: data && data.commits_count,
filesCount: data && data.files_count,
});
};
getCommit = (owner, projectsId, mergeId) => {
this.setState({ isSpin: true });
const url = `/${owner}/${projectsId}/pulls/${mergeId}/commits.json`;
axios
.get(url)
.then((result) => {
if (result) {
this.setState({
commitsData: result.data.commits,
commitCount: result.data.commits_count,
});
}
this.setState({ isSpin: false });
})
.catch((error) => {
this.setState({ isSpin: false });
});
};
getFile = (owner, projectsId, mergeId) => {
this.setState({ isSpin: true });
const url = `/${owner}/${projectsId}/pulls/${mergeId}/files.json`;
axios
.get(url)
.then((result) => {
if (result) {
this.setState({
filesData: result.data,
filesCount: result.data.files_count,
});
}
this.setState({ isSpin: false });
})
.catch((error) => {
this.setState({ isSpin: false });
});
};
render() {
const { projectsId, owner, mergeId } = this.props.match.params;
const { order_id, data = {} } = this.props;
const {
isSpin,
activeKey,
filesCount,
commitCount,
filesData,
commitsData,
} = this.state;
// Comment0
const commentsTotalCount = parseInt(
this.state.commentsTotalCount || data.comments_total_count || 0,
10
);
return (
<div className="main" style={{ paddingTop: '0px' }}>
<Spin spinning={isSpin}>
<Tabs
activeKey={activeKey}
className="custom-commit-tabs"
animated={false}
>
<TabPane
tab={
<Link to={`/${owner}/${projectsId}/pulls/${mergeId}`}>
<span className="font-16">评论</span>
{commentsTotalCount > 0 && (
<span className="tabNum">{commentsTotalCount}</span>
)}
</Link>
}
key="1"
>
<Comments
order_id={order_id}
showNotification={this.props.showNotification}
only_show_content={true}
updateCommentsNum={(commentsCount) => {
this.setState({ commentsTotalCount: commentsCount || 0 });
}}
{...this.props}
/>
</TabPane>
<TabPane
tab={
<Link to={`/${owner}/${projectsId}/pulls/${mergeId}/commits`}>
<span className="font-16">提交</span>
{commitCount > 0 && (
<span className="tabNum">{commitCount}</span>
)}
</Link>
}
key="2"
>
{commitsData && (
<Commits
{...this.props}
commits={commitsData}
projectsId={projectsId}
owner={owner}
></Commits>
)}
</TabPane>
<TabPane
tab={
<Link to={`/${owner}/${projectsId}/pulls/${mergeId}/files`}>
<span className="font-16">文件</span>
{filesCount > 0 && (
<span className="tabNum">{filesCount}</span>
)}
</Link>
}
key="3"
>
<Files
{...this.props}
data={filesData}
projectsId={projectsId}
owner={owner}
/>
</TabPane>
</Tabs>
</Spin>
</div>
);
}
}
export default MergeFooter;

View File

@ -1,7 +1,6 @@
import React, { Component } from "react"; import React, { Component } from "react";
import { Tabs } from 'antd'; import { Tabs } from 'antd';
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { AlignCenter } from '../Component/layout';
import axios from "axios"; import axios from "axios";
import { getImageUrl } from "educoder"; import { getImageUrl } from "educoder";
import { import {
@ -11,7 +10,6 @@ import {
Dropdown, Dropdown,
Icon, Icon,
Menu, Menu,
Select,
Tag, Tag,
Button, Button,
Alert, Alert,
@ -19,9 +17,8 @@ import {
import "./merge.css"; import "./merge.css";
import RenderHtml from "../../components/render-html"; import RenderHtml from "../../components/render-html";
import "../Order/order.css"; import "../Order/order.css";
import MergeFooter from "./merge_footer"; import MergeLinkFooter from "./MergeLinkFooter";
const Option = Select.Option;
const TextArea = Input.TextArea; const TextArea = Input.TextArea;
function turnbar(str){ function turnbar(str){
@ -283,13 +280,13 @@ class MessageCount extends Component {
conflict_files && conflict_files.length>0 && conflict_files && conflict_files.length>0 &&
<div> <div>
<p className="mt10 font-16 pt10" style={{borderTop:"1px solid #f9d7d5"}}>如下文件有代码冲突</p> <p className="mt10 font-16 pt10" style={{borderTop:"1px solid #f9d7d5"}}>如下文件有代码冲突</p>
<p> <div>
{ {
conflict_files.map((i,k)=>{ conflict_files.map((i,k)=>{
return <p>{i}</p> return <p key={k}>{i}</p>
}) })
} }
</p> </div>
</div> </div>
} }
</div> </div>
@ -448,7 +445,7 @@ class MessageCount extends Component {
type="green" type="green"
ghost ghost
className="ml20" className="ml20"
onClick={()=>{this.props.history.push(`/${owner}/${projectsId}/pulls/${mergeId}/UpdateMerge`);}} onClick={()=>{this.props.history.push(`/${owner}/${projectsId}/pulls/${mergeId}/updatemerge`);}}
> >
编辑 编辑
</Button> </Button>
@ -543,7 +540,7 @@ class MessageCount extends Component {
onChange={this.changbodypr} onChange={this.changbodypr}
/> />
</div> </div>
<p <div
className="clearfix mt15" className="clearfix mt15"
style={{ display: this.state.buttonshow }} style={{ display: this.state.buttonshow }}
> >
@ -558,19 +555,18 @@ class MessageCount extends Component {
取消 取消
</Button> </Button>
</Spin> </Spin>
</p> </div>
</div> </div>
</Spin> </Spin>
)} )}
</div> </div>
</div> </div>
<MergeFooter <MergeLinkFooter
footer_type={true}
order_id={data && data.issue.id} order_id={data && data.issue.id}
{...this.props} {...this.props}
{...this.state} {...this.state}
></MergeFooter> ></MergeLinkFooter>
</div> </div>
) : ( ) : (
"" ""

View File

@ -194,7 +194,7 @@ class NewMerge extends Component {
// this.ischeckmerge(); // this.ischeckmerge();
let { id ,merge , pull } = this.state; let { id ,merge , pull } = this.state;
if(type==="pull"){ if(type==="pull"){
this.props.history.push(`/${owner}/${projectsId}/pulls/new/${pull}`) this.props.history.push(`/${owner}/${projectsId}/compare/${pull}`)
this.compareProject(id,value,merge); this.compareProject(id,value,merge);
}else{ }else{
this.compareProject(id,pull,value); this.compareProject(id,pull,value);
@ -216,7 +216,7 @@ class NewMerge extends Component {
merge_user_login: is_fork_id ? projects_names[0].project_user_login : undefined merge_user_login: is_fork_id ? projects_names[0].project_user_login : undefined
} }
}) })
this.props.history.push(`/${login}/${identifier}/pulls/new`); this.props.history.push(`/${login}/${identifier}/compare`);
this.newMergelist(login,identifier); this.newMergelist(login,identifier);
}; };

View File

@ -213,7 +213,7 @@ class merge extends Component {
checkOperation() { checkOperation() {
const { projectsId,owner } = this.props.match.params; const { projectsId,owner } = this.props.match.params;
this.props.history.push(`/${owner}/${projectsId}/pulls/new`); this.props.history.push(`/${owner}/${projectsId}/compare`);
} }
render() { render() {
const { projectsId , owner } = this.props.match.params; const { projectsId , owner } = this.props.match.params;

View File

@ -1,169 +1,84 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { Tabs, Spin } from "antd"; import { Tabs } from 'antd';
import "../Order/order.css"; import Commits from './Commits';
import "./merge.css"; import Files from './Files';
import Commits from "./Commits";
import Comments from "../comments/comments"; import '../Order/order.css';
import Files from "./Files"; import './merge.css';
import axios from 'axios';
const { TabPane } = Tabs; const { TabPane } = Tabs;
class MergeFooter extends Component { class MergeFooter extends Component {
constructor(props){ constructor(props) {
super(props); super(props);
this.state={ this.state = {
pageData:undefined, activeKey: '1',
commitsData:undefined, };
filesData:undefined,
isSpin:false,
activeKey:"1",
commitCount:0,
filesCount:0
}
}
componentDidMount=()=>{
const { footer_type ,data } = this.props;
if(footer_type){
const { projectsId , owner , mergeId } = this.props.match.params;
this.getCommit(owner,projectsId,mergeId);
this.getFile(owner,projectsId,mergeId);
}
this.setState({
activeKey:footer_type ? "1" : "2",
commitCount:data && data.commits_count,
filesCount:data && data.files_count
})
}
componentDidUpdate=(prevProps)=>{
const { comparesData } = this.props;
const { footer_type } = this.props;
if(footer_type){
const { data } = this.props;
if(data !== prevProps.data){
this.setState({
commitCount:data && data.commits_count,
filesCount:data && data.files_count
})
}
}
if(comparesData !== prevProps.comparesData){
this.setState({
activeKey:footer_type ? "1" : "2"
})
this.changeTab(footer_type ? "1" : "2");
}
} }
changeTab=(index)=>{ changeTab = (index) => {
this.setState({ this.setState({
isSpin:true activeKey: index,
}) });
this.setState({ };
activeKey:index
})
const { footer_type , comparesData } = this.props;
const { projectsId , owner , mergeId } = this.props.match.params;
if(footer_type){
if(index === "2"){
this.getCommit(owner,projectsId,mergeId);
}else if(index === "3"){
this.getFile(owner,projectsId,mergeId);
}else{
this.setState({
isSpin:false
})
}
}else{
this.setState({
commitsData:comparesData.commits,
filesData:comparesData.diff,
commitCount:comparesData.commits_count,
filesCount:comparesData.diff && comparesData.diff.files_count,
isSpin:false
})
}
}
getCommit =(owner,projectsId,mergeId)=>{
const url = `/${owner}/${projectsId}/pulls/${mergeId}/commits.json`;
axios.get(url).then(result=>{
if(result){
this.setState({
commitsData:result.data.commits,
isSpin:false,
commitCount:result.data.commits_count
})
}
}).catch(error=>{})
}
getFile =(owner,projectsId,mergeId)=>{
const url = `/${owner}/${projectsId}/pulls/${mergeId}/files.json`;
axios.get(url).then(result=>{
if(result){
this.setState({
filesData:result.data,
isSpin:false,
filesCount:result.data.files_count,
})
}
}).catch(error=>{})
}
render() { render() {
const { projectsId , owner } = this.props.match.params; const { projectsId, owner } = this.props.match.params;
const { comparesData = {} } = this.props;
const { commits, diff, commits_count } = comparesData;
const { activeKey } = this.state;
const { footer_type, order_id, data , comparesData } = this.props; return (commits && commits.length === 0) || !diff ? (
let { isSpin , activeKey , filesCount, commitCount , filesData , commitsData } = this.state; ''
) : (
return ( <div className="main mergeRequest" style={{ paddingTop: '0px' }}>
!footer_type && !comparesData || (comparesData && ((comparesData.commits && comparesData.commits.length===0)||(comparesData && !comparesData.diff)) )?"": <Tabs
<div className="main mergeRequest" style={{paddingTop:"0px"}}> activeKey={activeKey}
<Spin spinning={isSpin}> className="custom-commit-tabs"
<Tabs animated={false}
activeKey={activeKey} onChange={this.changeTab}
className="custom-commit-tabs" >
animated={false} {commits && commits.length > 0 && (
onChange={this.changeTab} <TabPane
> tab={
{ <span>
footer_type && <span className="font-16">提交</span>
<TabPane {commits_count > 0 && (
tab={ <span className="tabNum">{commits_count}</span>
<span><span className="font-16">评论</span> )}
{data && parseInt(data.comments_count) > 0 && <span className="tabNum">{data.comments_count}</span>} </span>
</span> }
} key="1"> key="1"
<Comments >
order_id={order_id} <Commits
showNotification={this.props.showNotification} {...this.props}
only_show_content={true} commits={commits}
{...this.props} projectsId={projectsId}
/> owner={owner}
</TabPane> ></Commits>
} </TabPane>
{ )}
commitsData && commitsData.length > 0 && {diff && diff.files && diff.files.length > 0 && (
<TabPane tab={<span><span className="font-16">提交</span> <TabPane
{commitCount > 0 && <span className="tabNum">{commitCount}</span>} tab={
</span>} key="2"> <span>
<Commits {...this.props} commits={commitsData} projectsId={projectsId} owner={owner}></Commits> <span className="font-16">文件</span>
</TabPane> {diff.files_count > 0 && (
} <span className="tabNum">{diff.files_count}</span>
{ )}
filesData && filesData.files && filesData.files.length>0 && </span>
<TabPane tab={ }
<span><span className="font-16">文件</span> key="3"
{filesCount > 0 && <span className="tabNum">{filesCount}</span>} >
</span> <Files
} key="3"> {...this.props}
<Files {...this.props} data={filesData} projectsId={projectsId} owner={owner}/> data={diff}
</TabPane> projectsId={projectsId}
} owner={owner}
/>
</Tabs> </TabPane>
</Spin> )}
</Tabs>
</div> </div>
); );
} }

View File

@ -165,7 +165,8 @@ class MergeForm extends Component {
this.setState({ this.setState({
isSpin: false, isSpin: false,
}); });
this.props.history.push(`/${owner}/${projectsId}/pulls`); const { pull_request_id } = result.data;
this.props.history.push(`/${owner}/${projectsId}/pulls/${pull_request_id}`);
const { getDetail } = this.props; const { getDetail } = this.props;
getDetail && getDetail(); getDetail && getDetail();
} else { } else {
@ -195,7 +196,7 @@ class MergeForm extends Component {
isSpin: false, isSpin: false,
}); });
this.props.history.push( this.props.history.push(
`/${owner}/${projectsId}/pulls/${mergeId}/Messagecount` `/${owner}/${projectsId}/pulls/${mergeId}`
); );
} else { } else {
this.setState({ this.setState({
@ -287,7 +288,7 @@ class MergeForm extends Component {
type="default" type="default"
className="ml30" className="ml30"
onClick={()=>{ onClick={()=>{
this.props.history.push(merge_type === "new" ? `/${owner}/${projectsId}/pulls` : `/${owner}/${projectsId}/pulls/${mergeId}/detail`) this.props.history.push(merge_type === "new" ? `/${owner}/${projectsId}/pulls` : `/${owner}/${projectsId}/pulls/${mergeId}`)
}} }}
> >
<span className="plr10">取消</span> <span className="plr10">取消</span>

View File

@ -12,7 +12,7 @@ class Nodata extends Component{
<h3>欢迎使用合并请求</h3> <h3>欢迎使用合并请求</h3>
<div className="color-grey-8"> <div className="color-grey-8">
合并请求可以帮助您与他人协作编写代码在使用之前请先创建一个 <Link className="color-blue" to={`/${owner}/${projectsId}/pulls/new`}>合并请求</Link> 合并请求可以帮助您与他人协作编写代码在使用之前请先创建一个 <Link className="color-blue" to={`/${owner}/${projectsId}/compare`}>合并请求</Link>
</div> </div>
</div> </div>
</div> </div>

View File

@ -17,6 +17,7 @@ class children_comments extends Component {
page: 1, page: 1,
journal_spin: false, journal_spin: false,
search_count: 0, search_count: 0,
isSpin: false,
}; };
} }
@ -71,6 +72,9 @@ class children_comments extends Component {
.then((result) => { .then((result) => {
if (result) { if (result) {
this.getChildrenJournals(); this.getChildrenJournals();
// 删除回复后,如果需手动调用父组件查询评论列表的接口,以保持角标(评论数量)的一致(合并请求页面),
// 否则直接查顶级评论列表,否则只查询当前子评论列表(易修页面)
this.props.refreshCommentList && this.props.refreshCommentList();
} }
}) })
.catch((error) => { .catch((error) => {
@ -80,9 +84,15 @@ class children_comments extends Component {
// 翻页 // 翻页
ChangePage = (page) => { ChangePage = (page) => {
this.state.page = page; // this.state.page = page;
this.state.isSpin = true; // this.state.isSpin = true;
this.getChildrenJournals(); // 使用回调的写法这样在getChildrenJournals中使用的就是最新的state
this.setState({
page,
isSpin: true
}, () => {
this.getChildrenJournals();
});
}; };
commentCtx = (v) => { commentCtx = (v) => {
@ -183,7 +193,7 @@ class children_comments extends Component {
size="large" size="large"
loading={isSpin} loading={isSpin}
dataSource={journalsdata.issue_journals} dataSource={journalsdata.issue_journals}
renderItem={(item) => <List.Item>{this.renderList(item)}</List.Item>} renderItem={(item) => <List.Item key={item.id}>{this.renderList(item)}</List.Item>}
/> />
{this.Paginations()} {this.Paginations()}
</div> </div>

View File

@ -151,6 +151,8 @@ class comments extends Component {
isSpin: false, isSpin: false,
fileList: undefined, fileList: undefined,
}); });
const { updateCommentsNum } = this.props;
updateCommentsNum && updateCommentsNum(result.data.journals_total_count);
} }
}) })
.catch((error) => { .catch((error) => {
@ -372,7 +374,7 @@ class comments extends Component {
const renderList = (item) => { const renderList = (item) => {
return ( return (
<div className="width100"> <div className="width100" key={item.id}>
<div className="pb5"> <div className="pb5">
<Link <Link
to={`/${item && item.user_login}`} to={`/${item && item.user_login}`}
@ -456,6 +458,7 @@ class comments extends Component {
parent_id={item.id} parent_id={item.id}
onRef={this.onRef} onRef={this.onRef}
children_comment_id={new_journal_id} children_comment_id={new_journal_id}
refreshCommentList={this.getjournalslist}
{...this.props} {...this.props}
></ChildrenComments> ></ChildrenComments>
</div> </div>
@ -500,7 +503,7 @@ class comments extends Component {
loading={isSpin} loading={isSpin}
header="" header=""
dataSource={journalsdata.issue_journals} dataSource={journalsdata.issue_journals}
renderItem={(item) => <List.Item>{renderList(item)}</List.Item>} renderItem={(item) => <List.Item key={item.id}>{renderList(item)}</List.Item>}
/> />
)} )}
{this.Paginations()} {this.Paginations()}
@ -558,7 +561,7 @@ class comments extends Component {
header="" header=""
dataSource={journalsdata.issue_journals} dataSource={journalsdata.issue_journals}
renderItem={(item) => ( renderItem={(item) => (
<List.Item>{renderList(item)}</List.Item> <List.Item key={item.id}>{renderList(item)}</List.Item>
)} )}
/> />
)} )}