forgeplus-react/src/forge/Merge/MessageCount.js

589 lines
19 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;