forked from Gitlink/forgeplus-react
1051 lines
37 KiB
JavaScript
1051 lines
37 KiB
JavaScript
import React, { Component } from 'react';
|
||
import { Spin, Tooltip , Button } from 'antd';
|
||
import { Link, Route, Switch } from 'react-router-dom';
|
||
import { withRouter } from "react-router";
|
||
import { connect } from 'react-redux';
|
||
import { Content, AlignTop } from '../Component/layout';
|
||
import DetailBanner from './sub/DetailBanner';
|
||
import CoderDepot from './CoderDepot'
|
||
import cookie from 'react-cookies';
|
||
import { setSeoMeta } from 'educoder';
|
||
import { Base64 } from 'js-base64';
|
||
import { setProject, setProjectDetail, setProjectEntries, setProjectMenuList, setProjectReadMe } from '../../redux/actions/server';
|
||
import actions from '../../redux/actions';
|
||
import types from '../../redux/actions/actionTypes'
|
||
import { getProjectFunc, getProjectDetailFunc } from '../../services/project'
|
||
import '../css/index.scss'
|
||
import './list.scss';
|
||
import '../../modules/courses/css/Courses.css'
|
||
import { ImageLayerOfCommentHOC } from "../../modules/page/layers/ImageLayerOfCommentHOC";
|
||
import { unInstallMarketBot } from "../../softbot/api";
|
||
|
||
|
||
import Loadable from 'react-loadable';
|
||
import Loading from '../../Loading';
|
||
|
||
import axios from 'axios';
|
||
import { async } from 'q';
|
||
|
||
const Setting = Loadable({
|
||
loader: () => import('../Settings/Index'),
|
||
loading: Loading,
|
||
})
|
||
const OrderIndex = Loadable({
|
||
loader: () => import('../Issues/index'),
|
||
loading: Loading,
|
||
})
|
||
const CoderRootIndex = Loadable({
|
||
loader: () => import('./CoderRootIndex'),
|
||
loading: Loading,
|
||
})
|
||
const OrderMilepost = Loadable({
|
||
loader: () => import('../Order/Milepost'),
|
||
loading: Loading,
|
||
})
|
||
|
||
const OrdernewMilepost = Loadable({
|
||
loader: () => import('../Order/newMilepost'),
|
||
loading: Loading,
|
||
})
|
||
|
||
const OrderupdateMilepost = Loadable({
|
||
loader: () => import('../Order/UpdateMilepost'),
|
||
loading: Loading,
|
||
})
|
||
//合并请求
|
||
const MergeIndexDetail = Loadable({
|
||
loader: () => import('../Merge/merge'),
|
||
loading: Loading,
|
||
})
|
||
|
||
const CreateMerge = Loadable({
|
||
loader: () => import('../Merge/CreateMerge'),
|
||
loading: Loading,
|
||
})
|
||
|
||
const MessageCount = Loadable({
|
||
loader: () => import('../Merge/MessageCount'),
|
||
loading: Loading,
|
||
})
|
||
|
||
const UpdateMerge = Loadable({
|
||
loader: () => import('../Merge/UpdateMerge'),
|
||
loading: Loading,
|
||
})
|
||
|
||
const MilepostDetail = Loadable({
|
||
loader: () => import('../Order/MilepostDetail.jsx'),
|
||
loading: Loading,
|
||
})
|
||
const WatchUsers = Loadable({
|
||
loader: () => import('../UsersList/watch_users'),
|
||
loading: Loading,
|
||
})
|
||
const PraiseUsers = Loadable({
|
||
loader: () => import('../UsersList/praise_users'),
|
||
loading: Loading,
|
||
})
|
||
const ForkUsers = Loadable({
|
||
loader: () => import('../UsersList/fork_users'),
|
||
loading: Loading,
|
||
})
|
||
const Contribute = Loadable({
|
||
loader: () => import('./sub/Contribute'),
|
||
loading: Loading,
|
||
})
|
||
|
||
const CoderRootCommit = Loadable({
|
||
loader: () => import('./CoderRootCommit'),
|
||
loading: Loading,
|
||
})
|
||
// const CoderDepot = Loadable({
|
||
// loader: () => import('./CoderDepot'),
|
||
// loading: Loading,
|
||
// })
|
||
|
||
const TrendsIndex = Loadable({
|
||
loader: () => import('../Activity/Activity'),
|
||
loading: Loading,
|
||
})
|
||
const DataSetIndex = Loadable({
|
||
loader: () => import('../Dataset/Index'),
|
||
loading: Loading,
|
||
})
|
||
const DataSetUpload = Loadable({
|
||
loader: () => import('../Dataset/component/uploadModal'),
|
||
loading: Loading,
|
||
})
|
||
const DevAbout = Loadable({
|
||
loader: () => import('../About/Index'),
|
||
loading: Loading,
|
||
})
|
||
const Source = Loadable({
|
||
loader: () => import('../Source/Index'),
|
||
loading: Loading,
|
||
})
|
||
const Server = Loadable({
|
||
loader: () => import('../Server/Index'),
|
||
loading: Loading,
|
||
})
|
||
const DevIndex = Loadable({
|
||
loader: () => import('../DevOps/Index'),
|
||
loading: Loading,
|
||
});
|
||
const Wiki = Loadable({
|
||
loader: () => import('../Wiki/page/index'),
|
||
loading: Loading,
|
||
});
|
||
const WikiHisList = Loadable({
|
||
loader: () => import('../Wiki/page/historyList'),
|
||
loading: Loading,
|
||
});
|
||
const WikiEdit = Loadable({
|
||
loader: () => import('../Wiki/page/edit'),
|
||
loading: Loading,
|
||
});
|
||
const Invite = Loadable({
|
||
loader: () => import('../Invite/Index'),
|
||
loading: Loading,
|
||
});
|
||
const Review = Loadable({
|
||
loader: () => import('../Newfile/codeReview'),
|
||
loading: Loading,
|
||
});
|
||
const DevopsCard = Loadable({
|
||
loader: () => import('../DevOps/cardList'),
|
||
loading: Loading,
|
||
});
|
||
/**
|
||
* permission:Manager:管理员,Reporter:报告人员(只有读取权限),Developer:开发人员(除不能设置仓库信息外)
|
||
*/
|
||
function checkPathname(projectsId, owner, pathname) {
|
||
let name = "";
|
||
if (pathname && pathname !== `/${owner}/${projectsId}`) {
|
||
let url = pathname.split(`/${owner}/${projectsId}`)[1] || "";
|
||
if (url.indexOf("/about") > -1) {
|
||
name = "about"
|
||
} else if (url.indexOf("/issues") > -1 || url.indexOf("Milepost") > 0) {
|
||
name = "issues";
|
||
} else if (url.indexOf("/pulls") > -1 || url.indexOf("/compare") > -1) {
|
||
// /pulls,合并请求除新建合并请求外,
|
||
// /compare,新建合并请求
|
||
name = "pulls"
|
||
} else if (url.indexOf("/milestones") > -1) {
|
||
name = "milestones"
|
||
} else if (url.indexOf("/activity") > -1) {
|
||
name = "activity"
|
||
} else if (url.indexOf("/settings") > -1) {
|
||
name = "settings"
|
||
} else if (url.indexOf("/dataset") > -1) {
|
||
name = "dataset"
|
||
} else if (url.indexOf(`/devops`) > -1) {
|
||
name = "devops"
|
||
} else if (url.indexOf(`/actions`) > -1) {
|
||
name = "devops"
|
||
} else if (url.indexOf(`/source`) > -1) {
|
||
name = "source"
|
||
} else if (url.indexOf(`/wiki`) > -1) {
|
||
name = "wiki"
|
||
} else if (url.indexOf(`/service`) > -1) {
|
||
name = "server"
|
||
}
|
||
}
|
||
return name;
|
||
}
|
||
|
||
class Detail extends Component {
|
||
constructor(props) {
|
||
super(props);
|
||
this.state = {
|
||
projectDetail: props.defaultDetail || undefined,
|
||
isManager: false,
|
||
isReporter: false,
|
||
isDeveloper: false,
|
||
project_id: undefined,
|
||
watchers_count: undefined,
|
||
praises_count: undefined,
|
||
forked_count: undefined,
|
||
watched: false,
|
||
praised: false,
|
||
http_url: undefined,
|
||
branchs: undefined,
|
||
branchList: undefined,
|
||
project: props.projectBase || undefined,
|
||
firstSync: false,
|
||
secondSync: false,
|
||
open_devops: false,
|
||
forkSpin: false,
|
||
// 默认分支
|
||
defaultBranch: undefined,
|
||
|
||
// 非本平台项目
|
||
platform: true,
|
||
mirror_status:0,
|
||
bannerList: props.projectMenu || []
|
||
}
|
||
}
|
||
|
||
|
||
componentDidMount=()=>{
|
||
let history = this.props.location;
|
||
this.clearIssueCookies(history);
|
||
if (this.props.clearProject) {
|
||
const typeList = [ types.GET_PROJECT_BASE, types.GET_PROJECT_DETAIL, types.GET_PROJECT_ENTRIES, types.GET_PROJECT_MENU, types.GET_PROJECT_README ]
|
||
typeList.forEach(e => {
|
||
this.props.clearProject(e)
|
||
})
|
||
}
|
||
}
|
||
|
||
|
||
componentDidUpdate = async (prevState) => {
|
||
let prevParam = prevState.match.params;
|
||
let propsParam = this.props.match.params;
|
||
if (prevState && this.props && (prevParam.projectsId !== propsParam.projectsId || prevParam.owner !== propsParam.owner)) {
|
||
const { projectsId, owner } = this.props.match.params;
|
||
const data = await getProjectFunc(owner, projectsId);
|
||
if (data.data) {
|
||
this.getProject(data.data)
|
||
}
|
||
}
|
||
|
||
this.props.history.listen((history) => {
|
||
// 非issue链接地址清除cookie states,具体保存和操作在order.js页面
|
||
this.clearIssueCookies(history);
|
||
})
|
||
}
|
||
|
||
clearIssueCookies = (history) => {
|
||
const { pathname } = history;
|
||
const { projectsId, owner } = this.props.match.params;
|
||
let currentIssue = pathname.indexOf(`/${owner}/${projectsId}/issues`) === -1;
|
||
if (currentIssue) {
|
||
cookie.save('states', undefined, { expires: 0, path: `/` });
|
||
cookie.save('issuestates', undefined, { expires: 0, path: `/` });
|
||
}
|
||
}
|
||
async componentWillMount() {
|
||
const { projectsId, owner } = this.props.match.params;
|
||
if (!this.props.projectBase) {
|
||
const data = await getProjectFunc(owner, projectsId);
|
||
if (data && data.data) {
|
||
this.getProject(data.data)
|
||
}
|
||
} else {
|
||
this.getProject(this.props.projectBase)
|
||
}
|
||
}
|
||
componentWillUnmount() {
|
||
this.timerChannel && clearTimeout(this.timerChannel);
|
||
}
|
||
|
||
getProject = async (data) => {
|
||
const { projectsId, owner } = this.props.match.params;
|
||
this.setState({
|
||
project: data,
|
||
open_devops: data.open_devops,
|
||
platform: data.platform && data.platform !== 'educoder'
|
||
})
|
||
if (data.type !== 0 && data.mirror_status === 1) {
|
||
console.log("--------start channel --------");
|
||
this.setState({
|
||
firstSync: true,
|
||
secondSync: false,
|
||
mirror_status:1
|
||
})
|
||
// 是镜像项目,且未完成迁移
|
||
this.canvasChannel();
|
||
} else {
|
||
this.setState({
|
||
firstSync: false,
|
||
secondSync: false,
|
||
mirror_status:data.mirror_status || 0
|
||
})
|
||
this.getBanner(this.props.projectMenu)
|
||
let projectdata
|
||
if (this.props.defaultDetail) {
|
||
projectdata = this.props.defaultDetail
|
||
} else {
|
||
const res = await getProjectDetailFunc(owner, projectsId, !window.location.host);
|
||
if (res && res.status === 200) {
|
||
projectdata = res.data
|
||
}
|
||
}
|
||
if (projectdata) {
|
||
this.getDetail(projectdata)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 工作流激活后修改状态
|
||
changeOpenDevops = (flag) => {
|
||
this.setState({
|
||
open_devops: flag
|
||
})
|
||
}
|
||
/**
|
||
*
|
||
* @param {*} deleteFlag :同步镜像需要提示成功,且未成功的情况下不需要删除项目
|
||
*/
|
||
canvasChannel = (deleteFlag) => {
|
||
const name = window.location.hostname === "localhost" ? "testforgeplus.trustie.net" : window.location.hostname;
|
||
const actioncable = require("actioncable");
|
||
var project = this.state.project;
|
||
var cable = actioncable.createConsumer(`wss://${name}/cable`);
|
||
this.canvasChannel1 = cable.subscriptions.create({
|
||
channel: `MirrorProjectChannel`,
|
||
id: project && project.id
|
||
}, {
|
||
connected: () => {
|
||
console.log("###### channel connected! ######");
|
||
},
|
||
disconnected: () => {
|
||
console.log("###### cannot connected! ######");
|
||
},
|
||
received: async data => {
|
||
console.log(`###### ---received data--- ######`);
|
||
if (data) {
|
||
console.log("start ----",data)
|
||
if (deleteFlag) {
|
||
this.setState({
|
||
firstSync: false,
|
||
mirror_status:data.project && data.project.mirror_status,
|
||
secondSync: false
|
||
});
|
||
this.props.showNotification("镜像同步成功!");
|
||
window.location.reload();
|
||
}
|
||
// else {
|
||
if (data.status === -1) {
|
||
// this.deleteProjectBack();
|
||
// const projectdata = await getProjectDetailFunc(owner, projectsId, !window.location.host).data;
|
||
// this.getDetail(projectdata)
|
||
// this.getBanner();
|
||
this.toMirrorFunc();
|
||
}
|
||
// }
|
||
// this.reloadDetail();
|
||
cable.subscriptions.consumer.disconnect();
|
||
}
|
||
},
|
||
onerror: () => {
|
||
console.log("###### cannot connected! ######");
|
||
}
|
||
});
|
||
|
||
// 如果是火狐,由于部分版本ws不能连接成功,故增加刷新
|
||
// if(navigator.userAgent.indexOf("Firefox")>-1){
|
||
this.timerChannel = setTimeout(this.reloadDetail, 10000);
|
||
// }
|
||
}
|
||
|
||
reloadDetail = () => {
|
||
if (this.state.firstSync || this.state.secondSync) {
|
||
window.location.reload();
|
||
}
|
||
}
|
||
|
||
toMirrorFunc=()=>{
|
||
let hash = '/projects/mirror/new';
|
||
this.props.history.push({
|
||
pathname: hash,
|
||
mirror_status: 2
|
||
});
|
||
}
|
||
|
||
|
||
// deleteProjectBack = () => {
|
||
// const { history } = this.props;
|
||
// const { projectsId, owner } = this.props.match.params;
|
||
// axios.delete(`/${owner}/${projectsId}.json`).then(res => {
|
||
// let hash = '/projects/mirror/new';
|
||
// if (res && res.data) {
|
||
// history.push({
|
||
// pathname: hash,
|
||
// mirror_status: 2
|
||
// });
|
||
// }
|
||
// else {
|
||
// window.location.hash = hash;
|
||
// }
|
||
// });
|
||
// }
|
||
|
||
getDetail = async (data) => {
|
||
const { projectsId, owner } = this.props.match.params;
|
||
if (!data) {
|
||
const url = `/${owner}/${projectsId}/detail.json`;
|
||
const res = await axios.get(url)
|
||
if (res.data) {
|
||
data = res.data
|
||
}
|
||
}
|
||
if (data) {
|
||
if (data.status === 404) {
|
||
if (window.location.pathname.includes('/invite')) {
|
||
let inviteString = window.location.search && window.location.search.split('?invite=')[1];
|
||
let inviteData = inviteString && JSON.parse(Base64.decode(inviteString));
|
||
const { project = {}, projectDetail = {} } = this.state
|
||
this.setState({
|
||
project: Object.assign(project, { author: { name: inviteData.ownerName } }),
|
||
projectDetail: Object.assign(projectDetail, { name: inviteData.projectName })
|
||
});
|
||
} else {
|
||
this.props.history.push('/nopage');
|
||
}
|
||
} else {
|
||
this.setState({
|
||
projectDetail: data,
|
||
project_id: data.project_id,
|
||
isManager: data.permission && (data.permission === "Manager" || data.permission === "Admin" || data.permission === "Owner"),
|
||
isReporter: data.permission && data.permission === "Reporter",
|
||
isDeveloper: data.permission && data.permission === "Developer",
|
||
http_url: data.clone_url,
|
||
praised: data.praised,
|
||
watched: data.watched,
|
||
watchers_count: data.watchers_count,
|
||
praises_count: data.praises_count,
|
||
forked_count: data.forked_count,
|
||
defaultBranch: data.default_branch
|
||
});
|
||
// seo优化设置
|
||
let keyWords=`${owner},${projectsId}${ data.topics && data.topics.length > 0 && ','}${ data.topics && data.topics.length > 0 && data.topics.map(item => item.name).join(',') }`;
|
||
let title= `${owner}/${projectsId}${data.description?':'+data.description:''}`;
|
||
setSeoMeta(keyWords,title,data.description || '',`/${owner}/${projectsId}`,owner,projectsId);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 获取动态导航栏菜单
|
||
async getBanner(data) {
|
||
const { projectsId, owner } = this.props.match.params;
|
||
const url = `/${owner}/${projectsId}/menu_list.json`;
|
||
axios.get(url).then(res=>{
|
||
if(res && res.data){
|
||
this.setState({
|
||
bannerList: res.data
|
||
})
|
||
}
|
||
})
|
||
// if (!data) {
|
||
// const url = `/${owner}/${projectsId}/menu_list.json`;
|
||
// axios.get(url).then(res=>{
|
||
// if(res && res.data){
|
||
// this.setState({
|
||
// bannerList: res.data
|
||
// })
|
||
// }
|
||
// })
|
||
// }else{
|
||
// this.setState({
|
||
// bannerList: data
|
||
// })
|
||
// }
|
||
}
|
||
|
||
// 关注和取消关注
|
||
focusFunc = (flag) => {
|
||
const { platform } = this.state;
|
||
if (!platform) return;
|
||
|
||
const { project_id } = this.state;
|
||
axios({
|
||
method: flag ? 'delete' : 'post',
|
||
url: `/watchers/${flag ? 'unfollow' : 'follow'}.json`,
|
||
params: {
|
||
target_type: "project",
|
||
id: project_id
|
||
}
|
||
}).then(result => {
|
||
if (result && result.data.status === 0) {
|
||
this.setWatchersCount(result.data.watchers_count, result.data.watched);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.log(error);
|
||
});
|
||
!flag && this.props.showNpsModal("indexProject", 1);
|
||
}
|
||
|
||
// 点赞和取消点赞
|
||
pariseFunc = (flag) => {
|
||
const { platform } = this.state;
|
||
if (!platform) return;
|
||
const { project_id } = this.state;
|
||
axios({
|
||
method: flag ? 'delete' : 'post',
|
||
url: `/projects/${project_id}/praise_tread/${flag ? 'unlike' : 'like'}.json`
|
||
}).then(result => {
|
||
if (result && result.data.status === 0) {
|
||
this.setPraisesCount(result.data.praises_count, result.data.praised)
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.log(error);
|
||
});
|
||
!flag && this.props.showNpsModal("indexProject", 2);
|
||
}
|
||
|
||
setWatchersCount = (count, is_watched) => {
|
||
this.setState({
|
||
watched: is_watched,
|
||
watchers_count: count
|
||
})
|
||
}
|
||
|
||
setPraisesCount = (count, is_praised) => {
|
||
this.setState({
|
||
praised: is_praised,
|
||
praises_count: count
|
||
})
|
||
}
|
||
|
||
// fork项目
|
||
forkFunc = () => {
|
||
const { platform } = this.state;
|
||
if (!platform) return;
|
||
this.setState({
|
||
forkSpin: true
|
||
})
|
||
const { current_user } = this.props
|
||
const { projectsId, owner } = this.props.match.params;
|
||
const url = `/${owner}/${projectsId}/forks.json`;
|
||
axios.post(url).then(result => {
|
||
if (result && result.data.status === 0) {
|
||
this.props.showNotification(result.data.message);
|
||
if (result.data.message && result.data.message.indexOf("fork失败")>-1) {
|
||
// fork失败,已经fork过,跳转到fork的仓库
|
||
this.props.history.push(`/${current_user && current_user.login}/${projectsId}`);
|
||
return;
|
||
}
|
||
this.props.history.push(`/${current_user && current_user.login}/${result.data.identifier}`);
|
||
|
||
this.props.showNpsModal("indexProject", 3);
|
||
}
|
||
this.setState({
|
||
forkSpin: false
|
||
})
|
||
}).catch(error => {
|
||
this.setState({
|
||
forkSpin: false
|
||
})
|
||
})
|
||
}
|
||
|
||
// 同步镜像
|
||
synchronismMirror = () => {
|
||
const { isManager } = this.state;
|
||
const { current_user , showLoginDialog } = this.props;
|
||
if(!(current_user && current_user.login)){
|
||
showLoginDialog();
|
||
return
|
||
}
|
||
if((current_user && current_user.admin) || isManager){
|
||
const { platform } = this.state;
|
||
if (!platform) return;
|
||
const { projectsId, owner } = this.props.match.params;
|
||
const url = `/${owner}/${projectsId}/sync_mirror.json`;
|
||
axios.post(url).then(result => {
|
||
if (result && result.data && result.data.status === 0) {
|
||
this.setState({
|
||
secondSync: true
|
||
})
|
||
this.canvasChannel(true);
|
||
} else {
|
||
this.props.showNotification("镜像同步失败!");
|
||
}
|
||
}).catch(error => {
|
||
console.log(error);
|
||
})
|
||
}
|
||
}
|
||
|
||
textFunc = (forked_from_project_id, fork_info) => {
|
||
return forked_from_project_id && fork_info ?
|
||
<div className="color-grey-9 df">
|
||
<span>复刻自</span>
|
||
<Link to={`/${fork_info.fork_project_user_login}`} className="show-user-link color-grey-6 ml5">{fork_info.fork_project_user_name}</Link>
|
||
<span> / </span>
|
||
<Link to={`/${fork_info.fork_project_user_login}/${fork_info.fork_project_identifier}`} className="color-grey-6 task-hide flex1" style={{ maxWidth: "400px" }} title={fork_info.fork_form_name}>{fork_info.fork_form_name}</Link>
|
||
</div> : ""
|
||
}
|
||
|
||
// 删除仓库
|
||
deleteProject = () => {
|
||
const { projectsId , owner } = this.props.match.params;
|
||
const { projectName } = this.state;
|
||
this.props.confirm({
|
||
content: <span style={{display:"block",textAlign:"left"}}>该操作无法撤销!且将会一并删除相关的疑修、合并请求、工作流、里程碑、动态等数据。<br/>是否确认删除 <span style={{fontWeight:"bold"}}>{owner}/{projectName}({projectsId})</span>?</span>,
|
||
onOk: () => {
|
||
const url = `/${owner}/${projectsId}.json`;
|
||
axios.delete(url).then((result) => {
|
||
window.scrollTo(0,0);
|
||
this.props.showNotification("仓库删除成功!");
|
||
this.props.history.push(`/${owner}`);
|
||
})
|
||
.catch((error) => {
|
||
console.log(error);
|
||
});
|
||
},
|
||
});
|
||
};
|
||
|
||
render() {
|
||
const { projectDetail, watchers_count, praises_count,
|
||
forked_count, firstSync, secondSync, watched, praised,
|
||
project, open_devops, platform, defaultBranch, bannerList, forkSpin , mirror_status } = this.state;
|
||
const url = this.props.history.location.pathname;
|
||
const urlArr = url.split("/");
|
||
const urlFlag = (urlArr.length === 3);
|
||
|
||
const { projectsId, owner } = this.props.match.params;
|
||
const { current_user } = this.props;
|
||
let pathname = checkPathname(projectsId, owner, url);
|
||
|
||
const { state } = this.props.history.location;
|
||
const common = {
|
||
getDetail: this.getDetail,
|
||
getBanner: this.getBanner,
|
||
getProject:this.getProject,
|
||
changeOpenDevops: this.changeOpenDevops,
|
||
defaultBranch
|
||
}
|
||
return (
|
||
<div>
|
||
<div className="detailHeader-wrapper">
|
||
<div className="normal">
|
||
<div className="AlignTop" style={{ padding: "18px 0px 10px", justifyContent: "space-between" }}>
|
||
<div>
|
||
<div className="AlignTop">
|
||
<div className="projectallName">
|
||
{project && project.author &&
|
||
<Link to={`/${project.author.login}`}>{project.author.name}</Link>
|
||
}
|
||
<span className="ml5 mr5">/</span>
|
||
<Link to={`/${owner}/${projectsId}`} className="projectN mt6">{projectDetail && projectDetail.name}</Link>
|
||
</div>
|
||
{projectDetail && projectDetail.private && <span className="privateTag mt6">私有</span>}
|
||
{!platform && <span className="privateTag red mt6">只读</span>}
|
||
</div>
|
||
<div className="mt8">
|
||
{
|
||
projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ?
|
||
this.textFunc(projectDetail.forked_from_project_id, projectDetail.fork_info)
|
||
: ""
|
||
}
|
||
</div>
|
||
</div>
|
||
<div>
|
||
{
|
||
firstSync ? "" :
|
||
<span className="df">
|
||
{
|
||
(projectDetail && projectDetail.type && projectDetail.type === 2) ?
|
||
<a className="synchronism ml30" onClick={this.synchronismMirror}>同步镜像</a> : ""
|
||
}
|
||
<span className="detail_tag_btn">
|
||
<a className="detail_tag_btn_name" style={{ cursor: platform ? "pointer" : "default" }} onClick={() => this.focusFunc(watched)}>
|
||
<i className={watched ? "iconfont icon-yiguanzhuicon color-orange font-16 mr3" : "iconfont icon-guanzhuicon color-grey-9 font-16 mr3"}></i>
|
||
<span>{watched ? '取消关注' : '关注'}</span>
|
||
</a>
|
||
{
|
||
watchers_count > 0 ?
|
||
platform ?
|
||
<Link className="detail_tag_btn_count" style={{ color: `#666` }} to={platform ? { pathname: `/${owner}/${projectsId}/following`, state } : ""}>
|
||
{watchers_count}
|
||
</Link>
|
||
:
|
||
<span className="detail_tag_btn_count">{watchers_count}</span>
|
||
: ""
|
||
}
|
||
</span>
|
||
<span className="detail_tag_btn">
|
||
<a className="detail_tag_btn_name" style={{ cursor: platform ? "pointer" : "default" }} onClick={() => this.pariseFunc(praised)}>
|
||
<i className={praised ? "iconfont icon-yidianzan_icon color-orange font-15 mr3" : "iconfont icon-xingzhuang color-grey-9 font-14 mr3"}></i>
|
||
<span>{praised ? '取消点赞' : '点赞'}</span>
|
||
</a>
|
||
{
|
||
praises_count > 0 ?
|
||
platform ?
|
||
<Link className="detail_tag_btn_count" style={{ color: `#666` }} to={{ pathname: `/${owner}/${projectsId}/stargazers`, state }}>
|
||
{praises_count}
|
||
</Link> :
|
||
<span className="detail_tag_btn_count">{praises_count}</span>
|
||
: ""
|
||
}
|
||
</span>
|
||
<span className="detail_tag_btn" loading={forkSpin}>
|
||
<Tooltip title="复刻是fork的中文名,即复制代码仓库" placement="bottom">
|
||
<a className="detail_tag_btn_name" style={{ cursor: platform ? "pointer" : "default" }} onClick={this.forkFunc}>
|
||
<i className="iconfont icon-morenfuke_icon1 color-grey-9 mr3 font-16"></i><span>复刻(Fork)</span>
|
||
</a>
|
||
</Tooltip>
|
||
{
|
||
forked_count > 0 ?
|
||
platform ?
|
||
<Link className="detail_tag_btn_count" to={{ pathname: `/${owner}/${projectsId}/members`, state }}>
|
||
{forked_count}
|
||
</Link>
|
||
:
|
||
<span className="detail_tag_btn_count">{forked_count}</span>
|
||
: ""
|
||
}
|
||
</span>
|
||
</span>
|
||
}
|
||
</div>
|
||
</div>
|
||
{/* <div className="mt6" style={{minHeight:"20px"}}>
|
||
{
|
||
projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ?
|
||
this.textFunc(projectDetail.forked_from_project_id,projectDetail.fork_info)
|
||
:""
|
||
}
|
||
{
|
||
projectDetail && projectDetail.type && projectDetail.type !== 0 ?
|
||
<span className="color-grey-9">镜像自 <a className="color-blue hoverLine" target="_blank" href={projectDetail.mirror_url}>{projectDetail.mirror_url}</a></span>
|
||
:""
|
||
}
|
||
</div> */}
|
||
{
|
||
firstSync ? "" :
|
||
<DetailBanner
|
||
history={this.props.history}
|
||
list={bannerList}
|
||
owner={owner}
|
||
projectsId={projectsId}
|
||
pathname={pathname}
|
||
state={state}
|
||
projectDetail={projectDetail}
|
||
open_devops={open_devops}
|
||
platform={platform}
|
||
urlFlag={urlFlag}
|
||
showNotification={this.props.showNotification}
|
||
current_user={current_user}
|
||
showNpsModal={this.props.showNpsModal}
|
||
/>
|
||
}
|
||
</div>
|
||
</div>
|
||
{
|
||
firstSync &&
|
||
<Content className="spincontent">
|
||
<Spin className="spinstyle" tip={project && `正在从 ${project.mirror_url} 迁移`} size="large" />
|
||
<Button className="red_deleteBtn mt30" onClick={this.deleteProject}>
|
||
删除本仓库
|
||
</Button>
|
||
</Content>
|
||
}
|
||
<Spin spinning={secondSync && !firstSync} className="spinstyle" tip="正在同步镜像" size="large">
|
||
{/* mirror_status = 1的情况不显示项目详情子模块 */}
|
||
{!firstSync && <Switch {...this.props}>
|
||
{/* 服务 */}
|
||
<Route path="/:owner/:projectsId/service"
|
||
render={
|
||
() => (<Server {...this.props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* 资源 */}
|
||
<Route path="/:owner/:projectsId/source"
|
||
render={
|
||
() => (<Source {...this.props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* 主页 */}
|
||
<Route path="/:owner/:projectsId/about"
|
||
render={
|
||
() => (<DevAbout {...this.props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
|
||
{/* 数据集 */}
|
||
<Route path="/:owner/:projectsId/dataset/upload"
|
||
render={
|
||
(props) => (<DataSetUpload {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
<Route path="/:owner/:projectsId/dataset"
|
||
render={
|
||
(props) => (<DataSetIndex {...this.props} {...props} {...this.state} {...common}/>)
|
||
}
|
||
></Route>
|
||
{/* wiki新增文件 */}
|
||
<Route path="/:owner/:projectsId/wiki/add"
|
||
render={
|
||
() => (<WikiEdit {...this.props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* wiki编辑文件 */}
|
||
<Route path="/:owner/:projectsId/wiki/edit"
|
||
render={
|
||
() => (<WikiEdit {...this.props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* wiki复制文件 */}
|
||
<Route path="/:owner/:projectsId/wiki/copy"
|
||
render={
|
||
() => (<WikiEdit {...this.props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* wiki历史列表 */}
|
||
<Route path="/:owner/:projectsId/wiki/history"
|
||
render={
|
||
() => (<WikiHisList {...this.props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* wiki */}
|
||
<Route path="/:owner/:projectsId/wiki"
|
||
render={
|
||
() => (<Wiki {...this.props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* 工作流 */}
|
||
<Route path="/:owner/:projectsId/devops"
|
||
render={
|
||
() => (<DevIndex {...this.props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* 流水线 */}
|
||
<Route path="/:owner/:projectsId/actions"
|
||
render={
|
||
() => (<DevopsCard {...this.props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* 标签列表 */}
|
||
{/* <Route path="/:owner/:projectsId/issues/tags"
|
||
render={
|
||
(props) => (<TagList {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route> */}
|
||
{/* 仓库设置 */}
|
||
<Route path="/:owner/:projectsId/settings"
|
||
render={
|
||
(props) => (<Setting {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
|
||
{/*修改里程碑*/}
|
||
<Route path="/:owner/:projectsId/milestones/:meilid/edit"
|
||
render={
|
||
(props) => (<OrderupdateMilepost {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* 新建里程碑 */}
|
||
<Route path="/:owner/:projectsId/milestones/new"
|
||
render={
|
||
(props) => (<OrdernewMilepost {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/*里程碑详情*/}
|
||
<Route path="/:owner/:projectsId/milestones/:mileId"
|
||
render={
|
||
(props) => (<MilepostDetail {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* 里程碑 */}
|
||
<Route path="/:owner/:projectsId/milestones"
|
||
render={
|
||
(props) => (<OrderMilepost {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* 动态 */}
|
||
<Route path="/:owner/:projectsId/activity"
|
||
render={
|
||
(props) => (<TrendsIndex {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* 代码Index */}
|
||
<Route path="/:owner/:projectsId/issues"
|
||
render={
|
||
(props) => (<OrderIndex {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
<Route path="/:owner/:projectsId/compare"
|
||
render={
|
||
(props) => (<CreateMerge {...this.props} {...props} {...this.state} {...common} is_fork={true} />)
|
||
}
|
||
></Route>
|
||
<Route path="/:owner/:projectsId/pulls/:mergeId/edit"
|
||
render={
|
||
(props) => (<UpdateMerge {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* review */}
|
||
<Route path="/:owner/:projectsId/pulls/:mergeId/review"
|
||
render={
|
||
(props) => (<Review {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
<Route path="/:owner/:projectsId/pulls/:mergeId"
|
||
render={
|
||
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
<Route path="/:owner/:projectsId/pulls/:mergeId/commits"
|
||
render={
|
||
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
<Route path="/:owner/:projectsId/pulls/:mergeId/files"
|
||
render={
|
||
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
<Route path="/:owner/:projectsId/pulls/:mergeId/date"
|
||
render={
|
||
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
<Route path="/:owner/:projectsId/pulls/:mergeId/MergeSubmit"
|
||
render={
|
||
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
|
||
<Route path="/:owner/:projectsId/pulls"
|
||
render={
|
||
(props) => (<MergeIndexDetail {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
<Route path="/:owner/:projectsId/following"
|
||
render={
|
||
(props) => (<WatchUsers {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
<Route path="/:owner/:projectsId/stargazers"
|
||
render={
|
||
(props) => (<PraiseUsers {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
<Route path="/:owner/:projectsId/members"
|
||
render={
|
||
(props) => (<ForkUsers {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* 贡献者列表 */}
|
||
<Route path="/:owner/:projectsId/contribute"
|
||
render={
|
||
() => (<Contribute {...this.props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
|
||
{/* 代码库----详情页面 */}
|
||
<Route path="/:owner/:projectsId/commits/branch/:branchName"
|
||
render={
|
||
(props) => (<CoderRootCommit {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
<Route path="/:owner/:projectsId/tree/:branchName"
|
||
render={
|
||
(props) => (<CoderDepot {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
{/* 邀请 */}
|
||
<Route path="/:owner/:projectsId/invite"
|
||
render={
|
||
(props) => (<Invite {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
|
||
<Route path="/:owner/:projectsId/:subIndex"
|
||
render={
|
||
(props) => ( __CLIENT__ && <CoderRootIndex {...this.props} {...props} {...this.state} {...common} />)
|
||
}
|
||
></Route>
|
||
<Route path="/:owner/:projectsId"
|
||
render={
|
||
(props) => <CoderDepot {...this.props} {...props} {...this.state} {...common} mirror_status={mirror_status}/>
|
||
}
|
||
></Route>
|
||
</Switch>}
|
||
</Spin>
|
||
</div>
|
||
)
|
||
}
|
||
}
|
||
|
||
const mapStateToProps = (state) => {
|
||
const {
|
||
projectBase,
|
||
defaultDetail,
|
||
projectMenu,
|
||
} = state.projectReducer;
|
||
return {
|
||
projectBase,
|
||
defaultDetail,
|
||
projectMenu,
|
||
};
|
||
}
|
||
|
||
const mapDispatchToProps = (dispatch) => ({
|
||
clearProject: (type) => dispatch(actions.clearProject(type)),
|
||
});
|
||
|
||
Detail.preFetch = ({ store, match, query }) => {
|
||
return new Promise(async function(resolve, reject) {
|
||
let { dispatch } = store;
|
||
// const { owner,projectsId } = match.params
|
||
const detail = await dispatch(setProjectDetail(match.params))
|
||
const promises = [
|
||
dispatch(setProject(match.params)),
|
||
dispatch(setProjectEntries({...match.params, branch: match.params.branchName ? match.params.branchName : detail.default_branch})),
|
||
dispatch(setProjectMenuList(match.params)),
|
||
dispatch(setProjectReadMe({...match.params, branch: match.params.branchName ? match.params.branchName : detail.default_branch}))
|
||
];
|
||
const data = await Promise.all(promises);
|
||
resolve({
|
||
code: 200,
|
||
});
|
||
});
|
||
};
|
||
|
||
export default __CLIENT__ ? withRouter(connect(
|
||
mapStateToProps,
|
||
mapDispatchToProps
|
||
)(ImageLayerOfCommentHOC({
|
||
imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget",
|
||
parentSelector: ".newContainer",
|
||
})(Detail))) : withRouter(connect(
|
||
mapStateToProps,
|
||
mapDispatchToProps
|
||
)(Detail)); |