forked from Gitlink/forgeplus-react
400 lines
16 KiB
JavaScript
400 lines
16 KiB
JavaScript
import React , { useEffect , useState } from 'react';
|
||
import CopyTool from '../../Component/CopyTool';
|
||
import { truncateCommitId } from '../../common/util';
|
||
import { Link } from 'react-router-dom';
|
||
import { getImageUrl , turnbar } from 'educoder';
|
||
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, getDetail } = props;
|
||
useEffect(()=>{
|
||
// 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)=> (
|
||
<Menu>
|
||
<Menu.Item key={'0'}><a href={zip_url}>ZIP</a></Menu.Item>
|
||
<Menu.Item key={'1'}><a href={tar_url}>TAR.GZ</a></Menu.Item>
|
||
</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=>{
|
||
if(result){
|
||
setList(result.data);
|
||
}
|
||
setIsSpin(false);
|
||
}).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>
|
||
<p className="branchSort">{item.branch_type === "default" ? "默认分支" : item.branch_type==="protected"?"保护分支":"其它分支"}</p>
|
||
{
|
||
item.list && item.list.length>0 &&
|
||
<ul className="treeUl">
|
||
{
|
||
item.list.map((i,k)=>{
|
||
let last_commit = i.last_commit;
|
||
return(
|
||
<li>
|
||
<div className="treeinfo">
|
||
<Link to={`/${owner}/${projectsId}/tree/${turnbar(i.name)}`} className="task-hide">{i.name}</Link>
|
||
<div>
|
||
{
|
||
last_commit && last_commit.committer && last_commit.committer.id?
|
||
<Link to={`/${ last_commit.committer.login}`}>
|
||
<img style={{borderRadius:"50%"}} src={getImageUrl(`/${ last_commit.committer.image_url}`)} alt=""/>
|
||
<span className="mr3 color-grey-3" style={{fontWeight:"500"}}>{last_commit && last_commit.committer && last_commit.committer.name}</span>
|
||
</Link>
|
||
:
|
||
<React.Fragment>
|
||
<img style={{borderRadius:"50%"}} src={getImageUrl(`/${ last_commit.committer.image_url}`)} alt=""/>
|
||
<span className="mr3 color-grey-3" style={{fontWeight:"500"}}>{last_commit && last_commit.committer && last_commit.committer.name}</span>
|
||
</React.Fragment>
|
||
}
|
||
<span className="color-grey-3">更新于{last_commit && last_commit.time_from_now}</span>
|
||
</div>
|
||
</div>
|
||
<div className="treecopy">
|
||
<div>
|
||
<span>
|
||
<img src={Tree} alt="sha" width={"16px"}/>
|
||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(last_commit && last_commit.sha)}`}>{truncateCommitId(last_commit && last_commit.sha)}</Link>
|
||
<input type="text" id={`value${key}${k}`} value={`${truncateCommitId(last_commit && last_commit.sha)}`}/>
|
||
</span>
|
||
<CopyTool beforeText="复制commit id" afterText="复制成功" inputId={`value${key}${k}`}/>
|
||
</div>
|
||
</div>
|
||
<div className="treeabout">
|
||
{
|
||
(isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) &&
|
||
<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>
|
||
</Dropdown>
|
||
</div>
|
||
</li>
|
||
)
|
||
})
|
||
}
|
||
</ul>
|
||
}
|
||
</React.Fragment>
|
||
)
|
||
})
|
||
} */}
|
||
</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>
|
||
)
|
||
}
|
||
export default Index; |