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

463 lines
20 KiB
React
Raw Normal View History

2021-03-18 17:28:53 +08:00
import React , { useEffect , useState } from 'react';
import { WhiteBack , Box , LongWidth , ShortWidth , Gap , AlignCenter , FlexAJ } from '../Component/layout';
2021-03-30 11:50:25 +08:00
import { Dropdown , Menu , Divider , Spin, Button } from 'antd';
2021-03-18 17:28:53 +08:00
import { getImageUrl } from "educoder";
import { Link } from 'react-router-dom';
2021-03-19 17:22:02 +08:00
import CloneAddress from '../Branch/CloneAddress';
2021-03-18 17:28:53 +08:00
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';
2021-03-24 14:08:10 +08:00
import UpdateDescModal from './sub/UpdateDescModal';
2021-03-18 17:28:53 +08:00
import Nodata from '../Nodata';
/**
* projectDetail.type:0是托管项目1是镜像项目2是同步镜像项目(为2时不支持在线创建在线上传在线修改在线删除创建合并请求等功能)
*/
2021-03-18 17:28:53 +08:00
function CoderDepot(props){
const [ projectDetail , setProjectDetail ]= useState(undefined);
const [ treeValue , setTreeValue ] = useState(undefined);
const [ treeValuePath , setTreeValuePath ] = useState(undefined);
const [ lastCommit,setLastCommit ] = useState(undefined);
const [ lastCommitAuthor,setLastCommitAuthor ] = useState(undefined);
const [ type ,setType ] = useState('dir');
const [ hide , setHide ] = useState(true);
const [ hideBtn , setHideBtn ] = useState(false);
const [ commitCount ,setCommitCount ] = useState(0);
const [ dirInfo ,setDirInfo ] = useState(undefined);//文件夹目录列表
const [ fileInfo ,setFileInfo ] = useState(undefined);//文件内容信息
const [ zip_url , setZip_url ] = useState(undefined);
const [ tar_url , setTar_url ] = useState(undefined);
const [ readOnly , setReadOnly] = useState(true);
const [ isSpin , setIsSpin] = useState(true);
const [ visible ,setVisible ] = useState(false);
2021-03-19 16:29:43 +08:00
const [ mainFlag ,setMainFlag ] = useState(false);
2021-03-24 14:08:10 +08:00
const [ openModal , setOpenModal ] = useState(false);
const [ desc , setDesc ] = useState(undefined);
const [ website , setWebsite ] = useState(undefined);
const [ lesson_url , setLessonUrl ] = useState(undefined);
2021-05-26 16:00:55 +08:00
const [ readme , setReadme ] = useState(undefined);
const [ defaultBranch , setDefaultBranch ] = useState(undefined)
2021-03-18 17:28:53 +08:00
const owner = props.match.params.owner;
const projectsId = props.match.params.projectsId;
const branchName = props.match.params.branchName;
2021-05-21 18:58:17 +08:00
const details = props.projectDetail;
2021-03-18 17:28:53 +08:00
let pathname = props.history.location.pathname;
2021-05-21 18:58:17 +08:00
2021-03-18 17:28:53 +08:00
useEffect(()=>{
2021-05-21 18:58:17 +08:00
if(details){
setProjectDetail(details);
setDesc(details.description);
setWebsite(details.website);
setLessonUrl(details.lesson_url);
2021-05-26 16:00:55 +08:00
setDefaultBranch(details.default_branch);
2021-03-18 17:28:53 +08:00
}
2021-05-21 18:58:17 +08:00
},[details])
2021-03-18 17:28:53 +08:00
useEffect(()=>{
if(treeValue){
setTreeValuePath(treeValue.split('/'));
}else{
setTreeValuePath(undefined);
}
},[treeValue])
2021-05-21 18:58:17 +08:00
2021-03-18 17:28:53 +08:00
useEffect(()=>{
2021-05-26 16:00:55 +08:00
if (projectsId && owner && defaultBranch){
2021-03-18 17:28:53 +08:00
if(pathname.indexOf(`/projects/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${branchName}/`) > -1) {
let url = pathname.split(`/tree/${branchName}/`)[1];
setTreeValue(url);
getFileInfo(url,branchName);
setType("file");
2021-03-18 17:28:53 +08:00
}else{
setTreeValue(undefined);
2021-05-26 16:00:55 +08:00
getDirInfo(branchName || defaultBranch);
setType("dir");
2021-03-18 17:28:53 +08:00
}
}
2021-05-26 16:00:55 +08:00
},[projectsId,owner,pathname,defaultBranch])
2021-03-18 17:28:53 +08:00
// 获取主目录列表
function getDirInfo(branch){
setIsSpin(true);
const url = `/${owner}/${projectsId}/entries.json`;
axios.get(url, {
params: { ref: branch }
}).then((result) => {
if (result) {
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);
2021-03-30 15:01:25 +08:00
setLastCommitAuthor(c && c.committer);
2021-03-19 16:29:43 +08:00
setMainFlag(true);
setReadOnly(true);
2021-05-21 18:58:17 +08:00
setReadme(result.data.readme);
setHide(true);
2021-03-18 17:28:53 +08:00
}
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 > 18 ) setHideBtn(true);
2021-03-18 17:28:53 +08:00
}
}
},[projectDetail,lastCommit])
// 获取子目录列表
function getFileInfo(path, ref){
setIsSpin(true);
const url = `/${owner}/${projectsId}/sub_entries.json`;
axios.get(url, {
params:{
filepath:path,
ref:ref || branchName,
type
}
}).then((result) => {
if (result) {
let en = result.data.entries;
if(en.type){
setDirInfo(undefined);
setFileInfo(en);
setType(en.type);
}else{
setFileInfo(undefined);
setDirInfo(en);
setType("dir");
}
let c = result.data.last_commit
setLastCommit(c && c.commit);
2021-03-30 15:01:25 +08:00
setLastCommitAuthor(c && c.committer);
2021-03-19 16:29:43 +08:00
setMainFlag(false);
setReadOnly(true);
setHide(true);
2021-03-18 17:28:53 +08:00
}
setTimeout(function(){setIsSpin(false);},500)
}).catch(error=>{setIsSpin(false);})
}
// 切换分支或者标签
function changeBranch(value){
let url = `/projects/${owner}/${projectsId}${value && `/tree/${value}`}${treeValue ? `/${treeValue}`:""}`;
props.history.push(url);
}
// 文件相关的下拉项
const fileMenu =(
<Menu>
2021-05-26 16:00:55 +08:00
<Menu.Item><a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/${branchName || defaultBranch}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件</a></Menu.Item>
<Menu.Item><a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/${branchName || defaultBranch}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件</a></Menu.Item>
2021-03-18 17:28:53 +08:00
</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);
2021-05-26 16:00:55 +08:00
let branch = branchName || defaultBranch;
2021-03-18 17:28:53 +08:00
props.history.push(`/projects/${owner}/${projectsId}/tree/${branch}`);
};
// 子目录路径返回链接
function returnUlr(url){
props.history.push(`/projects/${owner}/${projectsId}/tree${branchName?`/${branchName}`:""}/${url}`);
}
// 点击跳转到子目录
function goToSubRoot(path,type,filename){
setType(type);
2021-05-26 16:00:55 +08:00
props.history.push(`/projects/${owner}/${projectsId}${`/tree/${branchName || defaultBranch}`}${path?`/${path}`:""}`);
2021-03-18 17:28:53 +08:00
}
function onEdit(readOnly){
setReadOnly(readOnly);
}
function ChangeFile(path, readOnly){
//点击直接跳转页面 加载一次路由
2021-05-26 16:00:55 +08:00
props.history.push(`/projects/${owner}/${projectsId}/tree/${branchName || defaultBranch}/${path}`);
2021-03-18 17:28:53 +08:00
setType("file");
setReadOnly(readOnly);
};
function changeHide(hide){
setHide(!hide);
}
2021-03-19 17:22:02 +08:00
function urlLink(link){
if(props.checkIfLogin()===false){
props.showLoginDialog()
return false;
}
props.history.push(link);
}
2021-03-18 17:28:53 +08:00
const downloadMenu = (
2021-03-19 17:22:02 +08:00
<div className="downMenu">
<div style={{padding:"20px",borderBottom:"1px solid #eee"}}>
<CloneAddress
http_url={projectDetail && projectDetail.clone_url}
showNotification={props.showNotification}/>
</div>
<Menu className="edu-txt-center">
<Menu.Item><a href={zip_url}>下载 ZIP</a></Menu.Item>
<Menu.Item><a href={tar_url}>下载 TAR.GZ</a></Menu.Item>
</Menu>
</div>
2021-03-18 17:28:53 +08:00
)
2021-04-08 17:44:31 +08:00
// 确认修改简介、website、实践课程链接
function okUpdate(d,w,l){
2021-03-24 14:08:10 +08:00
const url = `/${owner}/${projectsId}.json`;
axios.put(url,{
description:d,website:w,lesson_url:l
2021-03-24 14:08:10 +08:00
}).then(result=>{
if(result && result.data && result.data.id){
setDesc(result.data.description);
setWebsite(result.data.website);
setLessonUrl(result.data.lesson_url);
2021-03-24 14:08:10 +08:00
}
})
}
2021-04-20 15:31:49 +08:00
let n = fileInfo && fileInfo.name;
const mdFlag = n && n.substring(n.length-3,n.length) === ".md";
2021-06-11 11:01:46 +08:00
const { current_user } = props;
const fileOperate = type === "dir" && projectDetail && projectDetail.type !== 2 && (projectDetail.permission !=="Reporter" || (current_user && current_user.admin));
2021-03-18 17:28:53 +08:00
return(
<WhiteBack>
<UpdateDescModal desc={desc} website={website} lesson_url={lesson_url} visible={openModal} onCancel={()=>setOpenModal(false)} onOk={okUpdate}/>
2021-03-18 17:28:53 +08:00
<Spin spinning={isSpin}>
{
2021-03-19 16:29:43 +08:00
(dirInfo || fileInfo) &&
2021-03-18 17:28:53 +08:00
<React.Fragment>
<DrawerPanel
history={props.history}
owner={owner}
projectsId={projectsId}
name={projectDetail && projectDetail.name}
2021-05-26 16:00:55 +08:00
branch={branchName || defaultBranch}
2021-03-18 17:28:53 +08:00
visible={visible}
onClose={()=>setVisible(false)}
2021-03-19 16:29:43 +08:00
list = {mainFlag ? dirInfo : undefined}
2021-03-18 17:28:53 +08:00
/>
2021-03-30 10:26:02 +08:00
<div className="drawerBtn" onClick={()=>setVisible(true)}>
<i className="iconfont icon-youjiantou font-16"></i>
<span>目录</span>
</div>
2021-03-18 17:28:53 +08:00
</React.Fragment>
}
<div style={{minHeight:"500px"}}>
{
projectDetail &&
<Box className="Panels">
<LongWidth>
<div className="panelmenu">
<FlexAJ>
<AlignCenter>
<div className="mr20">
{
props && props.platform ?
<SelectBranch
repo_id={projectDetail && projectDetail.repo_id}
projectsId={projectsId}
2021-05-26 16:00:55 +08:00
branch={branchName || defaultBranch}
2021-03-18 17:28:53 +08:00
changeBranch={changeBranch}
owner={owner}
history={props.history}
branchList={projectDetail && projectDetail.branches && projectDetail.branches.list}
></SelectBranch>
:
2021-05-26 16:00:55 +08:00
<span>分支<span className="color-grey-6">{branchName || defaultBranch}</span></span>
2021-03-18 17:28:53 +08:00
}
</div>
<AlignCenter className="mr20">
<Link to={`/projects/${owner}/${projectsId}/branchs`} className="color-grey-9">
<i className="iconfont icon-fenzhi2 font-18 color-grey-9 mr3"></i>
<span className="color-grey-6 mr3">{projectDetail && projectDetail.branches && projectDetail.branches.total_count}</span>分支
</Link>
</AlignCenter>
<AlignCenter className="mr20">
<Link to={`/projects/${owner}/${projectsId}/tag`} className="color-grey-9">
<i className="iconfont icon-biaoqian3 font-16 color-grey-9 mr3"></i>
<span className="color-grey-6 mr3">{projectDetail && projectDetail.tags && projectDetail.tags.total_count}</span>标签
</Link>
</AlignCenter>
</AlignCenter>
<AlignCenter>
<div className="mr20 addOptionBtn">
{
projectDetail.type !== 2 &&
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/pulls/new`)} >+ 合并请求</a>
}
2021-03-19 17:22:02 +08:00
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/issues/new`)} >+ 任务</a>
2021-03-18 17:28:53 +08:00
</div>
2021-06-11 11:01:46 +08:00
{ fileOperate &&
2021-04-27 17:11:37 +08:00
<Dropdown overlay={fileMenu} className="mr20" trigger={['click']}>
2021-03-30 11:50:25 +08:00
<Button type="default">文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-9"></i></Button>
</Dropdown>
}
2021-04-27 17:11:37 +08:00
<Dropdown overlay={downloadMenu} placement="bottomRight" trigger={['click']}>
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white"></i></Button>
</Dropdown>
2021-03-18 17:28:53 +08:00
</AlignCenter>
</FlexAJ>
{
dirInfo || fileInfo ?
<div className="listtable">
{
lastCommit &&
<div className="listtablehead">
<User url={getImageUrl(`/${lastCommitAuthor && lastCommitAuthor.image_url}`)} name={lastCommitAuthor && lastCommitAuthor.name} id={lastCommitAuthor && lastCommitAuthor.id} login={lastCommitAuthor && lastCommitAuthor.login}/>
<div className={hideBtn && hide ? "ellipsistxt hidetxt" :"ellipsistxt"}>
<pre id="ptxt">{lastCommit && lastCommit.message}</pre>
</div>
2021-03-18 17:28:53 +08:00
{ hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> }
<span className="ml12 color-grey-9 mt3">{lastCommit && lastCommit.time_from_now}</span>
2021-03-19 16:29:43 +08:00
{ commitCount ? <Link to={`/projects/${owner}/${projectsId}/commits`} className="ml12 color-grey-9"><i className="iconfont icon-tijiao mr3 font-17 color-grey-9"></i>{commitCount}次提交</Link>:"" }
2021-03-18 17:28:53 +08:00
</div>
}
<ul className="listtablebody">
{
treeValuePath && treeValuePath.length > 0 &&
<Path
identifier={projectDetail && projectDetail.identifier}
treeValuePath={treeValuePath}
returnUlr={returnUlr}
returnMain={returnMain}
getPathUrl={getPathUrl}
/>
}
{
dirInfo && dirInfo.length > 0 &&
dirInfo.map((item,key)=>{
return(
<Catalogue
owner={owner}
item={item}
projectsId={projectsId}
goToSubRoot={goToSubRoot}
/>
)
})
}
{
fileInfo &&
<CoderRootFileDetail
{...props}
detail={fileInfo}
readOnly={readOnly}
2021-04-20 15:31:49 +08:00
md={mdFlag}
2021-03-18 17:28:53 +08:00
onEdit={onEdit}
2021-05-26 16:00:55 +08:00
currentBranch={branchName || defaultBranch}
type={projectDetail.type}
2021-03-18 17:28:53 +08:00
></CoderRootFileDetail>
}
</ul>
</div>
2021-03-19 16:29:43 +08:00
: ""
2021-03-18 17:28:53 +08:00
}
2021-03-19 16:29:43 +08:00
{
(dirInfo && dirInfo.length === 0) && (fileInfo && fileInfo.length === 0) ? <Nodata _html="暂未发现文件"/> :""
}
2021-03-18 17:28:53 +08:00
{/* readme文件显示(显示文件详情时不显示readme文件) */}
2021-06-04 10:55:05 +08:00
{ dirInfo && (readme && readme.content) ? <ReadMe ChangeFile={ChangeFile} readme={readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
2021-03-18 17:28:53 +08:00
</div>
</LongWidth>
{
!fileInfo &&
<ShortWidth>
<Gap style={{paddingLeft:"30px"}}>
<div className="panelmenu">
2021-03-24 14:08:10 +08:00
<FlexAJ className="font-18 color-grey-6 mb20" style={{lineHeight:"28px"}}>简介
{projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner") && <i onClick={()=>setOpenModal(true)} className="iconfont icon-anquanshezhi color-grey-9 font-15"></i>}
</FlexAJ>
2021-03-30 10:26:02 +08:00
{desc && <p className="font-14 color-grey-9 mb15 task-hide-2" style={{lineHeight:"22px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}}>{desc}</p>}
2021-03-18 17:28:53 +08:00
{
2021-03-24 14:08:10 +08:00
website &&
2021-03-18 17:28:53 +08:00
<p className="color-grey-6 df">
<i className="iconfont icon-lianjie2 font-15 mr10 color-grey-9"></i>
2021-05-10 11:34:30 +08:00
<a href={website} className="color-grey-6" target="_blank" style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px",textDecoration:"underline"}}>{website}</a>
2021-03-18 17:28:53 +08:00
</p>
}
<p>
<i className="iconfont icon-wenjian4 font-15 mr10 color-grey-9"></i>
<a href="#readme" className="color-grey-6">README.md</a>
</p>
<p className="color-grey-6">
2021-05-10 11:34:30 +08:00
<i className="iconfont icon-dataBase font-15 mr10 color-grey-6"></i>
2021-03-18 17:28:53 +08:00
<span>{projectDetail && projectDetail.size}</span>
</p>
{
projectDetail && projectDetail.license_name &&
<p className="color-grey-6">
2021-05-10 11:34:30 +08:00
<i className="iconfont icon-tianping font-16 mr10 color-grey-3"></i>
2021-03-18 17:28:53 +08:00
<span>{projectDetail.license_name}</span>
</p>
}
</div>
{
lesson_url &&
<div>
<Divider />
<p className="font-16 color-grey-6">实践课程</p>
<a href={lesson_url} target="_blank" className="color-grey-6" style={{textDecoration:"underline"}}>{lesson_url}</a>
</div>
}
2021-03-18 17:28:53 +08:00
{/* 发布 */}
{
projectDetail && projectDetail.release_versions &&
<React.Fragment>
<Divider />
<Releases owner={owner} projectsId={projectsId} releaseVersions={projectDetail.release_versions} history={props.history}/>
</React.Fragment>
}
{/* 贡献者 */}
{
projectDetail && projectDetail.contributors &&
2021-04-23 14:50:52 +08:00
<Contributors contributors={projectDetail && projectDetail.contributors} owner={owner} projectsId={projectsId} />
2021-03-18 17:28:53 +08:00
}
{/* 语言 */}
{ projectDetail && projectDetail.languages &&
<React.Fragment>
<Divider />
<LanguagePower languages={projectDetail.languages}/>
</React.Fragment>
}
</Gap>
</ShortWidth>
}
</Box>
}
</div>
</Spin>
</WhiteBack>
)
}
export default CoderDepot;