forked from Gitlink/forgeplus-react
385 lines
12 KiB
JavaScript
385 lines
12 KiB
JavaScript
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';
|
||
import readme_img from '../Images/book.svg';
|
||
import SelectBranch from '../Branch/SelectBranch';
|
||
import CloneAddress from '../Branch/CloneAddress';
|
||
import RootTable from './RootTable';
|
||
import CoderRootFileDetail from './CoderRootFileDetail';
|
||
import NullData from './NullData';
|
||
import { truncateCommitId } from '../common/util';
|
||
|
||
import axios from 'axios';
|
||
import img_fork from "../Images/fork.png";
|
||
/**
|
||
* address:http和SSH,http_url(对应git地址)
|
||
* branch:当前分支
|
||
* filePath:点击目录时当前目录的路径
|
||
* subfileType:保存当前点击目录的文件类型(显示目录列表时才显示新建文件,如果点击的是文件就不显示新建文件按钮)
|
||
* readMeContent:根目录下面的readme文件内容
|
||
*/
|
||
|
||
class CoderRootDirectory extends Component{
|
||
constructor(props){
|
||
super(props);
|
||
this.state={
|
||
address:"http",
|
||
branch:"master",
|
||
filePath:undefined,
|
||
http_url:undefined,
|
||
subFileType:"",
|
||
readMeContent:undefined,
|
||
readMeFile: undefined,
|
||
|
||
isSpin:true,
|
||
|
||
branchList:undefined,
|
||
fileDetail:undefined,
|
||
branchLastCommit:undefined,
|
||
|
||
rootList:undefined,
|
||
readOnly: true
|
||
}
|
||
}
|
||
changeAddress=(address)=>{
|
||
this.setState({
|
||
address
|
||
})
|
||
}
|
||
|
||
|
||
componentDidMount=()=>{
|
||
this.Init();
|
||
}
|
||
|
||
componentDidUpdate=(prevState)=>{
|
||
const {location} = this.props;
|
||
const prevlocation = prevState && prevState.location;
|
||
if(location !== prevlocation){
|
||
this.setState({
|
||
isSpin:true
|
||
})
|
||
this.Init();
|
||
}
|
||
}
|
||
|
||
Init=()=>{
|
||
let { search } = this.props.history.location;
|
||
let branchName = undefined;
|
||
if(search && search.indexOf("branch")>-1){
|
||
branchName = search.split("branch=")[1];
|
||
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);
|
||
}
|
||
|
||
// 获取根目录
|
||
getProjectRoot=(branch)=>{
|
||
const { projectsId } = this.props.match.params;
|
||
const url = `/repositories/${projectsId}/entries.json`;
|
||
axios.get((url),{
|
||
params:{
|
||
branch
|
||
}
|
||
}).then((result)=>{
|
||
if(result){
|
||
if(result && result.data && result.data.length > 0){
|
||
this.setState({
|
||
filePath:undefined,
|
||
fileDetail:undefined,
|
||
isSpin: false
|
||
})
|
||
this.renderData(result.data);
|
||
}
|
||
this.setState({
|
||
rootList:result.data,
|
||
subFileType: "dir"
|
||
})
|
||
}
|
||
|
||
}).catch((error)=>{})
|
||
}
|
||
|
||
ChangeFile=(arr,readOnly)=>{
|
||
const { projectsId } = this.props.match.params;
|
||
//点击直接跳转页面 加载一次路由
|
||
this.props.history.push(`/projects/${projectsId}/coders/filesurl/${arr.path}`);
|
||
this.setState({
|
||
subFileType:arr.type,
|
||
readOnly: readOnly
|
||
})
|
||
}
|
||
|
||
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)}`);
|
||
}else{
|
||
list.push({
|
||
index:0,
|
||
name,path,type
|
||
})
|
||
}
|
||
this.setState({
|
||
filePath:list
|
||
})
|
||
}
|
||
|
||
// 获取子目录
|
||
getFileDetail=(path)=>{
|
||
const { projectsId } = this.props.match.params;
|
||
const { branch } = this.state;
|
||
const url =`/repositories/${projectsId}/sub_entries.json`;
|
||
|
||
axios.get(url,{
|
||
params:{
|
||
filepath:path,
|
||
ref:branch
|
||
}
|
||
}).then((result)=>{
|
||
if(result && result.data && result.data.length > 0){
|
||
// 当前返回的子目录只有一条数据,且这条数据返回的是文件类型
|
||
if(result.data.length === 1 && result.data[0].type === "file"){
|
||
this.setState({
|
||
fileDetail:result.data,
|
||
rootList:undefined,
|
||
isSpin:false
|
||
})
|
||
}else{
|
||
this.setState({
|
||
fileDetail:undefined,
|
||
rootList:result.data,
|
||
isSpin:false
|
||
})
|
||
this.renderData(result.data)
|
||
}
|
||
}
|
||
}).catch((error)=>{
|
||
console.log(error);
|
||
})
|
||
}
|
||
|
||
renderData=(data)=>{
|
||
const rootList = [];
|
||
const readMeContent = [];
|
||
const readMeFile = [];
|
||
data && data.map((item,key)=>{
|
||
rootList.push({
|
||
key,
|
||
...item
|
||
})
|
||
if(item.name === 'README.md'){
|
||
readMeContent.push({...item})
|
||
readMeFile.push({...item})
|
||
}
|
||
})
|
||
this.setState({
|
||
rootList:rootList,
|
||
readMeContent,
|
||
readMeFile
|
||
})
|
||
}
|
||
|
||
// 点击跳转到子目录
|
||
goToSubRoot=(path)=>{
|
||
const { projectsId } = this.props.match.params;
|
||
this.props.history.push(`/projects/${projectsId}/coders/filesurl/${path}`);
|
||
}
|
||
|
||
// readme文件内容
|
||
renderReadMeContent=(readMeContent, permission)=>{
|
||
const { fileDetail,readMeFile } = this.state;
|
||
if(fileDetail){return;}
|
||
if(readMeContent && readMeContent.length > 0){
|
||
return(
|
||
<div className="commonBox">
|
||
<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>
|
||
<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;
|
||
|
||
let branchLastCommit = branchList && branchList.length >0 && branchList.filter(item=>item.name === value)[0];
|
||
this.setState({
|
||
branch:branchLastCommit && branchLastCommit.name,
|
||
branchLastCommit,
|
||
http_url:branchLastCommit && branchLastCommit.http_url,
|
||
isSpin: true
|
||
})
|
||
this.Init();
|
||
|
||
}
|
||
render(){
|
||
const { rootList , branch ,filePath , fileDetail , subFileType , readMeContent, isSpin } = this.state;
|
||
const { branchLastCommit , http_url , isManager , isDeveloper } = this.props;
|
||
const { projectsId } = this.props.match.params;
|
||
|
||
|
||
const columns = [
|
||
{
|
||
dataIndex: 'name',
|
||
width:"100%",
|
||
render: (text,item) => (
|
||
<a onClick={()=>this.goToSubRoot(item.path)}>
|
||
<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>
|
||
<img src={getImageUrl(`images/${branchLastCommit.author.image_url}`)} className="radius mr10" width="32" height="32" alt=""/>
|
||
<span className="mr15">{branchLastCommit.author.login}</span>
|
||
</React.Fragment>
|
||
:""
|
||
}
|
||
<span className="color-blue flex-1 hide-1">{branchLastCommit.last_commit.message}</span>
|
||
<span className="commitKey">{truncateCommitId(branchLastCommit.last_commit.id)}</span>
|
||
<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>
|
||
)
|
||
}
|
||
}
|
||
|
||
const urlRoot = `/${filePath}`;
|
||
const { projectDetail } = this.props;
|
||
let array = filePath && filePath.split("/");
|
||
return(
|
||
<Spin spinning={isSpin}>
|
||
<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>
|
||
{
|
||
array && array.map((item,key)=>{
|
||
return(
|
||
<React.Fragment>
|
||
{
|
||
key === array.length-1 ?
|
||
<span className="color-grey-6 subFileName" key={key}>{item}</span>
|
||
:
|
||
key === 0?
|
||
<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>
|
||
}
|
||
</div>
|
||
<div className="f-wrap-alignCenter">
|
||
{
|
||
subFileType !== "file" && (isManager || isDeveloper) &&
|
||
<p className="addFile mr30">
|
||
<Link to={`/projects/${projectsId}/coders/${branch}/newfile${urlRoot}`} >新建文件</Link>
|
||
</p>
|
||
}
|
||
{
|
||
http_url && <CloneAddress http_url={http_url} downloadUrl={downloadUrl} showNotification={this.props.showNotification}></CloneAddress>
|
||
}
|
||
</div>
|
||
</div>
|
||
{/* 主目录列表 */}
|
||
{
|
||
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>
|
||
)
|
||
}
|
||
}
|
||
export default CoderRootDirectory;
|