forked from Gitlink/forgeplus-react
589 lines
19 KiB
JavaScript
589 lines
19 KiB
JavaScript
import React, { Component } from "react";
|
||
import { Tabs } from 'antd';
|
||
import { Link } from "react-router-dom";
|
||
import axios from "axios";
|
||
import { getImageUrl } from "educoder";
|
||
import {
|
||
Form,
|
||
Input,
|
||
Spin,
|
||
Dropdown,
|
||
Icon,
|
||
Menu,
|
||
Tag,
|
||
Button,
|
||
Alert,
|
||
} from "antd";
|
||
import "./merge.css";
|
||
import RenderHtml from "../../components/render-html";
|
||
import "../Order/order.css";
|
||
import MergeLinkFooter from "./MergeLinkFooter";
|
||
|
||
const TextArea = Input.TextArea;
|
||
|
||
function turnbar(str){
|
||
if(str && str.length>0 && str.indexOf("/")>-1){
|
||
return str.replaceAll('/','%2F');
|
||
}
|
||
return str;
|
||
}
|
||
class MessageCount extends Component {
|
||
constructor(props) {
|
||
super(props);
|
||
this.state = {
|
||
data: undefined,
|
||
isSpin: false,
|
||
ismesrge: false,
|
||
buttonshow: "none",
|
||
mergename: "合并请求",
|
||
mergekey: "merge",
|
||
title: "",
|
||
body: "",
|
||
SpinFlag: true,
|
||
SpinMerge: false,
|
||
edit_spin: false,
|
||
pr_status: undefined,
|
||
pull_request:undefined,
|
||
conflict_files:[],
|
||
|
||
copyVisible:false,
|
||
};
|
||
}
|
||
|
||
componentDidMount = () => {
|
||
this.setState({
|
||
SpinFlag: true,
|
||
});
|
||
this.getDetail();
|
||
|
||
// this.clickBody();
|
||
};
|
||
|
||
bindFootRef = (footRef) => {
|
||
this.footRef = footRef;
|
||
}
|
||
|
||
clickBody=()=>{
|
||
document.body.addEventListener('click', e => {
|
||
let name = e.target.className;
|
||
if(name.indexOf("notHide")>-1 || name.indexOf("ant-tabs-tab")>-1 || name==="ant-tabs-nav-scroll"){return;}
|
||
this.setState({
|
||
copyVisible:false
|
||
})
|
||
})
|
||
}
|
||
|
||
getDetail = () => {
|
||
const { projectsId, mergeId, owner } = this.props.match.params;
|
||
const url = `/${owner}/${projectsId}/pulls/${mergeId}.json`;
|
||
axios
|
||
.get(url)
|
||
.then((result) => {
|
||
if (result && result.data) {
|
||
this.setState({
|
||
data: result.data,
|
||
SpinFlag: false,
|
||
pr_status: result.data.pull_request && result.data.pull_request.status,
|
||
pull_request:result.data.pull_request,
|
||
conflict_files:result.data.conflict_files
|
||
});
|
||
} else {
|
||
this.setState({ SpinFlag: false });
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
this.setState({
|
||
SpinFlag: false,
|
||
});
|
||
console.log(error);
|
||
});
|
||
};
|
||
|
||
//关闭任务
|
||
closedetail = () => {
|
||
this.setState({ isSpin: true });
|
||
const { projectsId, mergeId , owner } = this.props.match.params;
|
||
const url = `/${owner}/${projectsId}/pulls/${mergeId}/refuse_merge.json`;
|
||
axios
|
||
.post(url)
|
||
.then((result) => {
|
||
if (result) {
|
||
this.setState({
|
||
isSpin: false,
|
||
pr_status: 2,
|
||
});
|
||
const { getDetail } = this.props;
|
||
getDetail && getDetail();
|
||
} else {
|
||
this.setState({
|
||
isSpin: false,
|
||
});
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
this.setState({
|
||
isSpin: false,
|
||
});
|
||
console.log(error);
|
||
});
|
||
};
|
||
|
||
//合并请求
|
||
prmerge = () => {
|
||
this.setState({
|
||
SpinMerge: true,
|
||
});
|
||
const { projectsId , owner } = this.props.match.params;
|
||
const { data, title, body, mergekey, pr_status } = this.state;
|
||
const url = `/${owner}/${projectsId}/pulls/${data.pull_request.id}/pr_merge.json`;
|
||
axios
|
||
.post(url, {
|
||
project_id: projectsId,
|
||
id: data.pull_request.id,
|
||
do: mergekey,
|
||
body: body,
|
||
title: title,
|
||
})
|
||
.then((result) => {
|
||
if (result) {
|
||
this.setState({
|
||
SpinMerge: false,
|
||
pr_status: 1,
|
||
});
|
||
const { getDetail } = this.props;
|
||
getDetail && getDetail();
|
||
// 调用子组件的方法刷新评论列表
|
||
this.footRef && this.footRef.refreshComment();
|
||
} else {
|
||
this.setState({ SpinMerge: false });
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
this.setState({
|
||
SpinMerge: false,
|
||
});
|
||
console.log(error);
|
||
});
|
||
};
|
||
|
||
changtitlepr = (e) => {
|
||
this.setState({
|
||
title: e.target.value,
|
||
});
|
||
};
|
||
|
||
changbodypr = (e) => {
|
||
this.setState({
|
||
body: e.target.value,
|
||
});
|
||
};
|
||
|
||
submitmerge = () => {
|
||
if (this.state.mergekey === "rebase") {
|
||
this.setState({
|
||
buttonshow: "block",
|
||
ismesrge: true,
|
||
});
|
||
} else {
|
||
this.setState({
|
||
ismesrge: "block",
|
||
buttonshow: false,
|
||
});
|
||
}
|
||
};
|
||
|
||
nonemerge = () => {
|
||
this.setState({
|
||
ismesrge: false,
|
||
buttonshow: "none",
|
||
});
|
||
};
|
||
|
||
getOption = (e) => {
|
||
if (e.key === "rebase") {
|
||
this.setState({
|
||
mergename: e.item.props.value,
|
||
mergekey: e.key,
|
||
title: "",
|
||
body: "",
|
||
buttonshow: "block",
|
||
});
|
||
} else {
|
||
this.setState({
|
||
mergename: e.item.props.value,
|
||
mergekey: e.key,
|
||
title: "",
|
||
body: "",
|
||
ismesrge: true,
|
||
buttonshow: "block",
|
||
});
|
||
}
|
||
};
|
||
|
||
cancelSubmit = () => {
|
||
this.setState({
|
||
editMerge: false,
|
||
});
|
||
};
|
||
|
||
commentCtx = (v) => {
|
||
return <RenderHtml className="break_word_comments imageLayerParent" value={v} url={this.props.history.location}/>;
|
||
};
|
||
|
||
setCopyVisible=(e)=>{
|
||
e.stopPropagation();
|
||
this.setState({
|
||
copyVisible:true
|
||
})
|
||
}
|
||
|
||
copyItem =()=>{
|
||
return(
|
||
<div className="copyTab notHide">
|
||
<Tabs defaultActiveKey="1" className="notHide" animated={false} size={"small"}>
|
||
<Tabs.TabPane key="1" tab={<span className="notHide">HTTPS</span>}>{this.returnCopyUrl("https://gitee.com/44886/polhttp.git")}</Tabs.TabPane>
|
||
<Tabs.TabPane key="2" tab={<span className="notHide">SSH</span>}>{this.returnCopyUrl("https://gitee.com/44886/polssh.git")}</Tabs.TabPane>
|
||
</Tabs>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
returnCopyUrl=(url)=>{
|
||
return(
|
||
<div className="df notHide">
|
||
<Input value={url} className="notHide" disabled={true}/>
|
||
<Button type="primary" ghost className="ml15 notHide">复制</Button>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
// 点击按钮复制功能
|
||
jsCopy = () => {
|
||
const copyEle = document.querySelector('#descContent') // 获取要复制的节点
|
||
const range = document.createRange(); // 创造range
|
||
window.getSelection().removeAllRanges(); //清除页面中已有的selection
|
||
range.selectNode(copyEle); // 选中需要复制的节点
|
||
window.getSelection().addRange(range); // 执行选中元素
|
||
document.execCommand("Copy"); // 执行copy操作
|
||
}
|
||
|
||
mergeabledMes=()=>{
|
||
return(
|
||
<div className="clearfix">
|
||
<p className="fl">该分支存在冲突,无法自动合并,你可以尝试通过如下命令手动合并</p>
|
||
<i className="iconfont icon-fuzhi font-16 fr" onClick={()=>this.jsCopy()}></i>
|
||
</div>
|
||
)
|
||
}
|
||
mergeabledDesc=(base,head,conflict_files)=>{
|
||
return(
|
||
<div>
|
||
<ul id="descContent">
|
||
<li>git fetch origin</li>
|
||
<li>git checkout -b {`${base}`} origin/{`${base}`}</li>
|
||
<li>git merge {`${head}`}</li>
|
||
</ul>
|
||
{
|
||
conflict_files && conflict_files.length>0 &&
|
||
<div>
|
||
<p className="mt10 font-16 pt10" style={{borderTop:"1px solid #f9d7d5"}}>如下文件有代码冲突:</p>
|
||
<div>
|
||
{
|
||
conflict_files.map((i,k)=>{
|
||
return <p key={k}>{i}</p>
|
||
})
|
||
}
|
||
</div>
|
||
</div>
|
||
}
|
||
</div>
|
||
)
|
||
}
|
||
|
||
render() {
|
||
const { projectsId, mergeId , owner } = this.props.match.params;
|
||
|
||
const {
|
||
data,
|
||
SpinMerge,
|
||
pr_status,
|
||
isSpin,
|
||
ismesrge,
|
||
SpinFlag,
|
||
copyVisible,
|
||
pull_request,
|
||
conflict_files
|
||
} = this.state;
|
||
const { current_user, projectDetail } = this.props;
|
||
const menu = (
|
||
<Menu onClick={(e) => this.getOption(e)}>
|
||
<Menu.Item key={"merge"} value="合并请求">
|
||
合并请求
|
||
</Menu.Item>
|
||
<Menu.Item key={"rebase"} value="变基并合并">
|
||
变基并合并
|
||
</Menu.Item>
|
||
<Menu.Item key={"rebase-merge"} value="变基合并 --no-ff">
|
||
变基合并 --no-ff
|
||
</Menu.Item>
|
||
<Menu.Item key={"squash"} value="压缩提交并合并">
|
||
压缩提交并合并
|
||
</Menu.Item>
|
||
</Menu>
|
||
);
|
||
const permission = projectDetail && (projectDetail.permission === "Admin" || projectDetail.permission === "Owner" || projectDetail.permission === "Manager");
|
||
const userLogin = current_user && current_user.login;
|
||
const operate = userLogin && projectDetail && pr_status === 0 && permission;
|
||
return (
|
||
<div>
|
||
{data ? (
|
||
<div>
|
||
<div className="main">
|
||
<div>
|
||
<div className="pb20 border-1f df">
|
||
<div className="flex1">
|
||
<div className="ver-middle">
|
||
<span className="mr10 ver-middle">
|
||
<span className="font-18 fwb" style={{wordBreak:"break-all"}}>
|
||
{data.issue.subject}
|
||
</span>
|
||
</span>
|
||
|
||
{data.pull_request && (
|
||
<Tag
|
||
className={`pr_tags_${data.pull_request.pull_request_staus}`}
|
||
>
|
||
{pr_status === 1
|
||
? "已合并"
|
||
: pr_status === 2
|
||
? "已拒绝"
|
||
: "开启的"}
|
||
</Tag>
|
||
)}
|
||
</div>
|
||
{
|
||
<div className="mt15">
|
||
<Tag className="pr-branch-tag">
|
||
<Link
|
||
to={`/${data.pull_request.is_fork ? data.pull_request_base.fork_project_user : data.issue.author_name}/${data.pull_request.is_original?data.project_identifier:projectsId}/tree/${turnbar(data.pull_request && data.pull_request.head)}`}
|
||
className="ver-middle task-hide" style={{maxWidth:"200px"}} title={`${data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}: ${data.pull_request && data.pull_request.head}`}
|
||
>
|
||
{data.pull_request.is_fork ? data.pull_request_base.fork_project_user : data.issue.author_name}: {data.pull_request && data.pull_request.head}
|
||
</Link>
|
||
</Tag>
|
||
<span className="mr8 ver-middle">
|
||
<i
|
||
className={
|
||
"iconfont icon-youjiang color-grey-c font-16"
|
||
}
|
||
></i>
|
||
</span>
|
||
<Tag className="pr-branch-tag">
|
||
<Link
|
||
to={`/${owner}/${projectsId}/tree/${data.pull_request.base}`}
|
||
className="ver-middle task-hide" style={{maxWidth:"200px"}} title={`${data.issue.project_author_name}:${data.pull_request.base}`}
|
||
>
|
||
{data.issue.author_name}:{data.pull_request.base}
|
||
</Link>
|
||
</Tag>
|
||
</div>
|
||
}
|
||
|
||
<div className="mt15">
|
||
<Link to={`/${data.issue.author_login}`} className="show-user-link">
|
||
<img className="mr5" src={getImageUrl(`/${data.issue.author_picture}`)}
|
||
alt="" width="24" height="24" style={{borderRadius:"50%"}}
|
||
/>
|
||
</Link>
|
||
<span className="ver-middle">
|
||
<span className="color-grey-8 mr5">由</span>
|
||
<Link to={`/${data.issue.author_login}`} className="show-user-link color-blue">
|
||
{data.issue.author_name}
|
||
</Link>
|
||
<span className="ml5 color-grey-8">
|
||
{pr_status === 0
|
||
? "创建于"
|
||
: pr_status === 1
|
||
? "合并于"
|
||
: "更新于"}
|
||
</span>
|
||
<span className="color-grey-8 ml5">{data.pr_time}</span>
|
||
<span className="ml25">
|
||
<span className="color-grey-8">审查人员:</span>
|
||
{data.issue.assign_user_name ? (
|
||
<Link
|
||
to={`/${data.issue.assign_user_login}`}
|
||
className="show-user-link color-blue"
|
||
>
|
||
{data.issue.assign_user_name}
|
||
</Link>
|
||
) : (
|
||
"--"
|
||
)}
|
||
</span>
|
||
<span className="ml25">
|
||
<span className="color-grey-8">里程碑:</span>
|
||
<span className="color-grey-3">
|
||
{data.issue.version ? data.issue.version : "--"}
|
||
</span>
|
||
</span>
|
||
<span className="ml25">
|
||
<span className="color-grey-8">标记:</span>
|
||
<span className="color-grey-3">
|
||
{data.issue.issue_tags &&
|
||
data.issue.issue_tags.length > 0
|
||
? data.issue.issue_tags[0].name
|
||
: "--"}
|
||
</span>
|
||
</span>
|
||
<span className="ml25">
|
||
<span className="color-grey-8">优先级:</span>
|
||
<span className="color-grey-3">
|
||
{data.issue.priority ? data.issue.priority : "--"}
|
||
</span>
|
||
</span>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div className="ml10 text-right">
|
||
{operate && (
|
||
<Button
|
||
type="green"
|
||
ghost
|
||
className="ml20"
|
||
onClick={()=>{this.props.history.push(`/${owner}/${projectsId}/pulls/${mergeId}/edit`);}}
|
||
>
|
||
编辑
|
||
</Button>
|
||
)}
|
||
{operate && (
|
||
<Button
|
||
type="danger"
|
||
ghost
|
||
onClick={() => this.closedetail()}
|
||
className="ml20"
|
||
loading={isSpin}
|
||
>
|
||
拒绝
|
||
</Button>
|
||
)}
|
||
</div>
|
||
</div>
|
||
{
|
||
data.issue.description ?
|
||
<div className="mt15">{this.commentCtx(data.issue.description)}</div>
|
||
:
|
||
<p className="color-grey-9 ml3 mr3 mt15">没有描述</p>
|
||
}
|
||
</div>
|
||
<div className="mt15">
|
||
{pr_status === 2 && (
|
||
<Alert
|
||
message="提示"
|
||
description="该合并请求已被拒绝"
|
||
type="error"
|
||
/>
|
||
)}
|
||
{pr_status === 1 && (
|
||
<Alert
|
||
message="提示"
|
||
description="该合并请求已被合并"
|
||
type="success"
|
||
/>
|
||
)}
|
||
{operate && (
|
||
<Spin spinning={SpinFlag}>
|
||
<div
|
||
style={{
|
||
display:
|
||
this.state.mergekey === "rebase"
|
||
? this.state.buttonshow === "none" ? "block" : "none"
|
||
: !ismesrge ? "block" : "none",
|
||
}}
|
||
>
|
||
<Dropdown.Button
|
||
overlay={menu}
|
||
type="primary"
|
||
onClick={this.submitmerge}
|
||
className="mb15"
|
||
icon={<Icon type="caret-down" />}
|
||
disabled={!pull_request || (pull_request && !pull_request.mergeable) }
|
||
>
|
||
{this.state.mergename}
|
||
</Dropdown.Button>
|
||
{pull_request && pull_request.mergeable
|
||
?
|
||
<Alert
|
||
message="该合并请求可以进行自动合并操作"
|
||
type="success"
|
||
showIcon
|
||
/>:
|
||
<Alert
|
||
message={this.mergeabledMes()}
|
||
type="error"
|
||
description={this.mergeabledDesc(pull_request.base,pull_request.head,conflict_files)}
|
||
showIcon
|
||
/>
|
||
}
|
||
</div>
|
||
<div>
|
||
<div
|
||
style={{
|
||
display: ismesrge ? "block" : "none",
|
||
marginTop: 15,
|
||
}}
|
||
>
|
||
<Input
|
||
placeholder="标题"
|
||
value={this.state.title}
|
||
onChange={this.changtitlepr}
|
||
/>
|
||
<TextArea
|
||
placeholder="请输入合并描述..."
|
||
style={{ height: "170px", marginTop: 20 }}
|
||
value={this.state.body}
|
||
onChange={this.changbodypr}
|
||
/>
|
||
</div>
|
||
<div
|
||
className="clearfix mt15"
|
||
style={{ display: this.state.buttonshow }}
|
||
>
|
||
<Spin spinning={SpinMerge}>
|
||
<Button type="primary" onClick={() => this.prmerge()}>
|
||
确认合并
|
||
</Button>
|
||
<Button
|
||
onClick={() => this.nonemerge()}
|
||
className="ml15"
|
||
>
|
||
取消
|
||
</Button>
|
||
</Spin>
|
||
</div>
|
||
</div>
|
||
</Spin>
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
<MergeLinkFooter
|
||
order_id={data && data.issue.id}
|
||
{...this.props}
|
||
{...this.state}
|
||
bindFootRef={this.bindFootRef}
|
||
></MergeLinkFooter>
|
||
</div>
|
||
) : (
|
||
""
|
||
)}
|
||
</div>
|
||
);
|
||
}
|
||
}
|
||
|
||
const MessageCountForm = Form.create({ name: "MessageCountForm" })(
|
||
MessageCount
|
||
);
|
||
export default MessageCountForm;
|