forgeplus-react/src/forge/Main/Detail.js

989 lines
34 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { Component } from 'react';
import { Spin, Tooltip } 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 styles from './list.scss'
import styles1 from '../css/index.scss'
import withStyles from 'isomorphic-style-loader/withStyles';
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/Index'),
loading: Loading,
});
const WikiEdit = Loadable({
loader: () => import('../Wiki/EditWiki'),
loading: Loading,
});
const Invite = Loadable({
loader: () => import('../Invite/Index'),
loading: Loading,
});
const Review = Loadable({
loader: () => import('../Newfile/codeReview'),
loading: Loading,
});
/**
* permissionManager:管理员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(`/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: false,
mirror_status:2,
bannerList: props.projectMenu || []
}
}
componentDidMount = () => {
// this.getProject();
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) {
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.canvasChannel();
if (num) {
this.setState({
secondSync: true,
firstSync: false
})
} else {
this.setState({
firstSync: true,
secondSync: false
})
}
this.setState({
mirror_status:1
})
} else if (data.mirror_status === 2) {
this.setState({
mirror_status:2,
firstSync: false
})
this.deleteProjectBack();
} else {
this.setState({
firstSync: false,
secondSync: false,
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.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: data => {
console.log(`###### ---received data--- ######`);
if (data) {
if (deleteFlag) {
this.props.showNotification("镜像同步成功!");
window.location.reload();
} else {
if (data.project && data.project.mirror_status === 2) {
this.deleteProjectBack();
}
this.getDetail();
this.getBanner();
}
this.setState({
firstSync: false,
mirror_status:data.project && data.project.mirror_status,
secondSync: false
});
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();
}
}
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.length > 0 && ','}${ 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;
if (!data) {
const url = `/${owner}/${projectsId}/menu_list.json`;
const res = await axios.get(url)
if (res.data) {
data = res.data
}
}
if (data) {
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) {
if (result.data.message === "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.showNotification(result.data.message);
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> : ""
}
render() {
const { projectDetail, watchers_count, praises_count,
forked_count, firstSync, secondSync,
isManager, 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">
<AlignTop style={{ padding: "18px 0px 10px", justifyContent: "space-between" }}>
<div>
<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>}
</AlignTop>
<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>
</AlignTop>
{/* <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" />
</Content>
}
<Spin spinning={secondSync && !firstSync} className="spinstyle" tip="正在同步镜像" size="large">
<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/:wikiName/:key/edit"
render={
() => (<WikiEdit {...this.props} {...this.state} {...common} />)
}
></Route>
{/* wiki具体某一个地址 */}
<Route path="/:owner/:projectsId/wiki/:wikiName/:key"
render={
(props) => (<Wiki {...this.props} {...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/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/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) => (<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, getState } = store;
// const { owner,projectsId } = match.params
const promises = [
dispatch(setProjectDetail(match.params)),
dispatch(setProject(match.params)),
dispatch(setProjectEntries({...match.params, branch: ''})),
dispatch(setProjectMenuList(match.params)),
dispatch(setProjectReadMe({...match.params, branch: ''}))
];
const data = await Promise.all(promises);
resolve({
code: 200,
});
});
};
export default withRouter(withStyles(styles, styles1)(connect(
mapStateToProps,
mapDispatchToProps
)(Detail)));