forked from Gitlink/forgeplus-react
分支设置
This commit is contained in:
parent
57363291f1
commit
0d1345f957
|
@ -63,7 +63,7 @@ class IndexItem extends Component {
|
|||
<span className="p-r-detail">
|
||||
{/* <span><label>浏览量:</label>{item.visits}</span> */}
|
||||
{/* {item.category && item.category.id && <span>{item.category.name}</span>} */}
|
||||
{item.last_update_time ? <span ><label>更新于</label>{item.time_ago}</span> : ""}
|
||||
{item.last_update_time ? <span><label>更新于</label>{item.time_ago}</span> : ""}
|
||||
{item.language && item.language.id ? <span className="color-grey-3">{item.language.name}</span> : ""}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -2,8 +2,11 @@ import React , { useEffect, useState } from 'react';
|
|||
import SelectBranch from '../Branch/Select';
|
||||
import Title from '../Component/Title';
|
||||
import styled from 'styled-components';
|
||||
import { Blueline , FlexAJ , NumUl , GreenUnder , AlignCenter , WhiteBack } from '../Component/layout';
|
||||
import { AlignCenter , WhiteBack , FlexAJ } from '../Component/layout';
|
||||
import axios from 'axios';
|
||||
import { Button, Select } from 'antd';
|
||||
import { getBranch } from '../GetData/getData';
|
||||
|
||||
const Div = styled.div`{
|
||||
padding:20px 30px;
|
||||
min-height:500px;
|
||||
|
@ -11,6 +14,13 @@ const Div = styled.div`{
|
|||
|
||||
export default ((props)=>{
|
||||
const [ branch , setBranch ] = useState("master");
|
||||
const [ branchList , setBranchList ] = useState(undefined);
|
||||
const [ protectBranch , setProtectBranch ] = useState(undefined);
|
||||
const [ protectBranchList , setProtectBranchList ] = useState(undefined);
|
||||
|
||||
const [ count , setCount ] = useState(0);
|
||||
const [ page , setPage ] = useState(1);
|
||||
|
||||
const { projectsId , owner } = props.match.params;
|
||||
const projectDetail = props.projectDetail;
|
||||
|
||||
|
@ -21,7 +31,36 @@ export default ((props)=>{
|
|||
}
|
||||
},[defaultBranch]);
|
||||
|
||||
useEffect(()=>{
|
||||
if(owner){
|
||||
getBranchs(projectsId,owner);
|
||||
getProtectBranchList(owner,projectsId);
|
||||
}
|
||||
},[owner])
|
||||
|
||||
// 获取已经设置过分支保护的分支列表
|
||||
function getProtectBranchList(owner,repo){
|
||||
const url = `/${owner}/${repo}/protected_branches.json`;
|
||||
axios.get(url,{
|
||||
params:{
|
||||
page,limit:15
|
||||
}
|
||||
}).then(result=>{
|
||||
if(result){
|
||||
setCount(result.data.total_count);
|
||||
setProtectBranchList(result.data.protected_branches);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
||||
// 获取分支列表(下拉、过滤掉已经设置过分支保护的分支)
|
||||
async function getBranchs(id,owner){
|
||||
let re = await getBranch(id,owner);
|
||||
setBranchList(re);
|
||||
|
||||
}
|
||||
|
||||
// 设为默认分支
|
||||
function resetSetting(){
|
||||
const url = `/${owner}/${projectsId}.json`;
|
||||
axios.put(url, {
|
||||
|
@ -36,15 +75,18 @@ export default ((props)=>{
|
|||
console.log(error);
|
||||
});
|
||||
}
|
||||
function settingRule(){
|
||||
props.history.push(`/projects/${owner}/${projectsId}/setting/branch/new`);
|
||||
|
||||
// 跳转
|
||||
function settingRule(protectBranch){
|
||||
props.history.push(`/projects/${owner}/${projectsId}/setting/branch/${protectBranch}`);
|
||||
}
|
||||
|
||||
return(
|
||||
<WhiteBack>
|
||||
<Title>分支设置</Title>
|
||||
<Div>
|
||||
<div className="pb20" style={{borderBottom:"1px solid #eee"}}>
|
||||
<p className="color-grey-3 mb10">默认分支</p>
|
||||
<div className="pb20" style={{borderBottom:"1px dashed #eee"}}>
|
||||
<p className="color-grey-3 mb10 font-18">默认分支</p>
|
||||
<p className="mb10">默认分支被视作为代码库中的基本分支,是所有克隆、代码提交、合并请求的目标分支</p>
|
||||
<AlignCenter>
|
||||
<SelectBranch
|
||||
|
@ -58,16 +100,45 @@ export default ((props)=>{
|
|||
<a className="color-blue ml20" onClick={()=>resetSetting()}>设为默认分支</a>
|
||||
</AlignCenter>
|
||||
</div>
|
||||
<div>
|
||||
<FlexAJ className="pt20">
|
||||
<span className="color-grey-3">保护分支规则</span>
|
||||
<Blueline onClick={()=>settingRule()}>+ 新建规则</Blueline>
|
||||
<div className="mt10">
|
||||
<p className="color-grey-3 mb10 font-18">分支保护</p>
|
||||
<AlignCenter>
|
||||
<Select
|
||||
showSearch
|
||||
className="setHeight"
|
||||
style={{ width: 240, height: 40 }}
|
||||
placeholder="选择分支"
|
||||
optionFilterProp="children"
|
||||
filterOption={(input, option) =>
|
||||
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
onChange={setProtectBranch}
|
||||
>
|
||||
{
|
||||
branchList && branchList.length > 0 && branchList.map((item,key)=>{
|
||||
return(
|
||||
<Select.Option value={item.name}>{item.name}</Select.Option>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Select>
|
||||
<a className="color-blue ml20" onClick={()=>settingRule(protectBranch)}>设置分支保护</a>
|
||||
</AlignCenter>
|
||||
{
|
||||
protectBranchList && protectBranchList.length > 0 &&
|
||||
<div className="protectBranchList">
|
||||
{
|
||||
protectBranchList.map((item,key)=>{
|
||||
return(
|
||||
<FlexAJ>
|
||||
<span>{item.branch_name}</span>
|
||||
<Button onClick={()=>settingRule(item.branch_name)}>编辑</Button>
|
||||
</FlexAJ>
|
||||
<NumUl>
|
||||
<li>限制分支的推送、合并。强制推送相关请去<GreenUnder onClick={()=>{props.history.push(`/projects/${owner}/${projectsId}/setting`)}}>仓库设置</GreenUnder>。</li>
|
||||
<li>一个分支同时只能有一个保护分支规则生效,越早创建的规则优先级越高。</li>
|
||||
<li>保护分支规则只影响状态是【保护分支】的分支。【常规分支】和【只读分支】都不影响。</li>
|
||||
</NumUl>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</Div>
|
||||
</WhiteBack>
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
import React, { forwardRef, useCallback, useState, useEffect } from "react";
|
||||
import { Form, Input, Select, Button } from "antd";
|
||||
import { Form, InputNumber , Select, Button , Checkbox , Radio } from "antd";
|
||||
import Title from "../Component/Title";
|
||||
import { WhiteBack, Cancel } from "../Component/layout";
|
||||
import styled from "styled-components";
|
||||
import { Cancel } from "../Component/layout";
|
||||
import axios from "axios";
|
||||
|
||||
const { Option } = Select;
|
||||
const Div = styled.div`
|
||||
{
|
||||
padding: 20px 30px;
|
||||
}
|
||||
`;
|
||||
export default Form.create()(
|
||||
forwardRef(({ form, match, history }) => {
|
||||
forwardRef(({ form, match, history , showNotification }) => {
|
||||
const [ protect , setProtect ] = useState(false);
|
||||
const [ protects , setProtects ] = useState(false);
|
||||
const [ mergeOptions , setMergeOptions ] = useState(undefined);
|
||||
const [ approveOptions , setApproveOptions ] = useState(undefined);
|
||||
const [ options , setOptions ] = useState(undefined);
|
||||
const [ list, setList ] = useState(undefined);
|
||||
const { projectsId, owner } = match.params;
|
||||
const { getFieldDecorator, validateFields } = form;
|
||||
|
||||
const { projectsId, owner , branch } = match.params;
|
||||
const { getFieldDecorator, validateFields , setFieldsValue } = form;
|
||||
|
||||
useEffect(() => {
|
||||
const url = `/${owner}/${projectsId}/collaborators.json`;
|
||||
|
@ -25,23 +24,65 @@ export default Form.create()(
|
|||
.catch((error) => {});
|
||||
}, []);
|
||||
|
||||
function getMember(list) {
|
||||
return (
|
||||
list &&
|
||||
list.length > 0 &&
|
||||
list.map((item, key) => {
|
||||
return (
|
||||
item.role !== "Manager" && (
|
||||
<Option value={item.id}>{item.name}</Option>
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
useEffect(()=>{
|
||||
if(branch){
|
||||
// 需要设置分支保护的分支名,获取分支保护详情
|
||||
getGuardDetail(owner,projectsId,branch);
|
||||
}
|
||||
},[branch]);
|
||||
|
||||
function getGuardDetail(owner,projectsId,branch){
|
||||
const url = `/${owner}/${projectsId}/protected_branches/${branch}/edit.json`;
|
||||
axios.get(url).then((result)=>{
|
||||
if(result){
|
||||
setProtect(result.data.protected);
|
||||
setProtects(result.data.protected);
|
||||
let protected_branch = result.data.protected_branch;
|
||||
|
||||
if(protected_branch){
|
||||
let enable_push = protected_branch.enable_push_whitelist ? 2 : protected_branch.enable_push ? 1 : 0;
|
||||
|
||||
setOptions(enable_push);
|
||||
setMergeOptions(protected_branch.enable_merge_whitelist);
|
||||
setApproveOptions(protected_branch.enable_approvals_whitelist);
|
||||
|
||||
setFieldsValue({
|
||||
|
||||
enable_push,
|
||||
...protected_branch
|
||||
})
|
||||
}
|
||||
}
|
||||
}).catch(error=>{});
|
||||
}
|
||||
|
||||
|
||||
function saveBranchRule() {
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
let url = "";
|
||||
if(protects){
|
||||
// 为true则修改
|
||||
url = `/${owner}/${projectsId}/protected_branches/${branch}.json`;
|
||||
}else{
|
||||
// 否则是保存
|
||||
url = `/${owner}/${projectsId}/protected_branches.json`;
|
||||
}
|
||||
axios({
|
||||
method:!protects ? "post" : (protect ? "patch" : "delete"),
|
||||
url,
|
||||
params:
|
||||
{
|
||||
branch_name:branch,
|
||||
enable_push:values.enable_push !== 0 ,
|
||||
enable_push_whitelist:values.enable_push === 2 ? true : false,
|
||||
...values
|
||||
}
|
||||
}).then(result=>{
|
||||
if(result){
|
||||
showNotification("保存成功!");
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -50,49 +91,202 @@ export default Form.create()(
|
|||
(label, name, rules, widget, className, isRequired) => (
|
||||
<div className={className}>
|
||||
<span className={isRequired ? "required" : ""}>{label}</span>
|
||||
<Form.Item>
|
||||
<Form.Item >
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
</Form.Item>
|
||||
</div>
|
||||
),
|
||||
[]
|
||||
);
|
||||
// 启用分支保护
|
||||
function changeProtect(e){
|
||||
setProtect(e.target.checked);
|
||||
}
|
||||
// 切换保护选线
|
||||
function changeProtectOption(e){
|
||||
setOptions(e.target.value);
|
||||
}
|
||||
// 切换是否启用合并白名单
|
||||
function changeMergeOption(e){
|
||||
setMergeOptions(e.target.checked);
|
||||
}
|
||||
|
||||
// 是否启用批准仅限列入白名单的用户或团队
|
||||
function changeWhitelistUsernameOption(e){
|
||||
setApproveOptions(e.target.checked);
|
||||
}
|
||||
return (
|
||||
<WhiteBack>
|
||||
<div style={{backgroundColor:"#fff"}}>
|
||||
<Title>新建保护分支规则</Title>
|
||||
<Div>
|
||||
<Form>
|
||||
<div style={{padding:"20px 30px"}}>
|
||||
{helper(
|
||||
"设置分支/通配符",
|
||||
"sign",
|
||||
[{ required: true, message: "请输入分支/通配符" }],
|
||||
<Input placeholder="请输入分支名称或通配符规则" />,
|
||||
"",
|
||||
"branchProtect",
|
||||
[],
|
||||
<Checkbox checked={protect} onChange={changeProtect}>
|
||||
启用分支保护<span className="color-grey-9 ml5 font-12">组织删除并限制Git推送和合并到分支</span>
|
||||
</Checkbox>,
|
||||
"setStyleRule"
|
||||
)}
|
||||
<p className="color-grey-8 mb20">
|
||||
例如:设置为“master”,则对名称为“master”的分支生效;设置为“*-stable“
|
||||
或 ”release*“,则对名称符合此通配符的所有保护分支生效。
|
||||
</p>
|
||||
<div className="pl25 shortStyle">
|
||||
{helper(
|
||||
"可推送代码成员",
|
||||
"psuhmember",
|
||||
[{ required: true, message: "请选择可推送代码成员" }],
|
||||
<Select placeholder="请选择仓库成员">
|
||||
<Option value="0">请选择仓库成员</Option>
|
||||
{getMember(list)}
|
||||
"",
|
||||
"enable_push",
|
||||
[],
|
||||
|
||||
<Radio.Group disabled={!protect} onChange={changeProtectOption}>
|
||||
<Radio className="columsRadio" value={0}>
|
||||
禁用推送<span className="color-grey-9 ml5 font-12">此分支不允许推送</span>
|
||||
</Radio>
|
||||
<Radio className="columsRadio" value={1}>
|
||||
启用推送<span className="color-grey-9 ml5 font-12">任何拥有写访问权限的人将被允许推送到此分支(但不能强行推送)</span>
|
||||
</Radio>
|
||||
<Radio className="columsRadio" value={2}>
|
||||
启用推送白名单<span className="color-grey-9 ml5 font-12">只有列入白名单的用户或团队才能被允许推送到此分支(但不能强行推送)</span>
|
||||
</Radio>
|
||||
</Radio.Group>,
|
||||
""
|
||||
)}
|
||||
<div className="pl25 pt5 pb5 mb15">
|
||||
{helper(
|
||||
"",
|
||||
"push_whitelist_usernames",
|
||||
[],
|
||||
<Select
|
||||
mode="multiple"
|
||||
placeholder="搜索用户"
|
||||
style={{ width: '100%' }}
|
||||
disabled={!protect || (options ===undefined || options !== 2)}
|
||||
>
|
||||
{list && list.map(item => (
|
||||
<Select.Option key={item.id} value={item.login}>
|
||||
{item.name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>,
|
||||
"setSelectWidth"
|
||||
"setStyleRule"
|
||||
)}
|
||||
</div>
|
||||
{helper(
|
||||
"",
|
||||
"enable_merge_whitelist",
|
||||
[],
|
||||
<Checkbox disabled={!protect} checked={mergeOptions} onChange={changeMergeOption}>
|
||||
启用合并白名单<span className="color-grey-9 ml5 font-12">仅允许白名单用户或团队合并合并请求到此分支</span>
|
||||
</Checkbox>,
|
||||
"setStyleRule"
|
||||
)}
|
||||
<div className="pl25 pt5 pb5">
|
||||
{helper(
|
||||
"",
|
||||
"merge_whitelist_usernames",
|
||||
[],
|
||||
<Select
|
||||
mode="multiple"
|
||||
placeholder="搜索用户"
|
||||
style={{ width: '100%' }}
|
||||
disabled={!protect || !mergeOptions}
|
||||
>
|
||||
{list && list.map(item => (
|
||||
<Select.Option key={item.id} value={item.login}>
|
||||
{item.name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>,
|
||||
"setStyleRule"
|
||||
)}
|
||||
</div>
|
||||
{helper(
|
||||
"",
|
||||
"enable_status_check",
|
||||
[],
|
||||
<Checkbox disabled={!protect}>
|
||||
启用状态检查
|
||||
</Checkbox>,
|
||||
"setStyleRule"
|
||||
)}
|
||||
<div style={{display:"flex",alignItems:"center"}}>
|
||||
{helper(
|
||||
"所需的批准数",
|
||||
"required_approvals",
|
||||
[],
|
||||
<InputNumber min={0} style={{width:"140px"}}/>,
|
||||
"inlineFlex"
|
||||
)}
|
||||
<span className="color-grey-9 ml5 font-12">只允许合并有足够审核人数的拉取请求</span>
|
||||
</div>
|
||||
|
||||
{helper(
|
||||
"",
|
||||
"enable_approvals_whitelist",
|
||||
[],
|
||||
<Checkbox disabled={!protect} checked={approveOptions} onChange={changeWhitelistUsernameOption}>
|
||||
批准仅限列入白名单的用户或团队<span className="color-grey-9 ml5 font-12">只有白名单用户或团队的审核才能计数 没有批准的白名单,任何有写访问权限的人的审核都将计数</span>
|
||||
</Checkbox>,
|
||||
"setStyleRule"
|
||||
)}
|
||||
<div className="pl25 pt5 pb5 mb15">
|
||||
{helper(
|
||||
"",
|
||||
"approvals_whitelist_usernames",
|
||||
[],
|
||||
<Select
|
||||
mode="multiple"
|
||||
placeholder="搜索用户"
|
||||
style={{ width: '100%' }}
|
||||
disabled={!protect || !approveOptions}
|
||||
>
|
||||
{list && list.map(item => (
|
||||
<Select.Option key={item.id} value={item.login}>
|
||||
{item.name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>,
|
||||
"setStyleRule"
|
||||
)}
|
||||
</div>
|
||||
|
||||
{helper(
|
||||
"",
|
||||
"block_on_rejected_reviews",
|
||||
[],
|
||||
<Checkbox disabled={!protect}>
|
||||
拒绝审核阻止了合并<span className="color-grey-9 ml5 font-12">如果官方审查人员要求作出改动,即使有足够的批准,合并也不允许</span>
|
||||
</Checkbox>,
|
||||
"setStyleRule"
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"",
|
||||
"dismiss_stale_approvals",
|
||||
[],
|
||||
<Checkbox disabled={!protect}>
|
||||
取消过时的批准<span className="color-grey-9 ml5 font-12">当新的提交更改合并请求内容被推送到分支时,旧的批准将被撤销</span>
|
||||
</Checkbox>,
|
||||
"setStyleRule"
|
||||
)}
|
||||
{helper(
|
||||
"可合并Pull Request成员",
|
||||
"pullmember",
|
||||
[{ required: true, message: "请选择可合并Pull Request成员" }],
|
||||
<Select placeholder="请选择仓库成员">
|
||||
<Option value="0">请选择仓库成员</Option>
|
||||
{getMember(list)}
|
||||
</Select>,
|
||||
"setSelectWidth"
|
||||
"",
|
||||
"require_signed_commits",
|
||||
[],
|
||||
<Checkbox disabled={!protect}>
|
||||
需要签名提交
|
||||
</Checkbox>,
|
||||
"setStyleRule"
|
||||
)}
|
||||
<div className="df pb30">
|
||||
{helper(
|
||||
"",
|
||||
"block_on_outdated_branch",
|
||||
[],
|
||||
<Checkbox disabled={!protect}>
|
||||
如果拉取请求已经过时,阻止合并<span className="color-grey-9 ml5 font-12">当头部分支落后基础分支时,不能合并</span>
|
||||
</Checkbox>,
|
||||
"setStyleRule"
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="df pb30 pt20">
|
||||
<Button type="primary" onClick={saveBranchRule}>
|
||||
保存
|
||||
</Button>
|
||||
|
@ -105,8 +299,9 @@ export default Form.create()(
|
|||
取消
|
||||
</Cancel>
|
||||
</div>
|
||||
</Div>
|
||||
</WhiteBack>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
);
|
||||
|
|
|
@ -65,7 +65,7 @@ class Index extends Component {
|
|||
</Link>
|
||||
</p>
|
||||
</li>
|
||||
{/* <li
|
||||
<li
|
||||
className={
|
||||
pathname.indexOf("setting/branch") > -1 ? "active" : ""
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ class Index extends Component {
|
|||
分支设置
|
||||
</Link>
|
||||
</p>
|
||||
</li> */}
|
||||
</li>
|
||||
<li
|
||||
className={pathname.indexOf("setting/tags") > -1 ? "active" : ""}
|
||||
>
|
||||
|
@ -120,7 +120,7 @@ class Index extends Component {
|
|||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/projects/:owner/:projectsId/setting/branch/new"
|
||||
path="/projects/:owner/:projectsId/setting/branch/:branch"
|
||||
render={(props) => (
|
||||
<BranchNew {...this.props} {...props} {...this.state} />
|
||||
)}
|
||||
|
|
|
@ -187,7 +187,29 @@
|
|||
width: 100%;
|
||||
}
|
||||
}
|
||||
.shortStyle{
|
||||
.setStyleRule{
|
||||
height: 35px;
|
||||
}
|
||||
.columsRadio{
|
||||
display: block;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.ant-row.ant-form-item{
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
.inlineFlex{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
& > span{
|
||||
margin-right: 10px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
.setStyleRule{
|
||||
height: 35px;
|
||||
.ant-row.ant-form-item{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
@ -197,3 +219,21 @@
|
|||
width: 100%;
|
||||
}
|
||||
}
|
||||
.setHeight{
|
||||
.ant-select-selection,.ant-select-selection__rendered{
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
}
|
||||
.protectBranchList{
|
||||
border:1px solid #eee;
|
||||
border-radius: 5px;
|
||||
margin-top: 25px;
|
||||
&>div{
|
||||
padding:5px 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
&>div:last-child{
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ import { AlignCenter } from '../Component/layout';
|
|||
import axios from 'axios';
|
||||
import Modals from '../Component/Modal';
|
||||
import PasswordAuthority from '../Component/PasswordAuthority';
|
||||
import { func } from 'prop-types';
|
||||
|
||||
const TIPS = "解除CI服务器绑定后,您所有的项目构建数据将被清空。确定解除绑定?";
|
||||
function CIdispose(props){
|
||||
|
|
Loading…
Reference in New Issue