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

399 lines
12 KiB
JavaScript
Raw Normal View History

2020-03-16 14:12:11 +08:00
import React , { Component } from 'react';
import {Menu, Spin} from 'antd';
import { getImageUrl , markdownToHTML } from 'educoder';
import { Router , Route , Link } from 'react-router-dom';
import Top from './DetailTop';
import './list.css';
2020-04-13 17:45:36 +08:00
import readme_img from '../Images/book.svg';
2020-03-16 14:12:11 +08:00
import SelectBranch from '../Branch/SelectBranch';
import CloneAddress from '../Branch/CloneAddress';
import RootTable from './RootTable';
import CoderRootFileDetail from './CoderRootFileDetail';
import NullData from './NullData';
2020-03-30 10:21:22 +08:00
import { truncateCommitId } from '../common/util';
2020-03-16 14:12:11 +08:00
import axios from 'axios';
2020-04-13 17:45:36 +08:00
import img_fork from "../Images/fork.png";
2020-03-16 14:12:11 +08:00
/**
* address:http和SSHhttp_url(对应git地址)
* branch:当前分支
* filePath:点击目录时当前目录的路径
* subfileType:保存当前点击目录的文件类型显示目录列表时才显示新建文件如果点击的是文件就不显示新建文件按钮
* readMeContent:根目录下面的readme文件内容
*/
2020-04-20 15:37:01 +08:00
2020-03-16 14:12:11 +08:00
class CoderRootDirectory extends Component{
constructor(props){
super(props);
this.state={
address:"http",
branch:"master",
filePath:undefined,
2020-03-16 14:12:11 +08:00
http_url:undefined,
subFileType:"",
readMeContent:undefined,
2020-04-13 17:45:36 +08:00
readMeFile: undefined,
2020-03-16 14:12:11 +08:00
isSpin:true,
branchList:undefined,
fileDetail:undefined,
branchLastCommit:undefined,
rootList:undefined,
2020-04-13 17:45:36 +08:00
readOnly: true
2020-03-16 14:12:11 +08:00
}
}
changeAddress=(address)=>{
this.setState({
address
})
}
2020-03-16 14:12:11 +08:00
componentDidMount=()=>{
this.Init();
}
componentDidUpdate=(prevState)=>{
const {location} = this.props;
const prevlocation = prevState && prevState.location;
if(location !== prevlocation){
this.setState({
isSpin:true
})
this.Init();
}
}
2020-03-30 18:51:30 +08:00
Init=()=>{
2020-03-16 14:12:11 +08:00
let { search } = this.props.history.location;
let branchName = undefined;
if(search && search.indexOf("branch")>-1){
branchName = search.split("branch=")[1];
2020-03-16 14:12:11 +08:00
this.setState({
branch:branchName
})
}
const { pathname } = this.props.location;
if(pathname && pathname.indexOf("/filesurl/")>-1){
let url =pathname.split("filesurl/")[1];
this.setState({
filePath:url
})
this.getFileDetail(url);
}else{
const { branch } = this.state;
this.getProjectRoot( branchName || branch);
}
}
// 页面地址返回到主目录
returnMain=(branch)=>{
const { projectsId } = this.props.match.params;
this.props.history.push(`/projects/${projectsId}/coders`);
this.getProjectRoot(branch);
2020-03-16 14:12:11 +08:00
}
// 获取根目录
getProjectRoot=(branch)=>{
2020-03-20 20:50:30 +08:00
const { projectsId } = this.props.match.params;
const url = `/repositories/${projectsId}/entries.json`;
2020-03-16 14:12:11 +08:00
axios.get((url),{
params:{
branch
}
}).then((result)=>{
if(result){
if(result && result.data && result.data.length > 0){
this.setState({
filePath:undefined,
2020-03-16 14:12:11 +08:00
fileDetail:undefined,
isSpin: false
})
this.renderData(result.data);
}
this.setState({
rootList:result.data,
2020-04-14 15:06:02 +08:00
subFileType: "dir"
2020-03-16 14:12:11 +08:00
})
}
}).catch((error)=>{})
}
2020-04-13 17:45:36 +08:00
ChangeFile=(arr,readOnly)=>{
const { projectsId } = this.props.match.params;
2020-03-30 18:51:30 +08:00
//点击直接跳转页面 加载一次路由
this.props.history.push(`/projects/${projectsId}/coders/filesurl/${arr.path}`);
2020-03-16 14:12:11 +08:00
this.setState({
2020-04-13 17:45:36 +08:00
subFileType:arr.type,
readOnly: readOnly
2020-03-16 14:12:11 +08:00
})
}
renderUrl=(name,path,type)=>{
let list =[];
const { filePath } = this.state;
if(path.indexOf("/")){
const array = path.split("/");
let str = "";
array.map((i,k)=>{
str += '/'+i;
return list.push({
index:k,
name:i,
path:str.substr(1),
type:(filePath && filePath.length>0) ? (filePath[k] ? filePath[k].type : type) : type
})
})
const { projectsId } = this.props.match.params;
//点击直接跳转页面 加载一次路由
this.props.history.push(`/projects/${projectsId}/coders/filesurl/${str.substr(1)}`);
2020-03-16 14:12:11 +08:00
}else{
list.push({
index:0,
name,path,type
})
}
this.setState({
filePath:list
})
}
// 获取子目录
2020-04-23 14:11:43 +08:00
getFileDetail=(path,ref)=>{
2020-03-16 14:12:11 +08:00
const { projectsId } = this.props.match.params;
const { branch } = this.state;
2020-03-20 20:50:30 +08:00
const url =`/repositories/${projectsId}/sub_entries.json`;
2020-03-16 14:12:11 +08:00
axios.get(url,{
params:{
filepath:path,
2020-04-23 14:11:43 +08:00
ref:ref || branch
2020-03-16 14:12:11 +08:00
}
}).then((result)=>{
if(result && result.data && result.data.length > 0){
// 当前返回的子目录只有一条数据,且这条数据返回的是文件类型
if(result.data.length === 1 && result.data[0].type === "file"){
2020-03-16 14:12:11 +08:00
this.setState({
fileDetail:result.data,
rootList:undefined,
isSpin:false
2020-03-16 14:12:11 +08:00
})
}else{
this.setState({
fileDetail:undefined,
rootList:result.data,
isSpin:false
2020-03-16 14:12:11 +08:00
})
this.renderData(result.data)
}
}
}).catch((error)=>{
console.log(error);
})
}
renderData=(data)=>{
const rootList = [];
const readMeContent = [];
2020-04-13 17:45:36 +08:00
const readMeFile = [];
2020-03-16 14:12:11 +08:00
data && data.map((item,key)=>{
rootList.push({
key,
...item
})
if(item.name === 'README.md'){
readMeContent.push({...item})
2020-04-13 17:45:36 +08:00
readMeFile.push({...item})
2020-03-16 14:12:11 +08:00
}
})
this.setState({
rootList:rootList,
2020-04-13 17:45:36 +08:00
readMeContent,
readMeFile
2020-03-16 14:12:11 +08:00
})
}
// 点击跳转到子目录
goToSubRoot=(path)=>{
const { projectsId } = this.props.match.params;
this.props.history.push(`/projects/${projectsId}/coders/filesurl/${path}`);
}
2020-03-16 14:12:11 +08:00
// readme文件内容
2020-04-13 17:45:36 +08:00
renderReadMeContent=(readMeContent, permission)=>{
const { fileDetail,readMeFile } = this.state;
2020-03-16 14:12:11 +08:00
if(fileDetail){return;}
if(readMeContent && readMeContent.length > 0){
return(
<div className="commonBox">
2020-04-13 17:45:36 +08:00
<div className="commonBox-title">
<span className="mr5"><img src={readme_img} alt="" width="16px"/></span>
<span className="commonBox-title-read">{readMeContent[0].name}</span>
{
permission ?
<a onClick={()=>this.ChangeFile(readMeFile[0],false)} className="ml20 pull-right"><i className="iconfont icon-bianji font-15 color-grey-6"></i></a>
: ""
}
</div>
2020-03-16 14:12:11 +08:00
<div className="commonBox-info">
{
readMeContent[0].content ?
<div className={"markdown-body"} dangerouslySetInnerHTML={{__html: markdownToHTML(readMeContent[0].content).replace(/▁/g, "▁▁▁")}}></div>
:
<span>暂无~</span>
}
</div>
</div>
)
}
}
// 选择分支
changeBranch=(value)=>{
const { branchList } = this.props;
2020-03-20 16:49:41 +08:00
let branchLastCommit = branchList && branchList.length >0 && branchList.filter(item=>item.name === value)[0];
2020-03-16 14:12:11 +08:00
this.setState({
2020-03-20 16:49:41 +08:00
branch:branchLastCommit && branchLastCommit.name,
2020-03-16 14:12:11 +08:00
branchLastCommit,
2020-03-20 16:49:41 +08:00
http_url:branchLastCommit && branchLastCommit.http_url,
2020-03-16 14:12:11 +08:00
isSpin: true
})
2020-04-23 14:53:03 +08:00
if(branchLastCommit){
const { pathname } = this.props.location;
if(pathname && pathname.indexOf("/filesurl/")>-1){
let url =pathname.split("filesurl/")[1];
this.setState({
filePath:url
})
this.getFileDetail(url, branchLastCommit.name);
}else{
this.getProjectRoot( branchLastCommit.name );
}
// this.props.history.location.search.replace( branchLastCommit.name );
2020-04-23 14:11:43 +08:00
}
2020-03-16 14:12:11 +08:00
}
render(){
const { rootList , branch ,filePath , fileDetail , subFileType , readMeContent, isSpin } = this.state;
2020-03-16 14:12:11 +08:00
const { branchLastCommit , http_url , isManager , isDeveloper } = this.props;
2020-03-20 21:40:43 +08:00
const { projectsId } = this.props.match.params;
2020-03-16 14:12:11 +08:00
2020-03-16 14:12:11 +08:00
const columns = [
{
dataIndex: 'name',
width:"100%",
render: (text,item) => (
<a onClick={()=>this.goToSubRoot(item.path)}>
2020-03-16 14:12:11 +08:00
<i className={ item.type === "file" ? "iconfont icon-zuoye font-15 color-blue mr5":"iconfont icon-wenjian font-15 color-blue mr5"}></i>{text}
</a>
),
}
];
const title = () =>{
if(branchLastCommit && branchLastCommit.last_commit){
return(
<div className="f-wrap-alignCenter">
{
branchLastCommit.author ?
<React.Fragment>
2020-04-23 16:26:42 +08:00
<Link to={`/users/${branchLastCommit.author.login}/projects`} className="show-user-link">
<img src={getImageUrl(`images/${branchLastCommit.author.image_url}`)} className="radius mr10" width="32" height="32" alt=""/>
<span className="mr15">{branchLastCommit.author.login}</span>
</Link>
2020-03-16 14:12:11 +08:00
</React.Fragment>
:""
}
<span className="color-blue flex-1 hide-1">{branchLastCommit.last_commit.message}</span>
2020-04-09 18:13:26 +08:00
<span className="commitKey">{truncateCommitId(branchLastCommit.last_commit.id)}</span>
2020-03-16 14:12:11 +08:00
<span>{branchLastCommit.last_commit.time_from_now}</span>
</div>
)
}else{
return undefined;
}
}
const downloadUrl = ()=>{
if(branchLastCommit && branchLastCommit.zip_url){
return(
<Menu>
<Menu.Item><a href={branchLastCommit.zip_url}>ZIP</a></Menu.Item>
<Menu.Item><a href={branchLastCommit.tar_url}>TAR.GZ</a></Menu.Item>
</Menu>
)
}
}
2020-04-22 18:45:03 +08:00
const urlRoot = filePath === undefined ? '':`/${filePath}`;
2020-03-31 15:07:27 +08:00
const { projectDetail } = this.props;
let array = filePath && filePath.split("/");
2020-03-16 14:12:11 +08:00
return(
<Spin spinning={isSpin}>
2020-04-21 16:30:51 +08:00
<div>
<Top { ...this.props } {...this.state} />
<div className="f-wrap-between mt20">
<div className="f-wrap-alignCenter">
<SelectBranch branch={branch} changeBranch={this.changeBranch} {...this.props} {...this.state}></SelectBranch>
{
filePath &&
<span className="ml20 font-16">
<a onClick={()=>this.returnMain(branch)} className="color-blue">{ projectDetail && projectDetail.identifier }</a>
2020-04-21 16:30:51 +08:00
{
array && array.map((item,key)=>{
return(
<React.Fragment>
{
key === array.length-1 ?
<span className="color-grey-6 subFileName" key={key}>{item}</span>
:
key === 0?
2020-04-21 16:30:51 +08:00
<Link to={`/projects/${projectsId}/coders/filesurl/${item}`} className="color-blue subFileName" key={key}>{item}</Link>
:
<Link to={`/projects/${projectsId}/coders/filesurl/${array[key-1]}/${item}`} className="color-blue subFileName" key={key}>{item}</Link>
}
</React.Fragment>
)
})
}
</span>
2020-04-21 16:30:51 +08:00
}
2020-03-16 14:12:11 +08:00
</div>
2020-04-21 16:30:51 +08:00
<div className="f-wrap-alignCenter">
2020-04-22 19:05:03 +08:00
{
subFileType !== "file" && (isManager || isDeveloper) &&
2020-04-21 16:30:51 +08:00
<p className="addFile mr30">
<Link to={`/projects/${projectsId}/coders/${branch}/newfile${urlRoot}`} >新建文件</Link>
</p>
2020-04-22 19:05:03 +08:00
}
{
2020-04-21 16:30:51 +08:00
http_url && <CloneAddress http_url={http_url} downloadUrl={downloadUrl} showNotification={this.props.showNotification}></CloneAddress>
}
2020-04-21 16:30:51 +08:00
</div>
</div>
2020-04-21 16:30:51 +08:00
{/* 主目录列表 */}
{
rootList &&
<RootTable columns = {columns} data={rootList} title={() => title()}></RootTable>
}
{/* 子目录列表、文件 */}
{
fileDetail && fileDetail.length>0 &&
<CoderRootFileDetail detail = {fileDetail[0]} {...this.props} {...this.state} readOnly={this.state.readOnly}></CoderRootFileDetail>
}
{/* readme.txt (isManager || isDeveloper)*/}
{ this.renderReadMeContent(readMeContent,(isManager || isDeveloper)) }
</div>
</Spin>
2020-03-16 14:12:11 +08:00
)
}
}
export default CoderRootDirectory;