Merge branch 'undo' into develop

# Conflicts:
#	src/forge/Component/SearchUser.jsx
This commit is contained in:
caishi 2021-04-28 20:17:59 +08:00
commit 3a3a0251aa
21 changed files with 729 additions and 89 deletions

View File

@ -3,7 +3,7 @@ import { getImageUrl } from 'educoder';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import './Component.scss'; import './Component.scss';
function Cards({img , title, desc , rightBtn , src}){ function Cards({img , title, desc , rightBtn , src , bottomInfos}){
return( return(
<div className="cards"> <div className="cards">
{img &&<div className="img"><img src={getImageUrl(`/${img}`)} alt=""/></div>} {img &&<div className="img"><img src={getImageUrl(`/${img}`)} alt=""/></div>}
@ -15,6 +15,7 @@ function Cards({img , title, desc , rightBtn , src}){
<div className="desc"> <div className="desc">
{desc} {desc}
</div> </div>
{bottomInfos}
</div> </div>
</div> </div>
) )

View File

@ -1,8 +1,8 @@
.ant-modal-mask{ .ant-modal-mask{
z-index: 10000; z-index: 1001;
} }
.ant-modal-wrap{ .ant-modal-wrap{
z-index: 10001; z-index: 1002;
.ant-form-explain{ .ant-form-explain{
position: absolute; position: absolute;
} }

View File

@ -5,10 +5,16 @@ import axios from 'axios';
const Option = AutoComplete.Option; const Option = AutoComplete.Option;
export default ({ getUser , placeholder, width })=>{ export default ({ getUser , placeholder, width ,value })=>{
const [ source , setSource ] = useState(undefined); const [ source , setSource ] = useState(undefined);
const [ searchKey , setSearchKey ] = useState(undefined); const [ searchKey , setSearchKey ] = useState(undefined);
useEffect(()=>{
if(!value){
setSearchKey(undefined);
}
},[value])
useEffect(()=>{ useEffect(()=>{
getUserList(); getUserList();
},[searchKey]) },[searchKey])

View File

@ -0,0 +1,174 @@
import React ,{ forwardRef, useEffect, useState } from 'react';
import { Modal , Form , Input , Radio , Select } from 'antd';
import SearchUser from '../Component/SearchUser';
import './Index.scss';
import Axios from 'axios';
const { Option } = Select;
function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
const { getFieldDecorator, validateFields , setFieldsValue } = form;
const [ cate , setCate ] = useState(0);
const [ value , setValue ] = useState(undefined);
const [ organizations , setOrganizations ] = useState(undefined);
useEffect(()=>{
setFieldsValue({goal:cate})
},[])
useEffect(()=>{
if(owner && repo && visible===true){
getTeam();
}
if(!visible){
setFieldsValue({
owner_name:undefined,
identifier:undefined
})
setValue(undefined)
}
},[repo,owner,visible])
function getTeam(){
const url = `/${owner}/${repo}/applied_transfer_projects/organizations.json`;
Axios.get(url).then(result=>{
if(result){
setOrganizations(result.data.organizations);
}
}).catch(error=>{})
}
//
function onOk(){
validateFields((error,values)=>{
console.log(...values);
if(!error){
const url = `/${owner}/${repo}/applied_transfer_projects.json`;
Axios.post(url,{
...values
}).then(result=>{
if(result){
onSuccess(result.data && result.data.owner);
}
}).catch(error=>{})
}
})
}
function changeType(e){
setCate(e.target.value);
setFieldsValue({
owner_name:undefined
})
}
function checkIdentifier(rule, value, callback){
if(!value){
callback();
}
if (repo && value !== repo) {
callback("请输入当前项目的标识!");
}
callback();
}
const layout = {
labelCol: { span: 5 },
wrapperCol: { span: 18 },
};
function getUser(id){
setValue(id);
setFieldsValue({
owner_name:id
})
}
return(
<Modal
width="620px"
visible={visible}
title="转移仓库"
onCancel={onCancel}
onOk={onOk}
okText="确认转移"
cancelText={"取消"}
centered
>
<div className="diverModal">
{
cate === 0 ?
<ul className="descUl">
<li>转移需对方确认接受转移成功后你将被移出仓库其他已有成员权限不变</li>
<li>转移成功后仓库的地址将变更至目标用户的命名空间下</li>
<li>已有成员如需继续操作仓库需更新本地仓库的remote使之指向新的地址</li>
</ul>
:
<ul className="descUl">
<li>仓库仅可以转移到您已经加入的组织中不可以转移到未加入的组织中</li>
<li>涉及到仓库改名操作请提前做好仓库备份并且在转移后对本地仓库的remote进行修改</li>
<li>转移仓库到组织后你和组织创建者/管理员同时拥有对该仓库的管理操作</li>
</ul>
}
<Form {...layout} colon={false} layout={"horizontal"}>
<Form.Item label="转移给:" style={{marginBottom:"0px"}}>
{getFieldDecorator("goal",{
rules:[]
})(
<Radio.Group onChange={changeType}>
<Radio value={0}>个人</Radio>
<Radio value={1}>组织</Radio>
</Radio.Group>
)}
</Form.Item>
{
cate === 0 &&
<Form.Item label=" ">
{getFieldDecorator("owner_name",{
rules:[{required:true,message:"请输入目标用户名"}]
})(
// <Input placeholder="" autoComplete={"off"}/>
<SearchUser getUser={getUser} width={"100%"} placeholder="请输入目标用户" value={value}/>
)}
</Form.Item>
}
{
cate === 1 &&
<Form.Item label=" ">
{getFieldDecorator("owner_name",
{rules:[{required:true,message:"请选择目标组织"}]}
)(
<Select placeholder="请选择目标组织" getPopupContainer={trigger => trigger.parentNode}>
{
organizations && organizations.length > 0 ?
organizations.map((i,k)=>{
return(
<Option value={i.name}>{i.nickname}</Option>
)
})
:""
}
</Select>
)}
</Form.Item>
}
<Form.Item label="仓库标识:">
{getFieldDecorator("identifier",
{
rules:[
{required:true,message:"请输入仓库标识"},
{
validator:checkIdentifier
}
]
}
)(
<Input placeholder="请输入仓库标识" autoComplete={"off"}/>
)}
</Form.Item>
</Form>
</div>
</Modal>
)
}
export default Form.create()(forwardRef(DivertModal));

View File

@ -0,0 +1,12 @@
.diverModal{
.descUl{
background-color: #fffae6;
border-radius: 4px;
padding:10px 15px;
color: #efc16b;
border:1px solid #efc16b;
}
.ant-form-item-required::before{
content: "";
}
}

View File

@ -75,7 +75,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
</li> </li>
:"" :""
} }
{ {/* {
item.menu_name === "resources" && item.menu_name === "resources" &&
<li className={pathname==="source" ? "active" : ""}> <li className={pathname==="source" ? "active" : ""}>
<Link to={{ pathname: `/projects/${owner}/${projectsId}/source`, state }}> <Link to={{ pathname: `/projects/${owner}/${projectsId}/source`, state }}>
@ -84,7 +84,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
{projectDetail && projectDetail.source_count ? <span className="num">{projectDetail.source_count}</span> :""} {projectDetail && projectDetail.source_count ? <span className="num">{projectDetail.source_count}</span> :""}
</Link> </Link>
</li> </li>
} } */}
{ {
item.menu_name === "versions" && item.menu_name === "versions" &&
<li className={pathname==="milestones" ? "active" : ""}> <li className={pathname==="milestones" ? "active" : ""}>

View File

@ -178,7 +178,7 @@ class NewMerge extends Component {
let arr = projects_names && projects_names.filter(item=>item.id===value); let arr = projects_names && projects_names.filter(item=>item.id===value);
let identifier = arr && arr[0].project_id; let identifier = arr && arr[0].project_id;
let login = arr && arr[0].project_user_login; let login = arr && arr[0].project_user_login;
let is_fork_id = parseInt(value) !== parseInt(id) let is_fork_id = parseInt(value) !== parseInt(id);
this.setState({ this.setState({
isSpin: true, isSpin: true,
merge_head: is_fork_id, merge_head: is_fork_id,

View File

@ -34,17 +34,19 @@ class MergeForm extends Component {
this.set_defatul(); this.set_defatul();
}; };
componentDidUpdate=(prevPros)=>{ componentDidUpdate=(prevPros)=>{
const { projectsId ,owner } = this.props.match.params;
const pId = prevPros.match.params.projectsId;
const oId = prevPros.match.params.owner;
if(pId !== projectsId || oId !== owner ){
// console.log("切换了项目分支···········");
this.get_default_selects();
}
if(prevPros && this.props && !this.props.checkIfLogin()){ if(prevPros && this.props && !this.props.checkIfLogin()){
this.props.history.push("/403") this.props.history.push("/403")
return return
} }
} }
// check_is_login =() =>{
// if(!this.props.checkIfLogin()){
// this.props.history.push("/403")
// return
// }
// };
get_default_selects = () => { get_default_selects = () => {
const { projectsId ,owner } = this.props.match.params; const { projectsId ,owner } = this.props.match.params;
this.setState({ isSpin: true }); this.setState({ isSpin: true });

View File

@ -0,0 +1,88 @@
import React, { useEffect, useState } from "react";
import { Link } from 'react-router-dom';
import './Index.scss';
import Loadable from "react-loadable";
import Loading from "../../Loading";
import { Route, Switch } from "react-router-dom";
const Notify = Loadable({
loader: () => import("./Notify"),
loading: Loading,
});
const UndoEvent = Loadable({
loader: () => import("./UndoEvent"),
loading: Loading,
});
function Index(props){
const username = props.match.params.username;
const pathname = props.history.location.pathname;
const user = props.user;
const undo_messages = props.undo_messages;
const [ menu , setMenu ] = useState("notify");
const [ messages , setMessages ] = useState(0);
const [ transferProjects , setTransferProjects ] = useState(0);
useEffect(()=>{
if(user){
setTransferProjects(user.undo_transfer_projects);
}
if(undo_messages){
setMessages(undo_messages);
}
},[user,undo_messages])
useEffect(()=>{
if(pathname && username){
if(pathname === `/users/${username}/notice`){
setMenu("notify");
}
if(pathname === `/users/${username}/notice/undo`){
setMenu("undo");
}
}
},[pathname])
function fetchUser(){
props && props.fetchUser();
}
function changeNum(){
fetchUser();
}
return (
<div>
<ul className="noticeMenu">
<li className={menu === "notify" ? "active":""}>
<Link to={`/users/${username}/notice`} onClick={changeNum}>
<span>通知</span>
{messages ? <span className="unNum">{messages}</span>:""}
</Link>
</li>
<li className={menu === "undo" ? "active":""}>
<Link to={`/users/${username}/notice/undo`}>
<span>接收仓库</span>
{transferProjects ? <span className="unNum">{transferProjects}</span>:""}
</Link>
</li>
</ul>
<Switch>
<Route
path="/users/:username/notice/undo"
render={(p) => {
return <UndoEvent {...props} {...p} fetchUser={fetchUser}/>;
}}
></Route>
<Route
path="/users/:username/notice"
render={(p) => {
return <Notify {...props} {...p} fetchUser={fetchUser}/>;
}}
></Route>
</Switch>
</div>
);
}
export default Index;

View File

@ -0,0 +1,72 @@
.noticeMenu{
padding:0px 20px;
display: flex;
border-bottom: 1px solid #eee;
height: 54px;
line-height: 54px;
li{
font-size: 16px;
padding:0px;
margin:0px 30px 0px 20px!important;
height: 54px;
line-height: 54px;
position: relative;
transform: none;
a{
display: flex;
&>span{
position: relative;
}
}
&.active a span:first-child::after{
position: absolute;
bottom: 0px;
height: 2px;
left: 0px;
content: "";
background-color: #1890ff;
width: 100%;
}
.unNum{
color: #d38900;
font-size: 12px;
border-radius: 13px;
height: 16px;
line-height: 16px;
padding:0px 4px;
min-width: 23px;
text-align: center;
background-color: #ffe4b3;
margin-top: 19px;
margin-left: 10px;
display: block;
}
}
}
.notifyList{
padding:0px 20px;
min-height: 400px;
li{
display: flex;
border-bottom: 1px solid #eee;
padding:20px 0px;
.notifyImg{
width: 48px;
height: 48px;
border-radius: 50%;
margin-right: 15px;
}
.notifyFlex{
flex:1;
p{
margin:0px;
}
.notifyInfos{
margin-bottom: 8px;
}
}
&:last-child{
border-bottom: none;
}
}
}

View File

@ -0,0 +1,91 @@
import React, { useEffect, useState } from "react";
import Nodata from '../Nodata';
import {Pagination } from 'antd';
import { Link } from 'react-router-dom';
import { getImageUrl } from 'educoder';
import Axios from "axios";
const limit = 15;
function Notify(props){
const username = props.match.params.username;
const [ list , setList ] = useState(undefined);
const [ page , setPage ] = useState(1);
const [ total , setTotal ] = useState(0);
useEffect(()=>{
if(username){
getList();
}
},[username,page])
function getList(){
const url = `/users/${username}/applied_messages.json`;
Axios.get(url,{
params:{
page,per_page:limit
}
}).then(result=>{
if(result){
setList(result.data.applied_messages);
setTotal(result.data.total_count);
}
}).catch(error=>{})
}
function renderStatus(status,applied){
let { project , owner} = applied
if(status){
switch(status){
case 'canceled':
return <p>取消转移<Link to={`/projects/${project && project.owner && project.owner.login}/${project && project.identifier}`}>{project && project.name}</Link>仓库</p>
case 'common':
return <p>正在将<Link to={`/projects/${project && project.owner && project.owner.login}/${project && project.identifier}`}>{project && project.name}</Link>仓库转移给<Link to={`/users/${owner && owner.login}`}>{owner && owner.name}</Link></p>
case 'successed':
return <p><Link to={`/projects/${project && project.owner && project.owner.login}/${project && project.identifier}`}>{project && project.name}</Link>仓库成功转移给<Link to={`/users/${owner && owner.login}`}>{owner && owner.name}</Link></p>
default:
return <p>拒绝转移<Link to={`/projects/${project && project.owner && project.owner.login}/${project && project.identifier}`}>{project && project.name}</Link>仓库</p>
}
}else{
return ""
}
}
return(
<div>
{
list && list.length > 0 ?
<div>
<ul className="notifyList">
{
list.map((i,k)=>{
return(
<li>
<Link to={`/users/${i.login}`}><img src={getImageUrl(`/${i.applied_user && i.applied_user.image_url}`)} alt="" className="notifyImg"/></Link>
<div className="notifyFlex">
<p className="notifyInfos">
<Link to={`/users/${i.applied_user && i.applied_user.login}`} className="font-15 mr20">{i.applied_user && i.applied_user.name}</Link>
<span className="color-grey-9">{i.time_ago}</span>
</p>
{renderStatus(i.status,i.applied)}
</div>
</li>
)
})
}
</ul>
</div>
:
""
}
{list && list.length === 0 && <Nodata _html="暂无通知" />}
{
total > limit &&
<div className="edu-txt-center pt20 pb20">
<Pagination simple pageSize={limit} total={total} current={page} onChange={(p)=>{setPage(p)}}/>
</div>
}
</div>
)
}
export default Notify;

View File

@ -0,0 +1,118 @@
import React, { useEffect, useState } from "react";
import Nodata from '../Nodata';
import { FlexAJ } from '../Component/layout';
import { Pagination , Popconfirm } from 'antd';
import { Link } from 'react-router-dom';
import { getImageUrl } from 'educoder';
import Axios from 'axios';
const limit = 15;
function UndoEvent(props){
const username = props.match.params.username;
const [ list , setList ] = useState(undefined);
const [ page , setPage ] = useState(1);
const [ total , setTotal ] = useState(0);
useEffect(()=>{
if(username){
getList();
}
},[username,page])
function getList(){
const url = `/users/${username}/applied_transfer_projects.json`;
Axios.get(url,{
params:{
page,per_page:limit
}
}).then(result=>{
if(result){
setList(result.data.applied_transfer_projects);
setTotal(result.data.total_count);
}
}).catch(error=>{})
}
//
function acceptDivert(id){
const url = `/users/${username}/applied_transfer_projects/${id}/accept.json`;
Axios.post(url).then(result=>{
if(result && result.data){
getList();
props && props.fetchUser();
}
}).catch(error=>{})
}
//
function revertDivert(id){
const url = `/users/${username}/applied_transfer_projects/${id}/refuse.json`;
Axios.post(url).then(result=>{
if(result && result.data){
getList();
props && props.fetchUser();
}
}).catch(error=>{})
}
return(
<div>
{
list && list.length > 0 ?
<div>
<ul className="notifyList">
{
list.map((i,k)=>{
return(
<li>
<Link to={`/users/${i.user && i.user.login}`}><img src={getImageUrl(`/${i.user && i.user.image_url}`)} alt="" className="notifyImg"/></Link>
<div className="notifyFlex">
<p className="notifyInfos">
<Link to={`/users/${i.login}`} className="font-15 mr20">{i.user && i.user.name}</Link>
<span className="color-grey-9">{i.time_ago}</span>
</p>
<FlexAJ>
<p className="color-grey-6">请求将仓库<Link to={`/projects/${i.project && i.project.owner && i.project.owner.login}/${i.project && i.project.identifier}`}>{i.project && i.project.name}</Link>
转移给<Link to={`/users/${i.owner && i.owner.login}`}>{i.owner && i.owner.name}</Link>,是否接受</p>
{
i.status === "common" &&
<span>
<Popconfirm title={`确定接受仓库${i.project && i.project.name}`} okText="确定" cancelText="取消" onConfirm={()=>acceptDivert(i.id)}>
<a className="color-blue">接受</a>
</Popconfirm>
<Popconfirm title={`确定拒绝接受仓库${i.project && i.project.name}`} okText="确定" cancelText="取消" onConfirm={()=>revertDivert(i.id)}>
<a className="color-red ml20">拒绝</a>
</Popconfirm>
</span>
}
{
i.status === "canceled" && <span className="color-grey-9">对方已取消转移</span>
}
{
i.status === "accepted" && <span className="color-grey-9">已接受</span>
}
{
i.status === "refused" && <span className="color-grey-9">已拒绝</span>
}
</FlexAJ>
</div>
</li>
)
})
}
</ul>
</div>
:
""
}
{list && list.length === 0 && <Nodata _html="暂无接收信息" />}
{
total > limit &&
<div className="edu-txt-center pt20 pb20">
<Pagination simple pageSize={limit} total={total} current={page} onChange={(p)=>{setPage(p)}}/>
</div>
}
</div>
)
}
export default UndoEvent;

View File

@ -218,7 +218,7 @@ class MilepostDetail extends Component {
</span> </span>
<div className="milepostdiv"> <div className="milepostdiv">
<Link to={`/projects/${owner}/${projectsId}/milestones/${meilid}/edit`} className="topWrapper_btn" style={{ marginRight: 15 }} >编辑里程碑</Link> <Link to={`/projects/${owner}/${projectsId}/milestones/${meilid}/edit`} className="topWrapper_btn" style={{ marginRight: 15 }} >编辑里程碑</Link>
<Link to={`/projects/${owner}/${projectsId}/issues/${meilid}/new`} className="topWrapper_btn">创建任务</Link> <Link to={`/projects/${owner}/${projectsId}/issues/${meilid}/new`} className="topWrapper_btn">创建易修</Link>
</div> </div>
</FlexAJ> </FlexAJ>
</div> </div>

View File

@ -352,12 +352,12 @@ class order extends Component {
if (this.props.checkIfLogin()) { if (this.props.checkIfLogin()) {
return( return(
<Link className="topWrapper_btn ml10" target="_blank" to={`/projects/${owner}/${projectsId}/issues/new`}> <Link className="topWrapper_btn ml10" target="_blank" to={`/projects/${owner}/${projectsId}/issues/new`}>
+&nbsp;创建任务 +&nbsp;创建易修
</Link> </Link>
) )
}else{ }else{
return( return(
<a className="topWrapper_btn ml10" onClick={this.islogin}>+&nbsp;创建任务</a> <a className="topWrapper_btn ml10" onClick={this.islogin}>+&nbsp;创建易修</a>
) )
} }
} }

View File

@ -310,14 +310,14 @@ class order_form extends Component {
<div className="list-right"> <div className="list-right">
<div className="pd20"> <div className="pd20">
<h3 className="mb15"> <h3 className="mb15">
{form_type === "new" ? "新建" :( form_type === "copy" ? "复制" : "编辑")}任务 {form_type === "new" ? "新建" :( form_type === "copy" ? "复制" : "编辑")}易修
</h3> </h3>
<Form.Item> <Form.Item>
{getFieldDecorator("subject", { {getFieldDecorator("subject", {
rules: [ rules: [
{ {
required: true, required: true,
message: "请填写任务标题", message: "请填写易修标题",
}, },
] ]
})(<Input placeholder="标题" size="large" />)} })(<Input placeholder="标题" size="large" />)}

View File

@ -2,6 +2,8 @@ import React, { Component } from "react";
import { Form, Input, Checkbox, Select , Spin } from "antd"; import { Form, Input, Checkbox, Select , Spin } from "antd";
import Title from '../Component/Title'; import Title from '../Component/Title';
import {WhiteBack} from '../Component/layout'; import {WhiteBack} from '../Component/layout';
import DivertModal from '../Divert/DivertModal';
import { Link } from 'react-router-dom';
import axios from "axios"; import axios from "axios";
import "./setting.scss"; import "./setting.scss";
const { TextArea } = Input; const { TextArea } = Input;
@ -13,7 +15,7 @@ const menu = [
{name:"易修 (Issue)",index:"issues"}, {name:"易修 (Issue)",index:"issues"},
{name:"合并请求",index:"pulls"}, {name:"合并请求",index:"pulls"},
{name:"工作流(beta版)",index:"devops"}, {name:"工作流(beta版)",index:"devops"},
{name:"资源库",index:"resources"}, // {name:"资源库",index:"resources"},
{name:"里程碑",index:"versions"}, {name:"里程碑",index:"versions"},
{name:"动态",index:"activity"}, {name:"动态",index:"activity"},
] ]
@ -25,7 +27,9 @@ class Setting extends Component {
LanguageList: undefined, LanguageList: undefined,
private_check: undefined, private_check: undefined,
loading:true, loading:true,
project_units:['home',"activity","code"] project_units:['home',"activity","code"],
divertVisible:false,
is_transfering:undefined,
}; };
} }
@ -73,7 +77,9 @@ class Setting extends Component {
this.setState({ this.setState({
private_check: result.data.private, private_check: result.data.private,
loading:false, loading:false,
project_units:units project_units:units,
transfer:result.data.transfer,
is_transfering:result.data.is_transfering,
}); });
} }
}) })
@ -186,12 +192,55 @@ class Setting extends Component {
}); });
}; };
// 转移仓库
DivertProject=()=>{
this.setState({
divertVisible:true
})
}
// 取消仓库转移
CancelDivertProject=()=>{
this.props.confirm({
content: "是否确认取消将此项目转移给他人?",
onOk: () => {
const { projectsId , owner } = this.props.match.params;
const url = `/${owner}/${projectsId}/applied_transfer_projects/cancel.json`;
axios.post(url).then(result=>{
if(result && result.data){
this.setState({
is_transfering:false
})
}
}).catch(error=>{})
},
});
}
// 确定转移仓库
onSuccess=(owner)=>{
this.setState({
is_transfering:true,
divertVisible:false,
transfer:owner
})
}
render() { render() {
const { getFieldDecorator } = this.props.form; const { getFieldDecorator } = this.props.form;
const { projectsId , owner } = this.props.match.params;
const { projectDetail } = this.props;
const { CategoryList, LanguageList, private_check ,loading } = this.state; const { CategoryList, LanguageList, private_check ,loading , divertVisible , is_transfering, transfer } = this.state;
console.log(transfer);
return ( return (
<div> <div>
<DivertModal
owner={owner}
repo={projectsId}
visible={divertVisible}
onSuccess={this.onSuccess}
onCancel={()=>{this.setState({divertVisible:false})}}
/>
<Spin spinning={loading}> <Spin spinning={loading}>
<WhiteBack> <WhiteBack>
<Title>基本设置</Title> <Title>基本设置</Title>
@ -279,23 +328,48 @@ class Setting extends Component {
{/* 镜像设置部分,暂无接口,先不显示 */} {/* 镜像设置部分,暂无接口,先不显示 */}
{/* <Mirror /> */} {/* <Mirror /> */}
</WhiteBack> </WhiteBack>
<WhiteBack className="dangerousBox mb20"> {
<div> projectDetail && projectDetail.permission && (projectDetail.permission === "Admin" || projectDetail.permission === "Owner")?
<div className="dangerousTitle">危险操作区</div> <WhiteBack className="dangerousBox mb20">
<div className="flex-a-center padding15-10">
<div> <div>
<p className="font-bd font-16">删除本仓库</p> <div className="dangerousTitle">危险操作区</div>
<p className="mt10"> <div className="flex-a-center padding15-10" style={{borderBottom:"1px solid #f9edbe"}}>
删除仓库是永久性的, <div>
无法撤消且删除后与仓库关联的项目/任务/合并请求/版本发布等均会被删除 <p className="font-bd font-16">转移仓库</p>
</p> <p className="mt10">
{
is_transfering ?
<span>此仓库正在转移给
{transfer && <Link to={transfer.type="User"?`/users/${transfer.login}`:`/organize/${transfer.login}`}>{transfer.name}</Link>}
请联系对方接收此仓库</span>
:
`将此仓库转移给其他用户或组织`
}
</p>
</div>
{
is_transfering ?
<a onClick={this.CancelDivertProject} className="red_deleteBtn">取消转移</a>
:
<a onClick={this.DivertProject} className="red_deleteBtn">转移</a>
}
</div>
<div className="flex-a-center padding15-10">
<div>
<p className="font-bd font-16">删除本仓库</p>
<p className="mt10">
删除仓库是永久性的,
无法撤消且删除后与仓库关联的项目/任务/合并请求/版本发布等均会被删除
</p>
</div>
<a onClick={this.deleteProject} className="red_deleteBtn">
删除本仓库
</a>
</div>
</div> </div>
<a onClick={this.deleteProject} className="red_deleteBtn"> </WhiteBack>
删除本仓库 :""
</a> }
</div>
</div>
</WhiteBack>
</Spin> </Spin>
</div> </div>
); );

View File

@ -84,11 +84,12 @@ export default ((props) => {
// //
function removeUser(username) { function removeUser(username) {
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users/${username}.json`;
if (username) { if (username) {
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users/quit.json`;
axios.delete(url).then((result) => { axios.delete(url).then((result) => {
if (result && result.data) { if (result && result.data) {
props.showNotification(`已成功退出团队!`);
props.history.push(`/organize/${OIdentifier}`);
} }
}).catch((error) => { }); }).catch((error) => { });
} }

View File

@ -7,7 +7,7 @@ function ListItem({item,key,OIdentifier}) {
<div className="team_project" key={key}> <div className="team_project" key={key}>
<p className="t_p_title"> <p className="t_p_title">
<span className="flex1"> <span className="flex1">
<Link to={`/projects/${OIdentifier}/${item.identifier}`} className="name">{item.identifier}</Link> <Link to={`/projects/${OIdentifier}/${item.identifier}`} className="name">{item.name}</Link>
{ item.forked_from_project_id && <i className="iconfont icon-fork font-18 color-orange ml8" /> } { item.forked_from_project_id && <i className="iconfont icon-fork font-18 color-orange ml8" /> }
{ {
item.type && item.type !== 0 ? item.type && item.type !== 0 ?

View File

@ -41,8 +41,8 @@ const FanUser = Loadable({
loading: Loading, loading: Loading,
}) })
const UndoEvents = Loadable({ const Notice = Loadable({
loader: () => import("./undo_events"), loader: () => import("../Notice/Index"),
loading: Loading, loading: Loading,
}) })
class Infos extends Component { class Infos extends Component {
@ -52,7 +52,9 @@ class Infos extends Component {
isSpin: false, isSpin: false,
user: undefined, user: undefined,
project_type: undefined, project_type: undefined,
route_type: undefined route_type: undefined,
undo_events:0,
undo_messages:0
}; };
} }
@ -73,14 +75,22 @@ class Infos extends Component {
}); });
const { current_user } = this.props; const { current_user } = this.props;
const { username } = this.props.match.params; const { username } = this.props.match.params;
const { pathname } = this.props.location;
const { notice } = this.state;
let url = `/users/${username || (current_user && current_user.login)}.json`; let url = `/users/${username || (current_user && current_user.login)}.json`;
axios axios
.get(url) .get(url)
.then((result) => { .then((result) => {
let e = result.data && result.data.undo_events;
let p = result.data && result.data.undo_messages;
let n = notice || pathname === `/users/${username}/notice` ;
this.setState({ this.setState({
user: result.data, user: result.data,
isSpin: false, isSpin: false,
undo_events:n ? (e-p) : e,
undo_messages:0,
notice:n
}); });
}) })
.catch((error) => { .catch((error) => {
@ -114,11 +124,15 @@ class Infos extends Component {
} }
undo_link = () => { undo_link = () => {
const {user} = this.state const {user } = this.state;
this.setState({ this.setState({
route_type: undefined route_type: undefined,
project_type:"notice",
notice:true
},()=>{
this.props.history.push(`/users/${user && user.login}/notice`);
this.fetchUser();
}) })
this.props.history.push(`/users/${user && user.login}/undo_events`)
} }
route_link = (type) => { route_link = (type) => {
@ -130,7 +144,8 @@ class Infos extends Component {
organize_link = () => { organize_link = () => {
const {user} = this.state const {user} = this.state
this.setState({ this.setState({
route_type: undefined route_type: undefined,
project_type:"organizes"
}) })
this.props.history.push(`/users/${user && user.login}/organizes`) this.props.history.push(`/users/${user && user.login}/organizes`)
} }
@ -140,7 +155,7 @@ class Infos extends Component {
const { current_user, mygetHelmetapi } = this.props; const { current_user, mygetHelmetapi } = this.props;
const { username } = this.props.match.params; const { username } = this.props.match.params;
const { user, isSpin, project_type, route_type } = this.state; const { user, isSpin, project_type, route_type , undo_events , undo_messages } = this.state;
return ( return (
<div className="newMain clearfix"> <div className="newMain clearfix">
<Spin spinning={isSpin}> <Spin spinning={isSpin}>
@ -211,21 +226,23 @@ class Infos extends Component {
</div> </div>
</div> </div>
</div> </div>
{/* {current_user && user && current_user.id === user.id && ( {current_user && user && user.login === current_user.login ? (
<div className="bgcF"> <div className="bgcF">
<div className="list-l-Menu"> <div className="list-l-Menu">
<p className="list-l-p pd20" onClick={() => this.undo_link()}> <li className={project_type && project_type === "notice" ? "active" : ""}>
<span className="font-16 color-grey-3"> <p onClick={() => this.undo_link()}>
<i className="iconfont icon-dahuizhongzuo3x font-15 mr5"></i> <span className="font-16 color-grey-3">
待办事项 <i className="iconfont icon-dahuizhongzuo3x font-15 mr5"></i>
</span> 待办事项
<span className="text-yellow font-16"> </span>
{user.undo_events} <span className="text-yellow font-16">
</span> {undo_events}
</p> </span>
</p>
</li>
</div> </div>
</div> </div>
)} */} ):""}
<div className="bgcF"> <div className="bgcF">
<ul className="list-l-Menu"> <ul className="list-l-Menu">
@ -285,19 +302,19 @@ class Infos extends Component {
</ul> </ul>
</div> </div>
} }
<div className="bgcF"> <div className="bgcF">
<div className="list-l-Menu"> <div className="list-l-Menu">
<p className="list-l-p pd20" onClick={() => this.organize_link()} > <li className={project_type && project_type === "organizes" ? "active" : ""}>
<span className="font-16 color-grey-3"> <p onClick={() => this.organize_link()} >
<i className="iconfont icon-itsm-liuchengguanli font-15 mr5"></i> <span className="font-16 color-grey-3">
组织 <i className="iconfont icon-itsm-liuchengguanli font-15 mr5"></i>
</span> 组织
<span className="color-blue font-16"> </span>
{user && user.user_org_count} <span className="color-blue font-16">
</span> {user && user.user_org_count}
</p> </span>
</p>
</li>
</div> </div>
</div> </div>
</div> </div>
@ -312,9 +329,9 @@ class Infos extends Component {
}} }}
></Route> ></Route>
<Route <Route
path="/users/:username/undo_events" path="/users/:username/notice"
render={() => { render={() => {
return <UndoEvents {...this.props} {...this.state} />; return <Notice {...this.props} {...this.state} fetchUser={this.fetchUser}/>;
}} }}
></Route> ></Route>
<Route <Route

View File

@ -1,16 +0,0 @@
import React, { Component } from "react";
import Nodata from "../Nodata";
class UndoEvents extends Component {
render() {
return (
<div className="pd20">
<div className="grid-item pb20 bbt">
<h3>待办事项</h3>
</div>
<Nodata _html={`暂时没有数据~`} />
</div>
);
}
}
export default UndoEvents;

View File

@ -1062,7 +1062,7 @@ class TPMBanner extends Component {
</div> : </div> :
<div className="task-popup-content"> <div className="task-popup-content">
<p className="task-popup-text-center font-16 mt10 mb10"> <p className="task-popup-text-center font-16 mt10 mb10">
尚未创建任务的实训不能申请发布 尚未创建易修的实训不能申请发布
</p> </p>
</div> </div>
} }