add team codes
This commit is contained in:
parent
bd85703412
commit
7eef81b91a
|
@ -1,6 +1,8 @@
|
|||
import React from 'react';
|
||||
import './Component.scss';
|
||||
import { Button } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
import FocusButton from "../UsersList/focus_button";
|
||||
|
||||
const Img = styled.img`{
|
||||
border-radius:50%;
|
||||
|
@ -56,17 +58,18 @@ const Div = styled.div`{
|
|||
align-items: center;
|
||||
border:1px solid #eee;
|
||||
}`
|
||||
export default (({img,name,time, focusStatus})=>{
|
||||
return(
|
||||
export default (({ img, name, time, focusStatus, is_current_user, login }) => {
|
||||
return (
|
||||
<Div>
|
||||
<Img src={img}/>
|
||||
<Img src={img} />
|
||||
<div className="m-infos">
|
||||
<Name>{name}</Name>
|
||||
<Time><I className="iconfont icon-shijian"></I>加入时间:{time}</Time>
|
||||
{
|
||||
focusStatus ?
|
||||
<FocusBtn><Ifocused className="iconfont icon-shixing"></Ifocused>已关注</FocusBtn> :
|
||||
<FocusBtn><Ifocus className="iconfont icon-kongxing"></Ifocus>关注</FocusBtn>
|
||||
is_current_user ?
|
||||
<Button type="default">当前用户</Button>
|
||||
:
|
||||
<FocusButton is_watch={focusStatus} id={login} />
|
||||
}
|
||||
</div>
|
||||
</Div>
|
||||
|
|
|
@ -2,10 +2,9 @@ import React from "react";
|
|||
import { Input } from "antd";
|
||||
|
||||
const { Search } = Input;
|
||||
export default ({ placeholder , onSearch , value , onChange }) => {
|
||||
export default ({ placeholder , onSearch , onChange }) => {
|
||||
return (
|
||||
<Search
|
||||
value={value}
|
||||
allowClear
|
||||
placeholder={placeholder}
|
||||
enterButton={'搜索'}
|
||||
|
|
|
@ -40,7 +40,7 @@ export default ({ getUser })=>{
|
|||
return (
|
||||
<Option
|
||||
key={key}
|
||||
value={`${item.user_id}`}
|
||||
value={`${item.login}`}
|
||||
searchValue={`${item.username}`}
|
||||
>
|
||||
<img
|
||||
|
|
|
@ -61,22 +61,24 @@ export const Redline = styled.a`{
|
|||
line-height:28px;
|
||||
border-radius:2px;
|
||||
border:1px solid #F73030;
|
||||
color:#F73030;
|
||||
color:${props => (props.bold ? "#fff" : "#F73030")} !important;
|
||||
padding:0px 12px;
|
||||
display:inline-block;
|
||||
min-width:80px;
|
||||
text-align:center;
|
||||
background:${props => (props.bold ? "#F73030" : "#fff")};
|
||||
}`
|
||||
export const Greenline = styled.a`{
|
||||
height:30px;
|
||||
line-height:28px;
|
||||
border-radius:2px;
|
||||
border:1px solid #28BD6C;
|
||||
color:#28BD6C;
|
||||
color:${props => (props.bold ? "#fff" : "#28BD6C")} !important;
|
||||
padding:0px 12px;
|
||||
display:inline-block;
|
||||
min-width:80px;
|
||||
text-align:center;
|
||||
background:${props => (props.bold ? "#28BD6C" : "#fff")};
|
||||
}`
|
||||
export const Greenback = styled.a`{
|
||||
height:30px;
|
||||
|
@ -154,12 +156,9 @@ export const Content = styled.div`{
|
|||
background-color:#fff;
|
||||
justify-content: center;
|
||||
}`
|
||||
export const RadioList = styled.span`{
|
||||
color:#888888;
|
||||
margin-left: 8px;
|
||||
}`
|
||||
export const RadioListBold = styled.span`{
|
||||
color:#333 !important;
|
||||
margin: 0 2px;
|
||||
export const GroupProjectBackgroup = styled.div`{
|
||||
background:#fafafa;
|
||||
padding: 30px;
|
||||
width:100%;
|
||||
}`
|
||||
|
||||
|
|
|
@ -1,35 +1,68 @@
|
|||
import React from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import Cards from '../../Component/MemberCards';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import axios from 'axios';
|
||||
import { Spin, Empty,Pagination } from 'antd';
|
||||
export default ((props) => {
|
||||
const [page, setPage] = useState(1);
|
||||
const [limit, setLimit] = useState(15);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [data, setMembers] = useState(undefined);
|
||||
const [isSpin, setIsSpin] = useState(false);
|
||||
const { OIdentifier, groupId } = props.match.params;
|
||||
const { current_user } = props;
|
||||
|
||||
export default (()=>{
|
||||
return(
|
||||
<div>
|
||||
useEffect(() => {
|
||||
getMember()
|
||||
}, [page])
|
||||
|
||||
function getMember() {
|
||||
setIsSpin(true)
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users.json`;
|
||||
axios
|
||||
.get(url, {
|
||||
params: {
|
||||
page,
|
||||
limit
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
if (result && result.data) {
|
||||
setMembers(result.data.team_users)
|
||||
setTotal(result.data.total_count)
|
||||
}
|
||||
}).catch((error) => { });
|
||||
setIsSpin(false)
|
||||
};
|
||||
|
||||
return (
|
||||
<Spin spinning={isSpin}>
|
||||
<div className="MemberBoxThree">
|
||||
<Cards
|
||||
img="https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3331079987,1190181307&fm=111&gp=0.jpg"
|
||||
name="陈教授"
|
||||
time="2020-04-29"
|
||||
focusStatus={true}
|
||||
/>
|
||||
<Cards
|
||||
img="https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3331079987,1190181307&fm=111&gp=0.jpg"
|
||||
name="陈教授"
|
||||
time="2020-04-29"
|
||||
focusStatus={true}
|
||||
/>
|
||||
<Cards
|
||||
img="https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3331079987,1190181307&fm=111&gp=0.jpg"
|
||||
name="陈教授"
|
||||
time="2020-04-29"
|
||||
focusStatus={true}
|
||||
/>
|
||||
<Cards
|
||||
img="https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3331079987,1190181307&fm=111&gp=0.jpg"
|
||||
name="陈教授"
|
||||
time="2020-04-29"
|
||||
focusStatus={true}
|
||||
/>
|
||||
{
|
||||
data && data.length > 0 ? data.map((item, key) => {
|
||||
return (
|
||||
<Cards
|
||||
img={getImageUrl(`images/${item.user.image_url}`)}
|
||||
name={item.user.name}
|
||||
time={item.created_at}
|
||||
focusStatus={item.user.watched}
|
||||
is_current_user={current_user && item.user.login === current_user.login}
|
||||
login={item.user.login}
|
||||
/>
|
||||
)
|
||||
})
|
||||
:
|
||||
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
total > limit ?
|
||||
<div className="edu-txt-center mt30 mb20">
|
||||
<Pagination simple defaultCurrent={page} total={total} pageSize={limit} onChange={ChangePage}></Pagination>
|
||||
</div>
|
||||
: ""
|
||||
}
|
||||
</Spin>
|
||||
|
||||
)
|
||||
})
|
|
@ -1,8 +1,10 @@
|
|||
import React from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import { Spin, Empty, Pagination } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const Box=styled.div`{
|
||||
import { getImageUrl } from 'educoder';
|
||||
const Box = styled.div`{
|
||||
padding:0px 38px;
|
||||
}`
|
||||
const Div = styled.div`{
|
||||
|
@ -21,17 +23,76 @@ const Imgs = styled.img`{
|
|||
border-radius:50%;
|
||||
}`
|
||||
|
||||
export default (()=>{
|
||||
return(
|
||||
const faker_projects = [
|
||||
{
|
||||
id: 2,
|
||||
project: {
|
||||
owner_name: "ceshi_org_1",
|
||||
name: "jajaj0",
|
||||
identifier: "ssjsksjsk"
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
project: {
|
||||
owner_name: "sylor_test",
|
||||
name: "sylor_test",
|
||||
identifier: "sylor_test"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
export default ((props) => {
|
||||
const [isSpin, setIsSpin] = useState(false);
|
||||
const [projects, setProjects] = useState(undefined);
|
||||
const [page, setPage] = useState(1);
|
||||
const [limit, setLimit] = useState(15);
|
||||
const [total, setTotal] = useState(0);
|
||||
const { OIdentifier, groupId } = props.match.params;
|
||||
|
||||
useEffect(() => {
|
||||
get_project()
|
||||
}, [page])
|
||||
|
||||
function get_project() {
|
||||
setIsSpin(true)
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_projects.json`;
|
||||
axios
|
||||
.get(url, {
|
||||
params: {
|
||||
page,
|
||||
limit
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
if (result && result.data && result.data.team_projects.length > 0) {
|
||||
setProjects(result.data.team_projects)
|
||||
setTotal(result.data.total_count)
|
||||
} else {
|
||||
setProjects(faker_projects)
|
||||
}
|
||||
}).catch((error) => { });
|
||||
setIsSpin(false)
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Div>
|
||||
<Imgs src="https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"/>
|
||||
<Link to={""}>ajdfwkerijwirjklsf</Link>
|
||||
</Div>
|
||||
<Div>
|
||||
<Imgs src="https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"/>
|
||||
<Link to={""}>ajdfwkerijwirjklsf</Link>
|
||||
</Div>
|
||||
<Spin spinning={isSpin}>
|
||||
{
|
||||
projects && projects.length > 0 ? projects.map((item, key) => {
|
||||
return (
|
||||
<Div>
|
||||
<Imgs src={item.project.image_url ? getImageUrl(`images/${item.project.image_url}`) : "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"}/>
|
||||
<Link to={`/projects/${item.project.owner_name}/${item.project.name}`}>{item.project.name}</Link>
|
||||
</Div>
|
||||
)
|
||||
})
|
||||
:
|
||||
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
||||
}
|
||||
</Spin>
|
||||
|
||||
</Box>
|
||||
)
|
||||
})
|
|
@ -1,12 +1,12 @@
|
|||
import React , {useState} from 'react';
|
||||
import { Button } from 'antd';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Button, Spin, Popconfirm, Empty } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
import { Box , Short , Long , Gap , WhiteBack , AlignCenterBetween } from '../../Component/layout';
|
||||
import { Box, Short, Long, Gap, WhiteBack, AlignCenterBetween } from '../../Component/layout';
|
||||
import Tabs from '../../Component/Tabs';
|
||||
|
||||
import Memberlist from './GroupDetailMember';
|
||||
import Grouplist from './GroupDetailProject';
|
||||
|
||||
import axios from 'axios';
|
||||
const Leave = styled.a`{
|
||||
display:block;
|
||||
border-radius:5px;
|
||||
|
@ -16,30 +16,88 @@ const Leave = styled.a`{
|
|||
height:30px;
|
||||
line-height:30px;
|
||||
}`
|
||||
export default ((props)=>{
|
||||
const [ nav , setNav ] = useState('0');
|
||||
export default ((props) => {
|
||||
const [nav, setNav] = useState('0');
|
||||
const [isSpin, setIsSpin] = useState(false);
|
||||
const [userSpin, setUserSpin] = useState(false);
|
||||
const [page, setPage] = useState(1);
|
||||
const [limit, setLimit] = useState(15);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [group, setGroup] = useState(undefined);
|
||||
const { OIdentifier, groupId } = props.match.params;
|
||||
const { current_user } = props;
|
||||
|
||||
return(
|
||||
useEffect(() => {
|
||||
setIsSpin(true)
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}.json`;
|
||||
axios.get(url)
|
||||
.then((result) => {
|
||||
if (result && result.data) {
|
||||
setGroup(result.data)
|
||||
}
|
||||
}).catch((error) => { });
|
||||
setIsSpin(false)
|
||||
}, [])
|
||||
|
||||
// 移除成员
|
||||
function removeUser(username) {
|
||||
setIsSpin(true)
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users/${username}.json`;
|
||||
if (username) {
|
||||
axios.delete(url)
|
||||
.then((result) => {
|
||||
if (result && result.data) {
|
||||
setPage(1)
|
||||
setQuery(undefined)
|
||||
setIdentify(undefined)
|
||||
this.getMember();
|
||||
}
|
||||
})
|
||||
.catch((error) => { });
|
||||
}
|
||||
setIsSpin(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<Box className="GroupSubLevel">
|
||||
<Short className="g-sub-left">
|
||||
<AlignCenterBetween>
|
||||
<span className="color-grey-3">Owndsknamename</span>
|
||||
<Leave>离开团队</Leave>
|
||||
</AlignCenterBetween>
|
||||
<div className="g-desc">该团队暂无描述</div>
|
||||
<div className="g-tip">
|
||||
<p>管理员团队对 <span>所有仓库</span> 具有操作权限,且对组织具有 <span>管理员权限</span>。 </p>
|
||||
<p>此外,该团队拥有了 <span>创建仓库</span> 的权限:成员可以在组织中创建新的仓库。 </p>
|
||||
<Button type="primary">团队设置</Button>
|
||||
</div>
|
||||
<Spin spinning={isSpin}>
|
||||
{
|
||||
group ?
|
||||
<div>
|
||||
<AlignCenterBetween>
|
||||
<span className="color-grey-3">{group.name}</span>
|
||||
{group.is_member ?
|
||||
<Popconfirm
|
||||
title="确认离开团队吗?"
|
||||
onConfirm={() => removeUser(current_user.login)}
|
||||
okText="确认"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Leave>离开团队</Leave>
|
||||
</Popconfirm>
|
||||
: ""
|
||||
}
|
||||
</AlignCenterBetween>
|
||||
<div className="g-desc">{group.description ? group.description : "暂无描述"}</div>
|
||||
<div className="g-tip">
|
||||
<p>管理员团队对 <span>所有仓库</span> 具有操作权限,且对组织具有 <span>管理员权限</span>。 </p>
|
||||
<p>此外,该团队拥有了 <span>创建仓库</span> 的权限:成员可以在组织中创建新的仓库。 </p>
|
||||
{group.is_admin ? <Button type="primary" href={`/organize/${OIdentifier}/group/${groupId}/setting`}><span className="color-white">团队设置</span></Button> : ""}
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
||||
}
|
||||
</Spin>
|
||||
</Short>
|
||||
<Long>
|
||||
<Gap>
|
||||
<WhiteBack>
|
||||
<Tabs nav={['团队成员','团队项目']} index={nav} onChange={setNav}>
|
||||
<Tabs nav={['团队成员', '团队项目']} index={nav} onChange={setNav}>
|
||||
{
|
||||
nav === "0" ?
|
||||
<Memberlist />:<Grouplist />
|
||||
<Memberlist {...props} /> : <Grouplist {...props}/>
|
||||
}
|
||||
</Tabs>
|
||||
</WhiteBack>
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
import React, { forwardRef, useCallback, useEffect, useState } from 'react';
|
||||
import { Form, Input, Radio, Checkbox, Switch, Button, Spin } from 'antd';
|
||||
import { Banner, WhiteBack, AlignCenter, Cancel } from '../../Component/layout';
|
||||
import styled from 'styled-components';
|
||||
import axios from 'axios';
|
||||
const TextArea = Input.TextArea;
|
||||
const Div = styled.div`{
|
||||
padding:20px 30px;
|
||||
}`
|
||||
const OptionStyle = {
|
||||
lineHeight: "25px",
|
||||
height: '25px',
|
||||
display: 'block'
|
||||
}
|
||||
const addStyle = {
|
||||
...OptionStyle,
|
||||
marginBottom: "7px"
|
||||
}
|
||||
|
||||
export default Form.create()(
|
||||
forwardRef(({ form,props, match, showNotification, history, GroupDetail }) => {
|
||||
|
||||
const [isSpin, setIsSpin] = useState(false);
|
||||
const [check_box, setGroupDetail] = useState(false);
|
||||
const [switch_box, setSwtichBox] = useState([]);
|
||||
const [switch_box_code, setSwtichBoxCode] = useState(false);
|
||||
const [switch_box_pull, setSwtichBoxPull] = useState(false);
|
||||
const [switch_box_issue, setSwtichBoxIssue] = useState(false);
|
||||
const [switch_box_release, setSwtichBoxRelease] = useState(false);
|
||||
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||
const { OIdentifier, groupId } = match.params;
|
||||
|
||||
useEffect(() => {
|
||||
if (GroupDetail) {
|
||||
setGroupDetail(GroupDetail.can_create_org_project)
|
||||
setSwtichBox(GroupDetail.units)
|
||||
setFieldsValue({
|
||||
...GroupDetail
|
||||
})
|
||||
}
|
||||
}, [GroupDetail])
|
||||
|
||||
useEffect(() => {
|
||||
if (switch_box && switch_box.length > 0) {
|
||||
setSwtichBoxCode(switch_checked("code"))
|
||||
setSwtichBoxPull(switch_checked("pulls"))
|
||||
setSwtichBoxIssue(switch_checked("issues"))
|
||||
setSwtichBoxRelease(switch_checked("releases"))
|
||||
}
|
||||
}, [switch_box])
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget, isRequired, mbValue) => (
|
||||
<React.Fragment>
|
||||
<span className={isRequired ? "required" : ""}>{label}</span>
|
||||
<Form.Item style={{ marginBottom: `${mbValue}px` || "20px" }}>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
</Form.Item>
|
||||
</React.Fragment>
|
||||
),
|
||||
[]
|
||||
);
|
||||
function saveGroupFrom() {
|
||||
setIsSpin(true)
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
values.unit_types = switch_box
|
||||
if (groupId) { // 表示编辑,否则为新建
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}.json`;
|
||||
axios.put(url, {
|
||||
...values
|
||||
}).then(result => {
|
||||
if (result && result.data) {
|
||||
showNotification("基本设置更新成功!");
|
||||
history.push(`/organizations/${OIdentifier}/teams/${groupId}`);
|
||||
}
|
||||
}).catch(error => { })
|
||||
} else {
|
||||
const url = `/organizations/${OIdentifier}/teams.json`;
|
||||
axios.post(url, {
|
||||
...values
|
||||
}).then(result => {
|
||||
if (result && result.data) {
|
||||
showNotification("团队创建成功!");
|
||||
history.push(`/organizations/${OIdentifier}/teams/${result.data.id}`);
|
||||
}
|
||||
}).catch(error => { })
|
||||
}
|
||||
}
|
||||
});
|
||||
setIsSpin(false)
|
||||
}
|
||||
|
||||
function change_check_box_status() {
|
||||
setGroupDetail(!check_box)
|
||||
}
|
||||
|
||||
function switch_checked(code) {
|
||||
return switch_box.indexOf(code) > -1
|
||||
}
|
||||
|
||||
function switch_unit_types(checked, code) {
|
||||
const switch_index = switch_box.indexOf(code)
|
||||
if (checked) {
|
||||
switch_box.push(code)
|
||||
} else {
|
||||
switch_box.splice(switch_index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
function switch_code_types(checked, event) {
|
||||
switch_unit_types(checked, "code")
|
||||
setSwtichBoxCode(checked)
|
||||
}
|
||||
|
||||
function switch_issue_types(checked, event) {
|
||||
switch_unit_types(checked, "issues")
|
||||
setSwtichBoxIssue(checked)
|
||||
}
|
||||
|
||||
function switch_pull_types(checked, event) {
|
||||
switch_unit_types(checked, "pulls")
|
||||
setSwtichBoxPull(checked)
|
||||
}
|
||||
|
||||
function switch_releas_types(checked, event) {
|
||||
switch_unit_types(checked, "releases")
|
||||
setSwtichBoxRelease(checked)
|
||||
}
|
||||
|
||||
function cancelEdit(){
|
||||
if(groupId){
|
||||
history.push(`/organizations/${OIdentifier}/teams/${groupId}`);
|
||||
}else{
|
||||
history.push(`/organizations/${OIdentifier}/teams`);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Spin spinning={isSpin}>
|
||||
<WhiteBack className="mb30">
|
||||
<Banner>{groupId ? "基本设置" : "新建团队"}</Banner>
|
||||
<Div>
|
||||
<Form>
|
||||
{helper(
|
||||
'团队名称:',
|
||||
"name",
|
||||
[{ required: true, message: "请输入团队名称" }],
|
||||
<Input placeholder="请输入团队名称" />, true
|
||||
)}
|
||||
{helper(
|
||||
<span className="mb5">团队描述:<span className="color-grey-8">(描述团队的目的或作用)</span></span>,
|
||||
"description",
|
||||
[],
|
||||
<TextArea
|
||||
placeholder="请输入团队描述"
|
||||
/>
|
||||
)}
|
||||
{helper(
|
||||
'项目权限:',
|
||||
"includes_all_project",
|
||||
[],
|
||||
<Radio.Group>
|
||||
<Radio value={true} style={addStyle}>指定项目<span className="color-grey-8 ml10">(团队成员将只能访问添加到团队的项目。 选择此项 <span className="color-grey-3">将不会</span> 自动删除已经添加的项目)</span></Radio>
|
||||
<Radio value={false} style={OptionStyle}>所有项目<span className="color-grey-8 ml10">(团队可以访问所有项目。选择此选项将 <span className="color-grey-3">添加所有现有的</span> 项目到指定团队)</span></Radio>
|
||||
</Radio.Group>, false, 0
|
||||
)}
|
||||
{helper(
|
||||
'',
|
||||
"can_create_org_project",
|
||||
[],
|
||||
<Checkbox checked={check_box} onChange={change_check_box_status} style={OptionStyle}>新建项目<span className="color-grey-8 ml10">(成员可以在组织中新建项目。创建者将自动获得新建的项目的管理员权限。)</span></Checkbox>, false
|
||||
)}
|
||||
{helper(
|
||||
'权限:',
|
||||
"authorize",
|
||||
[],
|
||||
<Radio.Group>
|
||||
<Radio value="read" style={addStyle}>读取权限<span className="color-grey-8 ml10">(成员可以查看和克隆团队项目)</span></Radio>
|
||||
<Radio value="write" style={addStyle}>写入权限<span className="color-grey-8 ml10">(成员可以查看和推送提交到团队项目)</span></Radio>
|
||||
<Radio value="admin" style={OptionStyle}>管理员权限<span className="color-grey-8 ml10">(成员可以拉取和推送到团队项目同时可以添加协作者)</span></Radio>
|
||||
</Radio.Group>, false
|
||||
)}
|
||||
</Form>
|
||||
<p className="required">允许访问项目单元:</p>
|
||||
<AlignCenter className="mb10">
|
||||
<Switch checked={switch_box_code} onClick={switch_code_types} />
|
||||
<span className="ml30 color-grey-3">代码库<span className="color-grey-8 ml15">(查看源码、文件、提交和分支)</span></span>
|
||||
</AlignCenter>
|
||||
<AlignCenter className="mb10">
|
||||
<Switch checked={switch_box_issue} onClick={switch_issue_types} />
|
||||
<span className="ml30 color-grey-3">任务<span className="color-grey-8 ml15">(组织 bug 报告、任务和里程碑)</span></span>
|
||||
</AlignCenter>
|
||||
<AlignCenter className="mb10">
|
||||
<Switch checked={switch_box_pull} onClick={switch_pull_types} />
|
||||
<span className="ml30 color-grey-3">合并请求<span className="color-grey-8 ml15">(启用合并请求和代码评审)</span></span>
|
||||
</AlignCenter>
|
||||
<AlignCenter className="mb20">
|
||||
<Switch checked={switch_box_release} onClick={switch_releas_types} />
|
||||
<span className="ml30 color-grey-3">版本发布<span className="color-grey-8 ml15">(跟踪项目版本和下载)</span></span>
|
||||
</AlignCenter>
|
||||
<Button type={"primary"} onClick={saveGroupFrom}>{groupId ? "更新团队设置" : "新建团队"}</Button>
|
||||
<Cancel className="ml30" onClick={() => cancelEdit()}><span className="pl30 pr30">取消</span></Cancel>
|
||||
</Div>
|
||||
</WhiteBack>
|
||||
</Spin>
|
||||
)
|
||||
})
|
||||
)
|
|
@ -1,123 +1,9 @@
|
|||
import React , { forwardRef , useCallback } from 'react';
|
||||
import { Form , Input , Radio , Checkbox , Switch , Button } from 'antd';
|
||||
import { Banner , WhiteBack , AlignCenter , Cancel } from '../../Component/layout';
|
||||
import styled from 'styled-components';
|
||||
import React from 'react';
|
||||
import GroupFrom from './GroupForm'
|
||||
|
||||
const TextArea = Input.TextArea;
|
||||
const Div = styled.div`{
|
||||
padding:20px 30px;
|
||||
}`
|
||||
const OptionStyle = {
|
||||
lineHeight:"25px",
|
||||
height:'25px',
|
||||
display:'block'
|
||||
function GropNew(props){
|
||||
return(
|
||||
<GroupFrom {...props}></GroupFrom>
|
||||
)
|
||||
}
|
||||
const addStyle = {
|
||||
...OptionStyle,
|
||||
marginBottom:"7px"
|
||||
}
|
||||
|
||||
export default Form.create()(
|
||||
forwardRef(({ form })=>{
|
||||
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget, isRequired , mbValue ) => (
|
||||
<React.Fragment>
|
||||
<span className={isRequired?"required":""}>{label}</span>
|
||||
<Form.Item style={{marginBottom:`${mbValue}px` || "20px"}}>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
</Form.Item>
|
||||
</React.Fragment>
|
||||
),
|
||||
[]
|
||||
);
|
||||
return(
|
||||
<WhiteBack className="mb30">
|
||||
<Banner>新建团队</Banner>
|
||||
<Div>
|
||||
<Form>
|
||||
{helper(
|
||||
'团队名称:',
|
||||
"name",
|
||||
[{ required: true, message: "请输入团队名称" }],
|
||||
<Input placeholder="请输入团队名称" />,true
|
||||
)}
|
||||
{helper(
|
||||
<span>团队描述:<span className="color-grey-8">(描述团队的目的或作用)</span></span>,
|
||||
"desc",
|
||||
[],
|
||||
<TextArea
|
||||
placeholder="请输入团队描述"
|
||||
/>
|
||||
)}
|
||||
{helper(
|
||||
'项目权限:',
|
||||
"operation",
|
||||
[],
|
||||
<Radio.Group>
|
||||
<Radio value="0" style={addStyle}>指定项目<span className="color-grey-8">(团队成员将只能访问添加到团队的项目。 选择此项 <span className="color-grey-3">将不会</span> 自动删除已经添加的项目)</span></Radio>
|
||||
<Radio value="1" style={OptionStyle}>所有项目<span className="color-grey-8">(团队可以访问所有项目。选择此选项将 <span className="color-grey-3">添加所有现有的</span> 项目到指定团队)</span></Radio>
|
||||
</Radio.Group>,false,0
|
||||
)}
|
||||
{helper(
|
||||
'',
|
||||
"operation",
|
||||
[],
|
||||
<Checkbox value="0" style={OptionStyle}>新建项目<span className="color-grey-8">(成员可以在组织中新建项目。创建者将自动获得新建的项目的管理员权限。)</span></Checkbox>
|
||||
)}
|
||||
{helper(
|
||||
'权限:',
|
||||
"halfoperation",
|
||||
[],
|
||||
<Radio.Group>
|
||||
<Radio value="0" style={addStyle}>读取权限<span className="color-grey-8">(成员可以查看和克隆团队项目)</span></Radio>
|
||||
<Radio value="1" style={addStyle}>写入权限<span className="color-grey-8">(成员可以查看和推送提交到团队项目)</span></Radio>
|
||||
<Radio value="2" style={OptionStyle}>管理员权限<span className="color-grey-8">(成员可以拉取和推送到团队项目同时可以添加协作者)</span></Radio>
|
||||
</Radio.Group>,false
|
||||
)}
|
||||
<p class="required">允许访问项目单元:</p>
|
||||
<AlignCenter>
|
||||
{helper(
|
||||
'',
|
||||
"allowCode",
|
||||
[],
|
||||
<Switch />,false,0
|
||||
)}
|
||||
<span className="ml30 color-grey-3">代码库<span className="color-grey-8 ml15">(查看源码、文件、提交和分支)</span></span>
|
||||
</AlignCenter>
|
||||
<AlignCenter>
|
||||
{helper(
|
||||
'',
|
||||
"allowtask",
|
||||
[],
|
||||
<Switch />,false,0
|
||||
)}
|
||||
<span className="ml30 color-grey-3">任务<span className="color-grey-8 ml15">(组织 bug 报告、任务和里程碑)</span></span>
|
||||
</AlignCenter>
|
||||
<AlignCenter>
|
||||
{helper(
|
||||
'',
|
||||
"allowPull",
|
||||
[],
|
||||
<Switch />,false,0
|
||||
)}
|
||||
<span className="ml30 color-grey-3">合并请求<span className="color-grey-8 ml15">(启用合并请求和代码评审)</span></span>
|
||||
</AlignCenter>
|
||||
<AlignCenter className="mb20">
|
||||
{helper(
|
||||
'',
|
||||
"allowVersion",
|
||||
[],
|
||||
<Switch />,false,0
|
||||
)}
|
||||
<span className="ml30 color-grey-3">版本发布<span className="color-grey-8 ml15">(跟踪项目版本和下载)</span></span>
|
||||
</AlignCenter>
|
||||
<Button type={"primary"}>新建团队</Button>
|
||||
<Cancel className="ml30">取消</Cancel>
|
||||
</Form>
|
||||
</Div>
|
||||
</WhiteBack>
|
||||
)
|
||||
})
|
||||
)
|
||||
export default GropNew;
|
|
@ -1,9 +1,315 @@
|
|||
import React , { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { WhiteBack, Blueline, AlignCenter, FlexAJ } from '../../../Component/layout';
|
||||
import { Menu, Table, Pagination, Icon, Tooltip, Popconfirm, Dropdown, Spin } from 'antd';
|
||||
import Sort from '../../../Component/Sort';
|
||||
import Title from '../../../Component/Title';
|
||||
import Search from '../../../Component/Search';
|
||||
import SearchUser from '../../../Component/SearchUser';
|
||||
import styled from 'styled-components';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import axios from 'axios';
|
||||
import { Link } from 'react-router-dom';
|
||||
const Img = styled.img`{
|
||||
width:30px;
|
||||
height:30px;
|
||||
border-radius:50%;
|
||||
}`
|
||||
|
||||
export default ((props) => {
|
||||
const [login, setAddUserLogin] = useState(undefined);
|
||||
const [page, setPage] = useState(1);
|
||||
const [limit, setLimit] = useState(15);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [data, setMembers] = useState(undefined);
|
||||
const [isSpin, setIsSpin] = useState(false);
|
||||
const [identify, setIdentify] = useState(undefined);
|
||||
const [search, setQuery] = useState(undefined);
|
||||
const { OIdentifier, groupId } = props.match.params;
|
||||
const { current_user } = props;
|
||||
|
||||
useEffect(() => {
|
||||
getMember()
|
||||
}, [page, search, identify])
|
||||
|
||||
function GroupMemberSetting() {
|
||||
return(
|
||||
<div>团队成员管理</div>
|
||||
function getMember() {
|
||||
setIsSpin(true)
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users.json`;
|
||||
axios
|
||||
.get(url, {
|
||||
params: {
|
||||
page,
|
||||
search,
|
||||
identify,
|
||||
limit
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
if (result && result.data) {
|
||||
setMembers(result.data.team_users)
|
||||
setTotal(result.data.total_count)
|
||||
}
|
||||
}).catch((error) => { });
|
||||
setIsSpin(false)
|
||||
};
|
||||
|
||||
// 获取搜索用户框里面选择的用户Login字段,接口是这样定义的
|
||||
function getUser(login) {
|
||||
setAddUserLogin(login)
|
||||
}
|
||||
|
||||
function addUser() {
|
||||
setIsSpin(true)
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users.json`;
|
||||
if (login) {
|
||||
axios.post(url, {
|
||||
username: login
|
||||
})
|
||||
.then((result) => {
|
||||
if (result && result.data) {
|
||||
setPage(1)
|
||||
setQuery(undefined)
|
||||
setIdentify(undefined)
|
||||
this.getMember();
|
||||
}
|
||||
})
|
||||
.catch((error) => { });
|
||||
}
|
||||
setIsSpin(false)
|
||||
}
|
||||
// 搜索
|
||||
function onSearch(value) {
|
||||
setQuery(value)
|
||||
}
|
||||
|
||||
// 角色筛选
|
||||
function onSelectMenu(e) {
|
||||
let select_role = e.key
|
||||
setPage(1)
|
||||
setQuery(undefined)
|
||||
setIdentify(select_role === "all" ? undefined : select_role)
|
||||
}
|
||||
|
||||
// 切换分页
|
||||
function ChangePage(page) {
|
||||
setPage(page);
|
||||
}
|
||||
|
||||
// 移除成员
|
||||
function removeUser(username) {
|
||||
setIsSpin(true)
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users/${username}.json`;
|
||||
if (username) {
|
||||
axios.delete(url)
|
||||
.then((result) => {
|
||||
if (result && result.data) {
|
||||
setPage(1)
|
||||
setQuery(undefined)
|
||||
setIdentify(undefined)
|
||||
this.getMember();
|
||||
}
|
||||
})
|
||||
.catch((error) => { });
|
||||
}
|
||||
setIsSpin(false)
|
||||
}
|
||||
|
||||
const MENU_LIST = [
|
||||
{
|
||||
id: "Manager",
|
||||
name: "管理员",
|
||||
desc: "拥有仓库设置功能、代码库读、写操作"
|
||||
},
|
||||
{
|
||||
id: "Developer",
|
||||
name: "开发者",
|
||||
desc: "只拥有代码库读、写操作"
|
||||
},
|
||||
{
|
||||
id: "Reporter",
|
||||
name: "报告者",
|
||||
desc: "只拥有代码库读操作"
|
||||
},
|
||||
];
|
||||
|
||||
const menu = (
|
||||
<Menu onSelect={onSelectMenu}>
|
||||
<Menu.Item key="all">全部</Menu.Item>
|
||||
{MENU_LIST.map((item, key) => {
|
||||
return (
|
||||
<Menu.Item
|
||||
key={item.id}
|
||||
value={item.id}
|
||||
>
|
||||
{item.name}
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
export default GroupMemberSetting;
|
||||
const roleTitle = (
|
||||
<div><span className="mr3">角色</span>
|
||||
<Tooltip placement='bottom' title=
|
||||
{
|
||||
<div>
|
||||
{MENU_LIST.map((item, key) => {
|
||||
return (
|
||||
<div className="mb3">{item.name}:{item.desc}</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Icon type="question-circle"></Icon>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
function get_color(role) {
|
||||
if (role === "manager") {
|
||||
return "text-green";
|
||||
} else if (role === "developer") {
|
||||
return "text-primary";
|
||||
} else {
|
||||
return "text-yellow";
|
||||
}
|
||||
};
|
||||
|
||||
const setRoles = (id) => (
|
||||
<Menu>
|
||||
{MENU_LIST.map((item, key) => {
|
||||
return (
|
||||
<Menu.Item
|
||||
key={item.id}
|
||||
value={item.id}
|
||||
onClick={(e) => this.changeOperaiton(e, id)}
|
||||
>
|
||||
{item.name}
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
);
|
||||
|
||||
// 修改权限
|
||||
function changeOperaiton(e, id) {
|
||||
console.log(e)
|
||||
};
|
||||
|
||||
const member_roles = (item) => {
|
||||
const operation = MENU_LIST.filter((i) => i.id === item.identify);
|
||||
return (
|
||||
<span>
|
||||
{operation && operation[0] ?
|
||||
<span>
|
||||
{current_user && current_user.login === item.login ? (
|
||||
<label className={get_color(item.role)}>
|
||||
{operation && operation[0].name}
|
||||
</label>
|
||||
) : (
|
||||
<Dropdown overlay={setRoles(`${item.id}`)} placement={"bottomCenter"}>
|
||||
<span className={get_color(item.role)}>
|
||||
{operation && operation[0].name}
|
||||
<Icon type="caret-down" className="ml2" size="13" />
|
||||
</span>
|
||||
</Dropdown>
|
||||
)}
|
||||
</span>
|
||||
: ""
|
||||
}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '头像',
|
||||
dataIndex: 'Img',
|
||||
width: "7%",
|
||||
render: (value, item) => {
|
||||
return (
|
||||
<Img src={getImageUrl(`images/${item.user.image_url}`)}></Img>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '用户名',
|
||||
dataIndex: 'name',
|
||||
width: "13%",
|
||||
align: "center",
|
||||
render: (value, item) => {
|
||||
return (
|
||||
<Link to={`/users/${item.user.login}`}>{item.user.name}</Link>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '邮箱',
|
||||
dataIndex: 'email',
|
||||
width: "25%",
|
||||
render: (value, item) => {
|
||||
return (
|
||||
item.user.mail
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: roleTitle,
|
||||
dataIndex: 'role',
|
||||
width: "20%",
|
||||
render: (value, item) => member_roles(item.user),
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
width: "15%",
|
||||
render: (value, item) => {
|
||||
return <Popconfirm
|
||||
title="确认移除成员吗?"
|
||||
onConfirm={() => removeUser(item.user.login)}
|
||||
okText="确认"
|
||||
cancelText="取消"
|
||||
>
|
||||
<a className="color-grey-8" href="#">移除成员</a>
|
||||
</Popconfirm>
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<Spin spinning={isSpin}>
|
||||
<WhiteBack>
|
||||
<Title>
|
||||
<span>组织成员管理</span>
|
||||
<AlignCenter>
|
||||
<SearchUser getUser={getUser} />
|
||||
<Blueline className="ml30" onClick={addUser}>+ 添加用户</Blueline>
|
||||
</AlignCenter>
|
||||
</Title>
|
||||
<FlexAJ className="padding20-30">
|
||||
<div style={{ width: "580px" }}>
|
||||
<Search placeholder="输入用户名或邮箱、团队名搜索" value={search} onSearch={onSearch} />
|
||||
</div>
|
||||
<Sort menu={menu}>
|
||||
<a className="color-blue">角色筛选<i className="iconfont icon-sanjiaoxing-down ml3 font-14"></i></a>
|
||||
</Sort>
|
||||
</FlexAJ>
|
||||
<div className="pl30 pr30 pb30">
|
||||
<Table
|
||||
size="small"
|
||||
columns={columns}
|
||||
dataSource={data}
|
||||
pagination={false}
|
||||
className="teamMemberTable"
|
||||
></Table>
|
||||
{
|
||||
total > limit ?
|
||||
<div className="edu-txt-center mt30 mb20">
|
||||
<Pagination simple defaultCurrent={page} total={total} pageSize={limit} onChange={ChangePage}></Pagination>
|
||||
</div>
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
</WhiteBack>
|
||||
</Spin>
|
||||
|
||||
)
|
||||
})
|
|
@ -1,9 +1,177 @@
|
|||
import React , { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import { AutoComplete, Pagination, List, Popconfirm, Dropdown, Spin } from 'antd';
|
||||
import { WhiteBack, Blueline, FlexAJ, GroupProjectBackgroup, Greenline, Redline } from '../../../Component/layout';
|
||||
import Title from '../../../Component/Title';
|
||||
const faker_projects = [
|
||||
{
|
||||
id: 2,
|
||||
project: {
|
||||
owner_name: "ceshi_org_1",
|
||||
name: "jajaj0",
|
||||
identifier: "ssjsksjsk"
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
project: {
|
||||
owner_name: "sylor_test",
|
||||
name: "sylor_test",
|
||||
identifier: "sylor_test"
|
||||
}
|
||||
}
|
||||
]
|
||||
// 使用了faker数据,后续需要修改
|
||||
function GroupProjectSetting(props) {
|
||||
const [isSpin, setIsSpin] = useState(false);
|
||||
const [projects, setProjects] = useState(undefined);
|
||||
const [page, setPage] = useState(1);
|
||||
const [limit, setLimit] = useState(15);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [search, setQuery] = useState(undefined);
|
||||
const [repo_name, setRepoName] = useState(undefined);
|
||||
const { OIdentifier, groupId } = props.match.params;
|
||||
|
||||
useEffect(() => {
|
||||
get_project()
|
||||
}, [page, search])
|
||||
|
||||
function GroupProjectSetting() {
|
||||
return(
|
||||
<div>团队项目管理</div>
|
||||
function get_project() {
|
||||
setIsSpin(true)
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_projects.json`;
|
||||
axios
|
||||
.get(url, {
|
||||
params: {
|
||||
page,
|
||||
search,
|
||||
limit
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
if (result && result.data && result.data.team_projects.length > 0) {
|
||||
setProjects(result.data.team_projects)
|
||||
setTotal(result.data.total_count)
|
||||
} else {
|
||||
setProjects(faker_projects)
|
||||
}
|
||||
}).catch((error) => { });
|
||||
setIsSpin(false)
|
||||
}
|
||||
|
||||
// 切换分页
|
||||
function ChangePage(page) {
|
||||
setPage(page);
|
||||
}
|
||||
|
||||
function removeProject(identifier) {
|
||||
setIsSpin(true)
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_projects/${identifier}.json`;
|
||||
axios.delete(url)
|
||||
.then((result) => {
|
||||
if (result && result.data.status > -1) {
|
||||
setPage(1)
|
||||
setQuery(undefined)
|
||||
get_project()
|
||||
}
|
||||
}).catch((error) => { });
|
||||
setIsSpin(false)
|
||||
}
|
||||
|
||||
function removeALLProject() {
|
||||
// 移除所有项目
|
||||
}
|
||||
|
||||
function addALLProject() {
|
||||
// 添加所有项目
|
||||
}
|
||||
|
||||
// 添加单个项目
|
||||
function addSingleProject(){
|
||||
setIsSpin(true)
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_projects.json`;
|
||||
axios.post(url, {repo_name: repo_name})
|
||||
.then((result) => {
|
||||
if (result && result.data.id) {
|
||||
setPage(1)
|
||||
setQuery(undefined)
|
||||
get_project()
|
||||
}
|
||||
}).catch((error) => { });
|
||||
setIsSpin(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<Spin spinning={isSpin}>
|
||||
<WhiteBack className="mb30">
|
||||
<Title>
|
||||
<span>团队项目管理</span>
|
||||
</Title>
|
||||
<FlexAJ className="padding20-30">
|
||||
<GroupProjectBackgroup>
|
||||
<FlexAJ>
|
||||
<div>
|
||||
<AutoComplete
|
||||
style={{ width: 300 }}
|
||||
placeholder="搜索项目..."
|
||||
/>
|
||||
<Blueline className="ml30" onClick={()=>addSingleProject()}>+ 添加项目</Blueline>
|
||||
</div>
|
||||
<div>
|
||||
<Popconfirm
|
||||
title="确认添加所有成员的项目吗?"
|
||||
onConfirm={() => addALLProject()}
|
||||
okText="确认"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Greenline bold>添加所有</Greenline>
|
||||
</Popconfirm>
|
||||
|
||||
<Popconfirm
|
||||
title="确认移除所有项目吗?"
|
||||
onConfirm={() => removeALLProject()}
|
||||
okText="确认"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Redline bold className="ml30">移除所有</Redline>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
</FlexAJ>
|
||||
</GroupProjectBackgroup>
|
||||
</FlexAJ>
|
||||
<div className="padding20-30">
|
||||
<List
|
||||
itemLayout="horizontal"
|
||||
dataSource={projects}
|
||||
renderItem={item => (
|
||||
<List.Item
|
||||
extra={
|
||||
<Popconfirm
|
||||
title="确认移除项目吗?"
|
||||
onConfirm={() => removeProject(item.project.identifier)}
|
||||
okText="确认"
|
||||
cancelText="取消"
|
||||
>
|
||||
<a className="color-red" href="#">移除</a>
|
||||
</Popconfirm>
|
||||
}
|
||||
>
|
||||
<List.Item.Meta
|
||||
title={<a href={`/projects/${item.project.owner_name}/${item.project.name}`}>{item.project.owner_name}/{item.project.name}</a>}
|
||||
/>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{
|
||||
total > limit ?
|
||||
<div className="edu-txt-center mt30 mb20">
|
||||
<Pagination simple defaultCurrent={page} total={total} pageSize={limit} onChange={ChangePage}></Pagination>
|
||||
</div>
|
||||
: ""
|
||||
}
|
||||
</WhiteBack>
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
export default GroupProjectSetting;
|
|
@ -1,160 +1,32 @@
|
|||
import React, { forwardRef, useCallback, useEffect, useState } from 'react';
|
||||
import { Form, Input, Radio, Switch, Divider, Button } from 'antd';
|
||||
import { WhiteBack, RadioList, RadioListBold } from '../../Component/layout';
|
||||
import Title from '../../Component/Title';
|
||||
import styled from 'styled-components';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {Spin } from 'antd';
|
||||
import axios from 'axios';
|
||||
const TextArea = Input.TextArea;
|
||||
import GroupFrom from './GroupForm'
|
||||
|
||||
const Div = styled.div`{
|
||||
padding:20px 30px;
|
||||
}`
|
||||
const radioStyle = {
|
||||
display: 'block',
|
||||
height: '30px',
|
||||
lineHeight: '30px',
|
||||
};
|
||||
export default Form.create()(
|
||||
forwardRef(({ form, organizeDetail, showNotification, history, current_user }) => {
|
||||
const [image, setImage] = useState(undefined);
|
||||
const [imageFlag, setImageFlag] = useState(false);
|
||||
const [password, setPassword] = useState(undefined);
|
||||
const [passwordFlag, setPasswordFlag] = useState(false);
|
||||
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||
function SettingCommon(props){
|
||||
const OIdentifier = props.match.params.OIdentifier;
|
||||
const groupId = props.match.params.groupId;
|
||||
|
||||
useEffect(() => {
|
||||
if (organizeDetail) {
|
||||
setFieldsValue({
|
||||
...organizeDetail
|
||||
})
|
||||
setImage(organizeDetail.avatar_url);
|
||||
}
|
||||
}, [organizeDetail])
|
||||
const [ detail , setDetail ] = useState(undefined);
|
||||
const [isSpin, setIsSpin] = useState(true);
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget, isRequired, flag) => (
|
||||
<div>
|
||||
<span className={isRequired ? "required" : ""}>{label}</span>
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true, valuePropName: flag ? "checked" : "value" })(widget)}
|
||||
</Form.Item>
|
||||
</div>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
// 更新
|
||||
function updateDetail() {
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
const url = `/organizations/${organizeDetail.id}.json`;
|
||||
axios.patch(url, {
|
||||
...values, image: imageFlag ? image : undefined
|
||||
}).then(result => {
|
||||
if (result && result.data) {
|
||||
showNotification("组织信息更新成功!");
|
||||
history.push(`/organize/${values.name}/setting`);
|
||||
}
|
||||
}).catch(error => { })
|
||||
}
|
||||
})
|
||||
}
|
||||
function getImage(image) {
|
||||
setImageFlag(true);
|
||||
setImage(image);
|
||||
useEffect(()=>{
|
||||
if(groupId){
|
||||
getDetail();
|
||||
}
|
||||
},[groupId]);
|
||||
|
||||
// 删除组织
|
||||
function deleteOrganize() {
|
||||
if (!password) {
|
||||
setPasswordFlag(true);
|
||||
return
|
||||
} else {
|
||||
setPasswordFlag(false);
|
||||
const url = `/organizations/${organizeDetail.id}.json`;
|
||||
axios.delete(url, {
|
||||
params: { password }
|
||||
}).then(result => {
|
||||
if (result && result.data) {
|
||||
// 删除后跳转到个人中心的组织页面
|
||||
history.push(`/users/${current_user && current_user.login}/organizes`);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<WhiteBack>
|
||||
<Title primary>基本设置</Title>
|
||||
<Div>
|
||||
<Form>
|
||||
{helper(
|
||||
"团队名称:",
|
||||
"name",
|
||||
[{ required: true, message: "请输入团队名称:" }],
|
||||
<Input placeholder="请输入团队名称:" />, true
|
||||
)}
|
||||
{helper(
|
||||
"团队描述:",
|
||||
"description",
|
||||
[],
|
||||
<div style={{ marginTop: '4px' }}>
|
||||
<TextArea placeholder="请输入团队描述团队的目的或作用" />
|
||||
</div>
|
||||
|
||||
)}
|
||||
{helper(
|
||||
'项目权限:',
|
||||
"visibility",
|
||||
[],
|
||||
<Radio.Group>
|
||||
<Radio value="common" style={radioStyle}><span className="color-black">指定项目</span><RadioList>(团队成员将只能访问添加到团队的项目。 选择此项<RadioListBold>将不会</RadioListBold>自动删除已经添加的项目)</RadioList></Radio>
|
||||
<Radio value="limited" style={radioStyle}><span className="color-black">所有项目</span><RadioList>(团队可以访问所有项目。选择此选项将 <RadioListBold>添加所有现有的</RadioListBold>项目到指定团队)</RadioList></Radio>
|
||||
<Radio value="privacy" style={radioStyle}><span className="color-black">新建项目</span><RadioList>(成员可以在组织中新建项目。创建者将自动获得新建的项目的管理员权限。)</RadioList></Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
{helper(
|
||||
'权限:',
|
||||
"repo_admin_change_team_access",
|
||||
[],
|
||||
<Radio.Group>
|
||||
<Radio value="common" style={radioStyle}><span className="color-black">读取权限</span><RadioList>(成员可以查看和克隆团队项目)</RadioList></Radio>
|
||||
<Radio value="limited" style={radioStyle}><span className="color-black">写入权限</span><RadioList>(成员可以查看和推送提交到团队项目)</RadioList></Radio>
|
||||
<Radio value="privacy" style={radioStyle}><span className="color-black">管理员权限</span><RadioList>(成员可以拉取和推送到团队项目同时可以添加协作者)</RadioList></Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
<Divider />
|
||||
{helper(
|
||||
'允许访问项目单元:',
|
||||
"max_repo_creation",
|
||||
[{ required: true, message: "请至少选择一项" }],
|
||||
<div>
|
||||
<div>
|
||||
<Switch defaultChecked className="group-setting-switch"/>
|
||||
<span><span className="color-black ml15">代码库</span><RadioList>(查看源码、文件、提交和分支)</RadioList></span>
|
||||
</div>
|
||||
<div>
|
||||
<Switch className="group-setting-switch"/>
|
||||
<span><span className="color-black ml15">任务</span><RadioList>(组织 bug 报告、任务和里程碑)</RadioList></span>
|
||||
</div>
|
||||
<div>
|
||||
<Switch className="group-setting-switch"/>
|
||||
<span><span className="color-black ml15">合并请求</span><RadioList>(启用合并请求和代码评审)</RadioList></span>
|
||||
</div>
|
||||
<div>
|
||||
<Switch className="group-setting-switch"/>
|
||||
<span><span className="color-black ml15">版本发布</span><RadioList>(跟踪项目版本和下载)</RadioList></span>
|
||||
</div>
|
||||
|
||||
</div>,
|
||||
true
|
||||
)}
|
||||
<Button type={"primary"} onClick={updateDetail}>更新团队设置</Button>
|
||||
<Button type={"text"} onClick={updateDetail} className="ml30"><span className="pl30 pr30">取消</span></Button>
|
||||
</Form>
|
||||
</Div>
|
||||
</WhiteBack>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)
|
||||
function getDetail() {
|
||||
const url = `/organizations/${OIdentifier}/teams/${groupId}.json`;
|
||||
axios.get(url).then((result) => {
|
||||
setDetail(result.data)
|
||||
}).catch((error) => { });
|
||||
setIsSpin(false)
|
||||
}
|
||||
return(
|
||||
<Spin spinning={isSpin}>
|
||||
<GroupFrom {...props} GroupDetail={detail}></GroupFrom>
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
export default SettingCommon;
|
Loading…
Reference in New Issue