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

403 lines
13 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 {Menu, Spin} from 'antd';
import { getImageUrl } from 'educoder';
import { Link } from 'react-router-dom';
import './list.css';
import SelectBranch from '../Branch/SelectBranch';
import CloneAddress from '../Branch/CloneAddress';
import RootTable from './RootTable';
import CoderRootFileDetail from './CoderRootFileDetail';
import { truncateCommitId } from '../common/util';
import RenderHtml from '../../components/render-html';
import axios from 'axios';
/**
* address:http和SSHhttp_url(对应git地址)
* branch:当前分支
* filePath:点击目录时当前目录的路径
* subfileType:保存当前点击目录的文件类型(显示目录列表时才显示新建文件,如果点击的是文件就不显示新建文件按钮)
* readMeContent:根目录下面的readme文件内容
*/
class CoderRootDirectory extends Component{
constructor(props){
super(props);
this.state={
address:"http",
branch:"master",
filePath:undefined,
subFileType:undefined,
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
})
}
if(search && search.indexOf("?url=")>-1){
let url =search.split("?url=")[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:true
})
}
}).catch((error)=>{})
}
ChangeFile=(arr,readOnly)=>{
const { projectsId } = this.props.match.params;
//点击直接跳转页面 加载一次路由
this.props.history.push(`/projects/${projectsId}/coders?url=${arr.path}`);
this.setState({
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({
key:k,
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?url=${str.substr(1)}`);
}else{
list.push({
index:0,
name,path,type
})
}
this.setState({
filePath:list
})
}
// 获取子目录
getFileDetail=(path,ref)=>{
const { projectsId } = this.props.match.params;
const { branch } = this.state;
const url =`/repositories/${projectsId}/sub_entries.json`;
axios.get(url,{
params:{
filepath:path,
ref: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,
subFileType: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,
message:item.commit && item.commit.message,
...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?url=${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="mr10"><i className="iconfont icon-xinjianjianliwodejianli font-20 color-grey-9 fl mt3"></i></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-bianji2 font-20 color-blue"></i></a>
: ""
}
</div>
<div className="commonBox-info">
{
readMeContent[0].content ?
<RenderHtml className="break_word_comments" value={readMeContent[0].content} />
:
<span>暂无~</span>
}
</div>
</div>
)
}
}
// 选择分支
changeBranch=(value)=>{
const { branchList } = this.props;
// let branchLastCommit = branchList && branchList.length >0 && branchList.filter(item=>item.name === value)[0];
// if(branchLastCommit){
this.setState({
branch:value,
// branchLastCommit,
isSpin: true
})
let { search } = this.props.history.location;
if(search && search.indexOf("?url=")>-1){
let url =search.split("?url=")[1];
this.setState({
filePath:url
})
this.getFileDetail(url, value);
}else{
this.getProjectRoot( value );
}
// }
}
render(){
const { rootList , branch ,filePath , fileDetail , subFileType , readMeContent, isSpin } = this.state;
const { branchLastCommit , isManager , isDeveloper , projectDetail } = this.props;
const { projectsId } = this.props.match.params;
const columns = [
{
dataIndex: 'name',
width:"30%",
render: (text,item) => (
<a onClick={()=>this.goToSubRoot(item.path)} className="ml12">
<i className={ item.type === "file" ? "iconfont icon-wenjia font-15 color-green-file mr5":"iconfont icon-wenjianjia1 color-green-file font-15 mr5"}></i>{text}
</a>
),
},{
dataIndex:"commit",
width:"60%",
render:(text,item)=>
(
item.commit && item.commit.message ? <span className="task-hide" style={{display:'block',maxWidth:"670px"}}>{item.commit.message}</span> :""
)
},{
dataIndex:"commit",
width:"10%",
className:"edu-txt-right",
render:(text,item)=>(
item.commit && item.commit.time_from_now ? <a title={item.commit.created_at} className="mr12" style={{cursor:"default",color:"#888"}}>{item.commit.time_from_now}</a> :""
)
}
];
const title = () =>{
if(branchLastCommit && branchLastCommit.last_commit){
return(
<div className="f-wrap-alignCenter">
{
branchLastCommit.author ?
<React.Fragment>
<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>
</React.Fragment>
:""
}
<span className="color-blue flex-1 hide-1">{branchLastCommit.last_commit.message}</span>
<span>{branchLastCommit.last_commit.time_from_now}</span>
<span className="commitKey">{truncateCommitId(branchLastCommit.last_commit.id)}</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 === undefined ? '':`/${filePath}`;
let array = filePath && filePath.split("/");
return(
<Spin spinning={isSpin}>
<div className="main">
<div className="f-wrap-between mb20">
<div className="f-wrap-alignCenter">
<SelectBranch repo_id={projectDetail && projectDetail.repo_id} 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?url=${item}`} className="color-blue subFileName" key={key}>{item}</Link>
:
<Link to={`/projects/${projectsId}/coders?url=${array[key-1]}/${item}`} className="color-blue subFileName" key={key}>{item}</Link>
}
</React.Fragment>
)
})
}
</span>
}
</div>
<div className="f-wrap-alignCenter">
{
subFileType && (isManager || isDeveloper) &&
<p className="mr30">
<Link className="color-blue" to={`/projects/${projectsId}/coders/${branch}/newfile${urlRoot}`} >新建文件</Link>
</p>
}
{
projectDetail && projectDetail.clone_url && <CloneAddress http_url={projectDetail.clone_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;