forgeplus-react/src/forge/Main/CoderDepot.jsx

753 lines
32 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 , { useEffect , useState } from 'react';
import { Dropdown , Menu , Divider , Spin, Button, Tooltip } from 'antd';
import { getImageUrl , turnbar , returnbar } from "educoder";
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { truncateCommitId } from "../common/util";
import CloneAddress from '../Branch/CloneAddress';
import CheckProfile from '../Component/ProfileModal/Profile';
import SelectBranch from '../Branch/Select';
import User from '../Component/User';
import axios from 'axios';
import Path from './CoderDepotPath';
import Catalogue from './CoderDepotCatalogue';
import ReadMe from './CoderDepotReadme';
// import CoderRootFileDetail from './CoderRootFileDetail';
import './Index.scss';
import Releases from '../Component/Releases';
import Contributors from '../Component/Contributors';
import LanguagePower from '../Component/LanguagePower';
import DrawerPanel from '../Component/DrawerPanel';
import UpdateDescModal from './sub/UpdateDescModal';
import Nodata from '../Nodata';
import Invite from './sub/Invite';
import RenderHtml from '../../components/render-html';
import Loadable from 'react-loadable';
import Loading from '../../Loading';
import ProjectPortrait from '../Component/projectPortrait';
import imNoneImg from './img/importNone.png';
import LicenseModal from '../Component/licenseModal/index';
import moment from 'moment';
const ProjectCompass = Loadable({
loader: () => import('../Component/projectCompass'),
loading: Loading,
})
const format = "YYYY-MM-DD HH:mm"
const CoderRootFileDetail = Loadable({
loader: () => import("./CoderRootFileDetail"),
loading: Loading,
});
const mangementOperate =["Manager","Admin","Owner"]
/**
* projectDetail.type:0是托管项目1是镜像项目2是同步镜像项目(为2时不支持在线创建、在线上传、在线修改、在线删除、创建合并请求等功能)
* project.open_portrait: 是否开启项目画像展示
*/
function CoderDepot(props){
// const [ projectDetail , setProjectDetail ]= useState(undefined);
let { platform , mirror_status , bannerList , projectDetail, projectEntries, projectReadMe, project } = props ;
projectDetail = props.defaultDetail || projectDetail || {}
const [ inviteCode , setInviteCode ] = useState(projectDetail.invite_code || undefined);
const [ treeValue , setTreeValue ] = useState(undefined);
const [ treeValuePath , setTreeValuePath ] = useState(undefined);
const [ lastCommit,setLastCommit ] = useState((projectEntries.last_commit && projectEntries.last_commit.commit) || undefined);
const [ lastCommitAuthor,setLastCommitAuthor ] = useState((projectEntries.last_commit && projectEntries.last_commit.author) || undefined);
const [ type ,setType ] = useState('dir');
const [ hide , setHide ] = useState(true);
const [ hideBtn , setHideBtn ] = useState(true);
const [ commitCount ,setCommitCount ] = useState(projectEntries.commits_count || 0);
const [ dirInfo ,setDirInfo ] = useState(projectEntries.entries || undefined);//文件夹目录列表
const [ fileInfo ,setFileInfo ] = useState(undefined);//文件内容信息
const [ zip_url , setZip_url ] = useState(projectEntries.zip_url || undefined);
const [ tar_url , setTar_url ] = useState(projectEntries.tar_url || undefined);
const [ readOnly , setReadOnly] = useState(undefined);
const [ isSpin , setIsSpin] = useState(false);
const [ visible ,setVisible ] = useState(false);
const [ mainFlag ,setMainFlag ] = useState(false);
const [ openModal , setOpenModal ] = useState(false);
const [ desc , setDesc ] = useState(projectDetail.description || undefined);
const [ website , setWebsite ] = useState(projectDetail.website ||undefined);
const [ lesson_url , setLessonUrl ] = useState(projectDetail.lesson_url || undefined);
const [ topics, setTopics] = useState(projectDetail.topics || undefined);
const [ readme , setReadme ] = useState((projectReadMe && JSON.parse(decodeURIComponent(projectReadMe))) || undefined);
const [ defaultBranch , setDefaultBranch ] = useState(projectDetail.default_branch || undefined);
const [ editReadme , setEditReadme ] = useState(false);
const [ pullsFlag , setPullsFlag ] = useState(true);
const [ issuesFlag , setIssuesFlag ] = useState(true);
const [ releaseVersions , setReleaseVersions] = useState(undefined);
const [ licenseVisible ,setLicenseVisible] = useState(false);
const owner = props.match.params.owner;
const projectsId = props.match.params.projectsId;
let branchName = props.match.params.branchName;
branchName = returnbar(branchName);
let pathname = props.history.location.pathname;
let search = props.history.location.search
//distribution判断此用户是否可以创建发行版
const distribution = projectDetail && ( projectDetail.permission && projectDetail.permission !== "Reporter");
useEffect(()=>{
if(bannerList && bannerList.length>0){
let a = bannerList.filter(i=>i.menu_name === "pulls");
let i = bannerList.filter(i=>i.menu_name === "issues");
if(a && a.length === 0){
setPullsFlag(false);
}
if(i && i.length === 0){
setIssuesFlag(false);
}
}
},[bannerList])
// 埋点
function eventTrack(path){
const url = `/users/action.json`;
axios.post(url,{
action_type:"webide",
action_id:projectDetail && projectDetail.repo_id
}).then(result=>{});
window.open(path,"_blank");
}
useEffect(()=>{
if(projectDetail){
// setProjectDetail(projectDetail);
setTopics(projectDetail.topics);
setDesc(projectDetail.description);
setWebsite(projectDetail.website);
setLessonUrl(projectDetail.lesson_url);
setDefaultBranch(projectDetail.default_branch);
setInviteCode(projectDetail.invite_code);
}
},[projectDetail,mirror_status])
useEffect(()=>{
// 设置网页标题
if(projectDetail && projectDetail.project_identifier){
const { author, name, description, default_branch} = projectDetail;
if(branchName && branchName !== default_branch){
// 处于某分支/标签
document.title = `${author.name}/${name}-${branchName} | GitLink`;
}else{
document.title = `${author.name}/${name}${description?': '+description:''} | GitLink` ;
}
}
}, [treeValuePath, projectDetail, branchName])
useEffect(()=>{
if(treeValue){
setTreeValuePath(decodeURIComponent(treeValue).split('/'));
}else{
setTreeValuePath(undefined);
}
},[treeValue])
useEffect(()=>{
if (projectsId && owner && defaultBranch && mirror_status===0){
let b = turnbar(branchName) ;
if(pathname.indexOf(`/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${b}/`) > -1) {
let url = pathname.split(`/tree/${b}/`)[1];
setTreeValue(url);
getFileInfo(url,branchName);
setType("file");
}else{
setTreeValue(undefined);
if (!projectEntries) {
getDirInfo(branchName || defaultBranch);
}
setType("dir");
}
}
},[projectsId,owner,pathname,defaultBranch,mirror_status])
// 编辑完回来重新获取
useEffect(()=>{
let b = turnbar(branchName) ;
if (projectsId && owner && defaultBranch && mirror_status===0 && !search && pathname.indexOf(`/tree/${b}/`) > -1){
let url = pathname.split(`/tree/${b}/`)[1];
getFileInfo(url,branchName);
}
},[search])
useEffect(()=>{
if(platform && mirror_status===0){
setReadOnly(props.history.location.search.indexOf('edit') !== -1);
axios.get(`/${owner}/${projectsId}/releases.json`).then((result)=>{
if(result && result.data){
const release = {
"list":result.data.releases,
"total_count":result.data.releases && result.data.releases.length
}
setReleaseVersions(release);
}
})
}
},[platform,mirror_status])
// 获取readme信息
function getReadmeInfo(path, ref) {
axios.get(`/${owner}/${projectsId}/readme.json`, {
params:{
owner: owner,
repo: projectsId,
filepath:path,
ref:ref || branchName
}
}).then((result) => {
if (result) {
setReadme(result.data);
} else {
setReadme(undefined);
}
})
}
// 获取主目录列表
function getDirInfo(branch){
setIsSpin(true);
const url = `/${owner}/${projectsId}/entries.json`;
axios.get(url, {
params: { ref:branch}
}).then((result) => {
if (result && result.data.status !== 404) {
setCommitCount(result.data.commits_count);
setDirInfo(result.data.entries);
setFileInfo(undefined);
setTar_url(result.data.tar_url);
setZip_url(result.data.zip_url);
let c = result.data.last_commit
setLastCommit(c && c.commit);
setLastCommitAuthor(c && c.author);
setMainFlag(true);
setReadOnly(true);
// setReadme(result.data.readme);
setEditReadme(false);
setHide(true);
getReadmeInfo('', branchName || defaultBranch);
}else{
// entries接口返回404分支不存在或被删除
props.history.push(`/${owner}/${projectsId}`)
}
setTimeout(function(){setIsSpin(false);},500);
}).catch(error=>{setIsSpin(false);})
}
useEffect(()=>{
if(projectDetail && lastCommit)
{
let ele = document.getElementById("ptxt");
if(ele){
let h = ele.offsetHeight;
if( h <= 36 ) setHideBtn(false);
}
}
},[projectDetail,lastCommit])
// 获取子目录列表
function getFileInfo(path, ref){
setIsSpin(true);
const url = `/${owner}/${projectsId}/sub_entries.json`;
axios.get(url, {
params:{
filepath:returnbar(path),
ref:ref || branchName,
type
}
}).then((result) => {
if(result.data.status === -2){
props.showNotification(result.data.message);
props.history.push(`/${owner}/${projectsId}/tree/${turnbar(ref || branchName)}`)
}
if (result) {
let en = result.data.entries;
if(en.type){
setDirInfo(undefined);
setFileInfo(en);
setType(en.type);
setReadme(undefined);
}else{
setFileInfo(undefined);
setDirInfo(en);
setType("dir");
getReadmeInfo(path, branchName || defaultBranch);
}
let c = result.data.last_commit
setLastCommit(c && c.commit);
setLastCommitAuthor(c && c.author);
setMainFlag(false);
setReadOnly(true);
setReadOnly(!editReadme);
setHide(true);
}
setTimeout(function(){setIsSpin(false);},500)
}).catch(error=>{setIsSpin(false);})
}
// 切换分支或者标签
function changeBranch(value){
let checkvalue = value;
let u = `/${owner}/${projectsId}${checkvalue && `/tree/${checkvalue}`}${treeValue ? `/${treeValue}`:""}`;
props.history.push(u);
}
// 文件相关的下拉项
function fileMenu(){
let b = branchName || defaultBranch;
let checkvalue = turnbar(b);
return (
<Menu className="fileMenu">
<Menu.Item>
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件</CheckProfile>
</Menu.Item>
<Menu.Item>
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件</CheckProfile>
</Menu.Item>
</Menu>
)
}
function getPathUrl(array,index){
if(array && array.length>0 && index){
let str = "";
for(let i=0;i<index;i++){
str += `/${array[i]}`;
}
return str.substr(1);
}
}
// 页面地址返回到主目录
function returnMain(){
setTreeValue(undefined);
let branch = branchName || defaultBranch;
let checkvalue = turnbar(branch);
props.history.push(`/${owner}/${projectsId}/tree/${checkvalue}`);
};
// 子目录路径返回链接
function returnUlr(url){
let enBranch = turnbar(branchName);
setType('dir');
props.history.push(`/${owner}/${projectsId}/tree${enBranch?`/${enBranch}`:""}/${url}`);
}
// 点击跳转到子目录
function goToSubRoot(path,type,filename){
if(type!=="submodule"){
let enBranch = branchName || defaultBranch;
let checkvalue = turnbar(enBranch);
let enPath = turnbar(path);
setType(type);
window.scrollTo(0,0)
props.history.push(`/${owner}/${projectsId}${`/tree/${checkvalue}`}${enPath?`/${enPath}`:""}`);
}
}
function onEdit(readOnly){
setReadOnly(readOnly);
setEditReadme(false);
const {history} = props;
if(readOnly){
history.push(history.location.pathname);
}else{
history.push(`${history.location.pathname}?edit`);
}
}
function ChangeFile(path, readOnly){
//点击直接跳转页面 加载一次路由
let enBranch = branchName || defaultBranch;
let checkvalue = turnbar(enBranch);
props.history.push(`/${owner}/${projectsId}/tree/${checkvalue}/${path}?edit`);
setType("file");
setEditReadme(true);
};
function changeHide(hide){
setHide(!hide);
}
function urlLink(link){
if(props.checkIfLogin()===false){
props.showLoginDialog()
return false;
}
props.history.push(link);
}
const downloadMenu = (
<CloneAddress
http_url={projectDetail && projectDetail.clone_url}
ssh_url = {(projectDetail && props && props.platform) && projectDetail.ssh_url}
zip_url={(props && props.platform) && zip_url}
tar_url={(props && props.platform) && tar_url}
showNotification={props.showNotification}/>
)
// 确认修改简介、website、实践课程链接
function okUpdate(d,w,l, projectTopicNames){
const url = `/${owner}/${projectsId}.json`;
axios.put(url,{
description:d,website:w || "",lesson_url:l||"",
project_topic_names: projectTopicNames
}).then(result=>{
if(result && result.data && result.data.id){
setDesc(result.data.description);
setWebsite(result.data.website);
setLessonUrl(result.data.lesson_url);
setTopics(result.data.topics);
}
})
}
function createIssue(){
if(baseOper){
props.history.push(`/${owner}/${projectsId}/issues/new`);
}else{
props.showLoginDialog(`/${owner}/${projectsId}/issues/new`);
}
}
// 创建自定义许可证
function createDefaultLicense(id){
if(props.checkIfLogin()===false){
props.showLoginDialog()
return false;
}
let b = branchName || defaultBranch;
let checkvalue = turnbar(b);
props.history.push({pathname:`/${owner}/${projectsId}/${checkvalue}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`,state:`${id}`})
}
// 如果项目是fork的项目pr自动指向源仓库否则指向本仓库默认分支
function compare() {
if (projectDetail && projectDetail.fork_info) {
urlLink(`/${projectDetail.fork_info.fork_project_user_login}/${projectDetail.fork_info.fork_project_identifier}/compare/${turnbar(branchName || defaultBranch)}...${owner +'/' + projectsId + ':' + turnbar(branchName || defaultBranch)}`)
} else {
urlLink(`/${owner}/${projectsId}/compare/${turnbar(defaultBranch)}...${turnbar(branchName || defaultBranch)}`);
}
}
let n = fileInfo && fileInfo.name;
const mdFlag = n && n.substring(n.length-3,n.length) === ".md";
const { current_user , checkIfLogin , showLoginDialog } = props;
const baseOper = current_user && current_user.login && issuesFlag;
const baseOperate = projectDetail && projectDetail.permission && projectDetail.permission !=="Reporter" && projectDetail.type !==2 && pullsFlag && props.platform;
const fileOperate = type === "dir" && projectDetail && projectDetail.type !==2 && ((projectDetail.permission && projectDetail.permission !=="Reporter") || (current_user && current_user.admin));
return(
<div className='WhiteBack'>
{mirror_status ===0 && <UpdateDescModal desc={desc} website={website} lesson_url={lesson_url} topicsInfo={topics} visible={openModal} onCancel={()=>setOpenModal(false)} onOk={okUpdate}/> }
<LicenseModal visible={licenseVisible} onCancel={()=>{setLicenseVisible(false)}} createDefaultLicense={createDefaultLicense}/>
<Spin spinning={isSpin}>
{
((dirInfo || fileInfo) && mirror_status===0 ) &&
<React.Fragment>
<DrawerPanel
history={props.history}
owner={owner}
projectsId={projectsId}
name={projectDetail && projectDetail.name}
branch={branchName || defaultBranch}
visible={visible}
onClose={()=>setVisible(false)}
list = {mainFlag ? dirInfo : undefined}
/>
<div className="drawerBtn" onClick={()=>setVisible(true)}>
<i className="iconfont icon-zuohuaicon font-14"></i>
<span>目录</span>
</div>
</React.Fragment>
}
<div style={{minHeight:"500px"}}>
{
mirror_status === 2 &&
<div className='importFailTip'>
<img src={imNoneImg} alt="" width={290}/>
{
projectDetail.permission && mangementOperate.includes(projectDetail.permission) ?
<div className='failInfo'>
<p className='font-18 weight500 color-grey-3'>导入项目失败可能存在以下原因</p>
<li>1导入的仓库 URL 错误</li>
<li>2您需要导入的可能是一个您无权访问的私有仓库需要输入授权验证仓库的帐号密码或者个人令牌此信息仅用于本次代码同步不做任何记录</li>
<p className='font-18 weight500 color-grey-3'>请前往 <Link className='color-blue' to={`/${owner}/${projectsId}/settings`}>仓库设置</Link> </p>
</div>
:
<p className='font-17 weight500'>导入项目失败请联系管理员重新导入</p>
}
</div>
}
{
projectDetail && mirror_status === 0 &&
<div className="Panels Box">
<div className="LongWidth">
<div className="panelmenu">
<div className="FlexAJ">
<div className="AlignCenter">
<div className="mr30">
{
props && (props.platform && mirror_status ===0) ?
<SelectBranch
repo_id={projectDetail && projectDetail.repo_id}
projectsId={projectsId}
branch={branchName || defaultBranch}
changeBranch={changeBranch}
owner={owner}
history={props.history}
branchList={projectDetail && projectDetail.branches && projectDetail.branches.list}
></SelectBranch>
:
<span>分支<span className="color-grey-6">{branchName || defaultBranch}</span></span>
}
</div>
{
treeValuePath && treeValuePath.length > 0 ?
<Path
identifier={projectDetail && projectDetail.identifier}
treeValuePath={treeValuePath}
returnUlr={returnUlr}
returnMain={returnMain}
getPathUrl={getPathUrl}
/>
:
<React.Fragment>
<div className="mr20 AlignCenter">
{
props.platform ?
<Link to={`/${owner}/${projectsId}/branches`} className="iconBtn">
<i className="iconfont icon-master_icon font-16"></i>
<span>分支</span>
<span>{projectDetail && projectDetail.branches_count}</span>
</Link>
:
<span>
<i className="iconfont icon-master_icon font-16 color-grey-6"></i>
<span className="ml3 color-grey-6">分支</span>
<span className="ml3">{projectDetail && projectDetail.branches_count}</span>
</span>
}
</div>
<div className="mr20 AlignCenter">
{
props.platform ?
<Link to={`/${owner}/${projectsId}/tags`} className="iconBtn">
<i className="iconfont icon-biaoqianicon font-16"></i>
<span>标签</span>
<span>{projectDetail && projectDetail.tags_count}</span>
</Link>:
<span>
<i className="iconfont icon-biaoqianicon font-16 color-grey-6"></i>
<span className="ml3 color-grey-6">标签</span>
<span className="ml3">{projectDetail && projectDetail.tags_count}</span>
</span>
}
</div>
</React.Fragment>
}
</div>
<div className="depotBtn AlignCenter">
<div className="addOptionBtn">
{
baseOperate &&
<CheckProfile {...props} sureFunc={compare}>+ 合并请求</CheckProfile>
}
{
issuesFlag &&
<CheckProfile {...props} sureFunc={createIssue} checklogin>+ 疑修</CheckProfile>
}
</div>
{ fileOperate &&
<Dropdown
overlay={fileMenu()}
className="mr10"
trigger={['click']}
getPopupContainer={document.parentNode}
>
<a>文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-6 mr-5"></i></a>
</Dropdown>
}
{
checkIfLogin && checkIfLogin()?
<a className='newBtn' onClick={()=>eventTrack(`/${owner}/${projectsId}/webIDE/tree/${branchName||defaultBranch}`)}>Web IDE</a>
:
<a className='newBtn' onClick={()=>{showLoginDialog(`/${owner}/${projectsId}`)}}>Web IDE</a>
}
<Dropdown overlay={downloadMenu} placement="bottomRight" trigger={['click']}>
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white mr-3"></i></Button>
</Dropdown>
</div>
</div>
{
(dirInfo && dirInfo.length>0) || fileInfo ?
<div className="listtable">
{
((lastCommit && lastCommit.message) || lastCommitAuthor) &&
<div className="listtablehead">
{
lastCommitAuthor &&
<User url={getImageUrl(`/${lastCommitAuthor.image_url}`)} name={lastCommitAuthor.name} id={lastCommitAuthor.id} login={lastCommitAuthor.login}/>
}
{
lastCommit.message &&
<div className={hideBtn && hide ? "ellipsistxt hidetxt" :"ellipsistxt"}>
<pre id="ptxt"><Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(lastCommit.sha)}`}><RenderHtml value={lastCommit.message}/></Link></pre>
</div>
}
{ hideBtn && __CLIENT__ && <div className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></div> }
<Tooltip title={lastCommit.committer && moment(lastCommit.committer.date).format(format)}><span className="ml20 color-grey-6 font-12 mt3">{lastCommit.time_from_now}</span></Tooltip>
{
commitCount ?
<Link to={`/${owner}/${projectsId}/commits/branch/${turnbar(branchName || defaultBranch)}`} className="ml20 color-grey-3"style={{height:"28px",lineHeight:"28px"}}>
<i className="iconfont icon-tijiaoicon mr3 font-16"></i><span style={{fontWeight:"500"}}>{commitCount}</span>
</Link>:""
}
</div>
}
<ul className="listtablebody">
{
dirInfo && dirInfo.length > 0 &&
dirInfo.map((item,key)=>{
return(
<Catalogue
key={item.id||key}
owner={owner}
item={item}
projectsId={projectsId}
goToSubRoot={goToSubRoot}
platform={props.platform}
/>
)
})
}
{
fileInfo && __CLIENT__ &&
<CoderRootFileDetail
{...props}
detail={fileInfo}
readOnly={readOnly}
md={mdFlag}
onEdit={onEdit}
currentBranch={branchName || defaultBranch}
branch={branchName || defaultBranch}
type={projectDetail.type}
treeValuePath={treeValuePath}
></CoderRootFileDetail>
}
</ul>
</div>
: ""
}
{
(dirInfo && dirInfo.length === 0) && !fileInfo ? <Nodata _html="暂未发现文件"/> :""
}
{/* readme文件显示(显示文件详情时不显示readme文件) */}
{ (readme && readme.replace_content) ? <ReadMe ChangeFile={ChangeFile} readme={readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
</div>
</div>
{
(!(treeValuePath && treeValuePath.length > 0) && !fileInfo ) &&
<div className="ShortWidth">
<div className="Gap" style={{paddingLeft:"30px"}}>
<div className="panelmenu">
<div className="font-18 color-ooo mb20 FlexAJ" style={{lineHeight:"28px"}}>关于
{
projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner" || projectDetail.permission==="Manager") &&
<i onClick={()=>setOpenModal(true)} className="iconfont icon-a-shezhi color-grey-9 font-15 pointer"></i>
}
</div>
{desc && <p className="font-14 color-grey-3 mb15 task-hide-2" style={{lineHeight:"24px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}} title={desc}>{desc}</p>}
{/* 项目标签 */}
{topics && <div className='projectHomeTopics'>
{topics.map(item=><Link to={`/explore/topic/${item.id}/${encodeURIComponent(item.name)}`} className='proHomeTopic mr15 mb10 font-13 task-hide'>{item.name}</Link>)}
</div>}
{
website &&
<div className="color-grey-6 df pinfos mb5">
<i className="iconfont icon-lianjie2 font-15 mr10"></i>
<a href={website} target="_blank" style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px",textDecoration:"underline"}}>{website}</a>
</div>
}
<div className="pinfos mb5">
<i className="iconfont icon-zishuwenjian_icon font-15 mr10"></i>
<a href="#readme">README.md</a>
</div>
<div className="color-grey-6 mb5">
<i className="iconfont icon-neicunicon font-15 mr10"></i>
<span>{projectDetail && projectDetail.size}</span>
</div>
{
projectDetail && projectDetail.license_id !== 0 &&
<div className={projectDetail.license_name ? "pinfos" :"color-grey-6"}>
<i className="iconfont icon-xieyiicon font-16 mr10"></i>
{
projectDetail.license_name ?
<Link to={`/${owner}/${projectsId}/tree/${turnbar(branchName || defaultBranch)}/LICENSE`} className="color-grey-6">{projectDetail.license_name}</Link>
:
<a className='color-blue' onClick={()=>{setLicenseVisible(true)}}>点击选择许可证(LICENSE)</a>
}
</div>
}
</div>
{
inviteCode &&
<div>
<Divider />
<Invite code={inviteCode}/>
</div>
}
{
lesson_url &&
<div>
<Divider />
<p className="font-16 color-ooo">实践课程</p>
<a href={lesson_url} target="_blank" className="color-grey-6" style={{textDecoration:"underline",wordBreak:"break-all"}}>{lesson_url}</a>
</div>
}
{/* 发布 */}
{
releaseVersions &&
<React.Fragment>
<Divider />
<Releases
owner={owner}
projectsId={projectsId}
releaseVersions={releaseVersions}
history={props.history}
distribution={distribution}
/>
</React.Fragment>
}
{__CLIENT__ && projectDetail && projectDetail.project_id && !projectDetail.private && <ProjectCompass owner={owner} projectsId={projectsId} />}
{/* 贡献者 */}
{mirror_status ===0 && <Contributors owner={owner} projectsId={projectsId} /> }
{/* 项目画像: 导入/fork项目不展示, open_portrait后台配置是否开启仓库 */}
{__CLIENT__ && projectDetail && !projectDetail.type && !projectDetail.forked_from_project_id && project && project.open_portrait && <ProjectPortrait owner={owner} projectsId={projectsId}/>}
{/* 语言 */}
{ mirror_status ===0 && <LanguagePower owner={owner} projectsId={projectsId}/> }
</div>
</div>
}
</div>
}
</div>
</Spin>
</div>
)
}
const mapStateToProps = (state) => {
const {
defaultDetail,
projectEntries,
projectReadMe
} = state.projectReducer;
return {
defaultDetail,
projectEntries,
projectReadMe
};
}
export default connect(
mapStateToProps
)(CoderDepot);