forked from Gitlink/forgeplus-react
merge 分支
This commit is contained in:
parent
dccc4e118a
commit
6aaa67f240
|
|
@ -3,23 +3,60 @@ import CopyTool from '../../Component/CopyTool';
|
|||
import { truncateCommitId } from '../../common/util';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { getImageUrl , turnbar } from 'educoder';
|
||||
import { Dropdown , Menu , Spin } from 'antd';
|
||||
import Nodata from '../../Nodata';
|
||||
import { Button, Dropdown , Input, Menu , message, Modal, Select, Spin, Table, Tooltip } from 'antd';
|
||||
import Modals from '../../Component/PublicModal/Index';
|
||||
import './Index.scss';
|
||||
|
||||
import Tree from '../img/tree.png';
|
||||
import Axios from 'axios';
|
||||
|
||||
function Index(props) {
|
||||
const [ reload, setReload] = useState(undefined);
|
||||
const [ list , setList ] = useState([]);
|
||||
const [ isSpin , setIsSpin ] = useState(true);
|
||||
// 删除分支
|
||||
const [visible, setVisible] = useState(false);
|
||||
// 新建分支
|
||||
const [addBranch, setAddBranch] = useState(false);
|
||||
const [newBranchName, setNewBranchName] = useState(undefined);
|
||||
const [newFormBranchName, setNewFormBranchName] = useState(undefined);
|
||||
const [newBranchError, setNewBranchError] = useState(undefined);
|
||||
const [branchList, setBranchList] = useState([]);//所有分支
|
||||
// 通过分支名搜索分支
|
||||
const [name, setName] = useState(undefined);
|
||||
// 分页
|
||||
const [current, setCurrent] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
|
||||
const { projectsId , owner } = props.match.params;
|
||||
const { isManager , isDeveloper , projectDetail , defaultBranch } = props;
|
||||
|
||||
const { isManager , isDeveloper , projectDetail , defaultBranch, getDetail } = props;
|
||||
useEffect(()=>{
|
||||
getList();
|
||||
},[])
|
||||
// getList();
|
||||
const url = `/v1/${owner}/${projectsId}/branches.json`;
|
||||
Axios.get(url,{
|
||||
params:{
|
||||
keyword: name,
|
||||
page: current,
|
||||
limit: pageSize
|
||||
}
|
||||
}).then(result=>{
|
||||
if(result){
|
||||
const {branches, total_count} = result.data;
|
||||
setTotal(total_count)
|
||||
setList(branches);
|
||||
setNewFormBranchName(branches[0].name);
|
||||
}
|
||||
setIsSpin(false);
|
||||
}).catch(error=>{setIsSpin(false);})
|
||||
},[name, reload, pageSize, current])
|
||||
|
||||
useEffect(()=>{
|
||||
if(projectDetail && document.title.indexOf('所有分支-') === -1){
|
||||
const { author, name} = projectDetail;
|
||||
document.title = `所有分支-${author.name}/${name}`;
|
||||
}
|
||||
}, [projectDetail])
|
||||
|
||||
|
||||
const menu =(zip_url,tar_url)=> (
|
||||
|
|
@ -29,6 +66,105 @@ function Index(props) {
|
|||
</Menu>
|
||||
)
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "分支名称",
|
||||
dataIndex: "name",
|
||||
key: 1,
|
||||
ellipsis: true,
|
||||
className: "branchNameColumn",
|
||||
render: (txt, item) => {
|
||||
return (
|
||||
<Link to={`/${owner}/${projectsId}/tree/${turnbar(txt)}`} onClick={()=>{window.scrollTo(0,0)}} className="task-hide">{txt}</Link>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "更新信息",
|
||||
dataIndex: "commit",
|
||||
key: 3,
|
||||
ellipsis: true,
|
||||
width: "240px",
|
||||
render: (txt, item) => {
|
||||
return (
|
||||
<div className='treeinfo'>
|
||||
{
|
||||
txt && txt.committer && txt.committer.id?
|
||||
<Link to={`/${ txt.committer.login}`}>
|
||||
<img style={{borderRadius:"50%"}} src={getImageUrl(`/${ txt.committer.image_url}`)} alt="" className='branchLastUpdateUserImage'/>
|
||||
<span style={{fontWeight:"500"}}>{txt && txt.committer && txt.committer.name}</span>
|
||||
</Link>
|
||||
:
|
||||
<React.Fragment>
|
||||
<img style={{borderRadius:"50%"}} src={getImageUrl(`/${ txt.committer.image_url}`)} alt="" className='branchLastUpdateUserImage'/>
|
||||
<span style={{fontWeight:"500"}}>{txt && txt.committer && txt.committer.name}</span>
|
||||
</React.Fragment>
|
||||
}
|
||||
<span className="color-grey-3">更新于{txt && txt.time_ago}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "commit信息",
|
||||
dataIndex: "commit_id",
|
||||
key: 4,
|
||||
ellipsis: true,
|
||||
width: "250px",
|
||||
render: (txt, item) => {
|
||||
return <div className="treecopy">
|
||||
<div className='treeCopyBox'>
|
||||
<span>
|
||||
<img src={Tree} alt="sha" width={"16px"}/>
|
||||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(txt)}`}>{truncateCommitId(txt)}</Link>
|
||||
<input type="text" id={`value${truncateCommitId(txt)}`} value={`${truncateCommitId(txt)}`}/>
|
||||
</span>
|
||||
<CopyTool beforeText="复制commit id" afterText="复制成功" inputId={`value${truncateCommitId(txt)}`}/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "分支类型",
|
||||
dataIndex: "default_branch",
|
||||
key: 5,
|
||||
width: "150px",
|
||||
render: (txt, item) => {
|
||||
return isManager ? txt === item.name ? <a className='btn-83' style={{width: '93px'}}>默认分支</a> : <Select value={1} onChange={(value)=>{updateDefaultBranch(value, item)}}>
|
||||
<Select.Option value={0}>默认分支</Select.Option>
|
||||
<Select.Option value={1}>普通分支</Select.Option>
|
||||
</Select> : txt === item.name ? '默认分支' : '普通分支'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
dataIndex: "name",
|
||||
key: 6,
|
||||
align: "center",
|
||||
width: "320px",
|
||||
className: "branchActionColumn",
|
||||
render: (txt, item) => {
|
||||
return (
|
||||
<div className="treeabout">
|
||||
{
|
||||
(isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) &&
|
||||
<Tooltip title={`以${txt}为源分支创建一个合并请求`}><Link to={
|
||||
// 如果项目是fork的项目,pr自动指向源仓库,否则指向本仓库默认分支
|
||||
projectDetail && projectDetail.fork_info?
|
||||
`/${projectDetail.fork_info.fork_project_user_login}/${projectDetail.fork_info.fork_project_identifier}/compare/${turnbar(txt || defaultBranch)}...${owner + ':' + turnbar(txt)}`
|
||||
:`/${owner}/${projectsId}/compare/${turnbar(defaultBranch)}...${turnbar(txt)}`
|
||||
} className="btn-83">+ 合并请求</Link></Tooltip>
|
||||
}
|
||||
<Dropdown overlay={menu(item.zip_url,item.tar_url)} trigger={['click']} placement="bottomRight">
|
||||
<a className="btn-83" style={{width: '76px'}}>下载<i className="iconfont icon-sanjiaoxing-down font-14"></i></a>
|
||||
</Dropdown>
|
||||
{isManager && (txt === item.default_branch ? <Tooltip title={`该分支为默认分支,不支持删除操作`}><Button style={{width: '76px'}} disabled>删除</Button></Tooltip> : <Button className='f6_bor_but' style={{width: '76px'}} onClick={()=>{setVisible(item)}}>删除</Button>)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
function getList() {
|
||||
const url = `/${owner}/${projectsId}/branches_slice.json`;
|
||||
Axios.get(url).then(result=>{
|
||||
|
|
@ -39,10 +175,121 @@ function Index(props) {
|
|||
}).catch(error=>{setIsSpin(false);})
|
||||
}
|
||||
|
||||
// 删除分支确认函数
|
||||
function deleteLabel(){
|
||||
Axios.delete(`/v1/${owner}/${projectsId}/branches/${visible.name}.json`).then(res=>{
|
||||
if(res && res.data){
|
||||
if(current>1 && (list && list.length===1)){
|
||||
setCurrent(current-1);
|
||||
}else{
|
||||
setReload(Math.random());
|
||||
}
|
||||
setVisible(false);
|
||||
!res.data.status && message.success('删除成功');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 新建分支确认函数
|
||||
function createBranch(){
|
||||
setNewBranchError(undefined);
|
||||
if(!newBranchName){
|
||||
setNewBranchError("请输入新建分支名称");
|
||||
}else{
|
||||
Axios.post(`/v1/${owner}/${projectsId}/branches.json`, {
|
||||
new_branch_name: newBranchName,
|
||||
old_branch_name: newFormBranchName
|
||||
}).then(res=>{
|
||||
if(res && res.data){
|
||||
// 重新请求仓库详情接口,更新分支总数信息
|
||||
getDetail();
|
||||
setReload(Math.random());
|
||||
setAddBranch(false);
|
||||
message.success('新建分支成功');
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 新建分支名检查格式
|
||||
function checkNewBranchName(e) {
|
||||
setNewBranchError(undefined);
|
||||
const value = e.target.value;
|
||||
if (value) {
|
||||
const str = '^*';
|
||||
let reg = /\\/g;
|
||||
if(reg.test(value)){
|
||||
setNewBranchError('分支名不能包含下列任何字符:^ * \\ ');
|
||||
}else{
|
||||
for(var i=0;i<str.length;i++){
|
||||
let s = str[i];
|
||||
if(value.indexOf(s) > -1){
|
||||
setNewBranchError('分支名不能包含下列任何字符:^ * \\ ');
|
||||
return;
|
||||
}else{
|
||||
setNewBranchName(e.target.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新默认仓库分支
|
||||
function updateDefaultBranch(value, info){
|
||||
Axios.patch(`/v1/${owner}/${projectsId}/branches/update_default_branch.json`,{
|
||||
name: info.name
|
||||
}).then(res=>{
|
||||
if(res && res.data){
|
||||
getDetail();
|
||||
setReload(Math.random());
|
||||
!res.data.status && message.success('操作成功');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 改变pagesize
|
||||
function onShowSizeChange(current, pageSize){
|
||||
window.scrollTo(0, 0);
|
||||
setCurrent(1);
|
||||
setPageSize(pageSize);
|
||||
}
|
||||
|
||||
// 切换页数
|
||||
function changePage(page, pageSize){
|
||||
window.scrollTo(0, 0);
|
||||
setCurrent(page);
|
||||
}
|
||||
|
||||
// 新建分支按钮点击函数
|
||||
function addBranchBtn(){
|
||||
setAddBranch(true);
|
||||
const url = `/v1/${owner}/${projectsId}/branches/all.json`;
|
||||
Axios.get(url).then(result=>{
|
||||
if(result){
|
||||
setBranchList(result.data);
|
||||
}
|
||||
}).catch(error=>{console.log('error', error);})
|
||||
}
|
||||
|
||||
return(
|
||||
<Spin spinning={isSpin}>
|
||||
<div style={{paddingTop:"10px",minHeight:"400px",paddingBottom:"30px"}}>
|
||||
{
|
||||
<div className='branchListActionBox'>
|
||||
<Input.Search placeholder='请输入分支名称' style={{width: '354px'}} className='searchBranch' onSearch={(value)=>{setCurrent(1);setName(value)}} allowClear/>
|
||||
<div>
|
||||
{isManager && <Link to={`/${owner}/${projectsId}/settings/branches`} className="btn-83" style={{width: '102px'}}><i className="iconfont icon-xuanzhongjibenshezhiicon font-14 mr5"></i>分支设置</Link>}
|
||||
{(isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) && <Button type='primary' onClick={addBranchBtn}>+ 新建分支</Button>}
|
||||
</div>
|
||||
</div>
|
||||
<Table
|
||||
rowKey={'name'}
|
||||
className='branchListTable'
|
||||
dataSource={list}
|
||||
columns={columns}
|
||||
pagination={{current: current, pageSize: pageSize, total: total, showSizeChanger: true, onShowSizeChange:onShowSizeChange, showQuickJumper: true, onChange: changePage}}
|
||||
>
|
||||
</Table>
|
||||
{/* {
|
||||
list && list.length>0 && list.map((item,key)=>{
|
||||
return(
|
||||
<React.Fragment>
|
||||
|
|
@ -86,7 +333,12 @@ function Index(props) {
|
|||
<div className="treeabout">
|
||||
{
|
||||
(isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) &&
|
||||
<Link to={`/${owner}/${projectsId}/compare/${turnbar(defaultBranch)}...${turnbar(i.name)}`} className="btn-83">+ 合并请求</Link>
|
||||
<Link to={
|
||||
// 如果项目是fork的项目,pr自动指向源仓库,否则指向本仓库默认分支
|
||||
projectDetail && projectDetail.fork_info?
|
||||
`/${projectDetail.fork_info.fork_project_user_login}/${projectDetail.fork_info.fork_project_identifier}/compare/${turnbar(i.name || defaultBranch)}...${owner + ':' + turnbar(i.name)}`
|
||||
:`/${owner}/${projectsId}/compare/${turnbar(defaultBranch)}...${turnbar(i.name)}`
|
||||
} className="btn-83">+ 合并请求</Link>
|
||||
}
|
||||
<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>
|
||||
|
|
@ -101,11 +353,47 @@ function Index(props) {
|
|||
</React.Fragment>
|
||||
)
|
||||
})
|
||||
}
|
||||
{
|
||||
list && list.length === 0 && <Nodata _html="暂无数据"/>
|
||||
}
|
||||
} */}
|
||||
</div>
|
||||
<Modals
|
||||
title="删除分支"
|
||||
onCancel={()=>{setVisible(false)}}
|
||||
visible={Boolean(visible)}
|
||||
width="456px"
|
||||
btn={
|
||||
<div>
|
||||
<Button size={"large"} onClick={()=>{setVisible(false)}}>取消</Button>
|
||||
<Button type={'danger'} ghost size={"large"} onClick={deleteLabel}>确认删除</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="contents mb30" style={{justifyContent: 'flex-start'}}>
|
||||
<i className='iconfont icon-shanchu_tc_icon1 font-36 mr18' style={{color: '#ca0002'}}></i>
|
||||
<p style={{color: '#333'}}>确定删除{visible.name}分支?</p>
|
||||
</div>
|
||||
</Modals>
|
||||
<Modal
|
||||
title="新建分支"
|
||||
onCancel={()=>{setAddBranch(false)}}
|
||||
visible={addBranch}
|
||||
width="388px"
|
||||
footer={
|
||||
<Button type={'primary'} style={{width:'334px', height: '42px'}} onClick={createBranch}>确认新建</Button>
|
||||
}
|
||||
className="createNewBranchModal"
|
||||
>
|
||||
<div className="mb30" style={{justifyContent: 'flex-start'}}>
|
||||
<div className='font-15 createBranchLabel'>分支名称</div>
|
||||
<Input placeholder='请输入分支名称' className='createBranchInput' onChange={checkNewBranchName} maxLength={100}/>
|
||||
<div className='newBranchError mt5'>{newBranchError}</div>
|
||||
<div className='font-15 createBranchLabel mt20'>分支起点</div>
|
||||
<Select showSearch style={{width: '340px'}} className='createBranchInput' placeholder="请选择分支起点" onChange={(value)=>{setNewFormBranchName(value)}} getPopupContainer={triggerNode => triggerNode.parentNode}>
|
||||
{branchList && branchList.map((item, index)=>{
|
||||
return <Select.Option value={item.name} key={index}>{item.name}</Select.Option>
|
||||
})}
|
||||
</Select>
|
||||
</div>
|
||||
</Modal>
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,98 @@
|
|||
.treeinfo{
|
||||
.branchLastUpdateUserImage{
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
.f6_bor_but, .f6_bor_but:focus{
|
||||
color:#f60011;
|
||||
background-color:rgba(196, 0, 14, 0.09);
|
||||
border:1px solid #f60011;
|
||||
border-radius:5px;
|
||||
&:hover{
|
||||
color:#f60011;
|
||||
background-color:rgba(196, 0, 14, 0.18);
|
||||
border-color:#ff727c;
|
||||
}
|
||||
&:active{
|
||||
color:#f60011;
|
||||
background-color:rgba(196, 0, 14, 0.22);
|
||||
border-color:#f60011;
|
||||
}
|
||||
}
|
||||
.branchListTable{
|
||||
.ant-table-thead > tr > th{
|
||||
border-top: 1px solid rgba(42, 97, 255, 0.23);
|
||||
border-bottom: 1px solid rgba(42, 97, 255, 0.23) !important;
|
||||
background-color:#fafcff;
|
||||
}
|
||||
.ant-table-column-title{
|
||||
color:#40424a;
|
||||
}
|
||||
.ant-table-thead > tr:first-child > th:last-child{
|
||||
border-right: 1px solid rgba(42, 97, 255, 0.23);
|
||||
}
|
||||
.ant-table-thead > tr:first-child > th:first-child{
|
||||
border-left: 1px solid rgba(42, 97, 255, 0.23);
|
||||
}
|
||||
.ant-table-tbody > tr > td{
|
||||
border-color: #eeeeee;
|
||||
padding: 18.5px 16px;
|
||||
}
|
||||
.branchNameColumn{
|
||||
border-left: 1px solid #d0d0d0;
|
||||
}
|
||||
.branchActionColumn{
|
||||
border-right: 1px solid #d0d0d0;
|
||||
}
|
||||
.task-hide{
|
||||
color: $primary-color;
|
||||
}
|
||||
.ant-table-empty .ant-table-placeholder{
|
||||
border-left: 1px solid #d0d0d0;
|
||||
border-right: 1px solid #d0d0d0;
|
||||
}
|
||||
}
|
||||
.branchListActionBox{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 20px 0 30px;
|
||||
}
|
||||
.createNewBranchModal{
|
||||
.ant-modal-title{
|
||||
text-align: left;
|
||||
color:#333333;
|
||||
font-size:17px;
|
||||
font-weight: normal !important;
|
||||
}
|
||||
.ant-modal-header{
|
||||
border-bottom: none;
|
||||
background-color:rgba(70, 106, 255, 0.05);
|
||||
}
|
||||
.ant-modal-close{right: 5px;}
|
||||
.ant-modal-close-x{font-size: 26px;}
|
||||
.ant-modal-footer{
|
||||
border-top: none;
|
||||
text-align: center;
|
||||
padding-bottom: 53px;
|
||||
}
|
||||
.ant-modal-content{
|
||||
background-image:linear-gradient(359.37deg,#ebf3ff 0%,#f8fbff 55.01%,#f1f5ff 100%);
|
||||
}
|
||||
.createBranchLabel{
|
||||
color:#27282d;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.createBranchInput, .createBranchInput .ant-select-selection{
|
||||
border-color:#9eaacb;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
.newBranchError{
|
||||
color:#df0002;
|
||||
}
|
||||
}
|
||||
.branchSort{
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
|
|
@ -49,14 +144,16 @@
|
|||
}
|
||||
.treecopy{
|
||||
flex:1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
// justify-content: center;
|
||||
&>div:not(.treeCopyBox){
|
||||
position: relative;
|
||||
}
|
||||
&>div{
|
||||
height: 32px;
|
||||
background: #FAFBFC;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #D0D0D0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -64,6 +161,7 @@
|
|||
padding:0px 15px;
|
||||
border-right: 1px solid rgba(153, 153, 153, 0.4);
|
||||
height: 100%;
|
||||
width: 140px;
|
||||
img{
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue