切换标签

This commit is contained in:
caishi 2020-06-03 09:56:07 +08:00
parent d8b2244b9c
commit 7bdd2820ea
13 changed files with 455 additions and 527 deletions

View File

@ -1,7 +1,5 @@
import React, { useEffect, useRef, useState } from 'react'
import * as monaco from 'monaco-editor'
import ResizeObserver from 'resize-observer-polyfill';
import './TPIMonacoConfig'
import './index.css'
function processSize(size) {
@ -10,24 +8,6 @@ function processSize(size) {
function noop() { }
let __prevent_trigger_change_event = false
function debounce(func, wait, immediate) {
var timeout
return function () {
var context = this, args = arguments
var later = function () {
timeout = null
if (!immediate) func.apply(context, args)
};
var callNow = immediate && !timeout
clearTimeout(timeout)
timeout = setTimeout(later, wait)
if (callNow) func.apply(context, args)
}
}
//monaco-language
// 'abap' | 'apex' | 'azcli' | 'bat' | 'cameligo' | 'clojure' | 'coffee' | 'cpp' | 'csharp' | 'csp' | 'css' | 'dockerfile' | 'fsharp' | 'go' | 'graphql' | 'handlebars' | 'html' | 'ini' | 'java' | 'javascript' | 'json' | 'kotlin' | 'less' | 'lua' | 'markdown' | 'mips' | 'msdax' | 'mysql' | 'objective-c' | 'pascal' | 'pascaligo' | 'perl' | 'pgsql' | 'php' | 'postiats' | 'powerquery' | 'powershell' | 'pug' | 'python' | 'r' | 'razor' | 'redis' | 'redshift' | 'restructuredtext' | 'ruby' | 'rust' | 'sb' | 'scheme' | 'scss' | 'shell' | 'solidity' | 'sophia' | 'sql' | 'st' | 'swift' | 'tcl' | 'twig' | 'typescript' | 'vb' | 'xml' | 'yaml';
const DICT = {
"Python3.6": 'python',
"Python2.7": 'python',
@ -86,6 +66,7 @@ export function getLanguageByMirrorName(mirror_name = []) {
return DICT[lang] || lang
}
let monaco = null
export default ({
width = '100%',
height = '100%',
@ -117,7 +98,7 @@ export default ({
ro.observe(editorEl.current)
}
return ro
}
}
useEffect(() => {
let instance = editor.current.instance
@ -143,56 +124,57 @@ export default ({
}
useEffect(() => {
editor.current.instance = monaco.editor.create(
editorEl.current, {
value,
language: getLanguageByMirrorName(language),
theme,
...options
},
overrideServices
)
const instance = editor.current.instance
window.editor_monaco = instance //
editorDidMount(instance, monaco)
import(/* webpackChunkName: "monaco-editor" */ 'monaco-editor/esm/vs/editor/editor.api.js').then((mod) => {
monaco = mod
editor.current.instance = monaco.editor.create(
editorEl.current, {
value,
language: getLanguageByMirrorName(language),
theme,
...options
},
overrideServices
)
const instance = editor.current.instance
editorDidMount(instance, monaco)
editor.current.subscription = instance.onDidChangeModelContent(event => {
if (!__prevent_trigger_change_event) {
onChange(instance.getValue(), event);
editor.current.subscription = instance.onDidChangeModelContent(event => {
if (!__prevent_trigger_change_event) {
onChange(instance.getValue(), event);
}
})
if (onEditBlur) {
instance.onDidBlurEditorWidget(() => { onEditBlur(instance.getValue()) })
}
})
if (onEditBlur) {
instance.onDidBlurEditorWidget(() => { onEditBlur(instance.getValue()) })
}
if (onFocus) {
instance.onDidFocusEditorText(() => { onFocus(instance.getValue()) })
}
if (forbidCopy) {
instance.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_C, () => null)
instance.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_V, () => null)
instance.onDidPaste((pos) => { editor.current.pastePos = pos })
window.addEventListener('paste', onPaste)
}
let ro = onLayout()
setInit(true)
return () => {
const el = editor.current.instance
el.dispose()
const model = el.getModel()
if (model) {
model.dispose()
}
if (editor.current.subscription) {
editor.current.subscription.dispose()
if (onFocus) {
instance.onDidFocusEditorText(() => { onFocus(instance.getValue()) })
}
if (forbidCopy) {
window.removeEventListener('paste', onPaste)
instance.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_V, () => null)
instance.onDidPaste((pos) => { editor.current.pastePos = pos })
window.addEventListener('paste', onPaste)
}
ro.unobserve(editorEl.current)
}
let ro = onLayout()
setInit(true)
return () => {
const el = editor.current.instance
el.dispose()
const model = el.getModel()
if (model) {
model.dispose()
}
if (editor.current.subscription) {
editor.current.subscription.dispose()
}
if (forbidCopy) {
window.removeEventListener('paste', onPaste)
}
ro.unobserve(editorEl.current)
}
})
}, [])
useEffect(() => {
@ -200,7 +182,6 @@ export default ({
if (instance && init) {
let lang = getLanguageByMirrorName(language)
monaco.editor.setModelLanguage(instance.getModel(), lang)
console.log(`model language was changed to ${instance.getModel().getLanguageIdentifier().language}`)
}
}, [language, init])
@ -235,4 +216,42 @@ export default ({
return (
<div id='extend-challenge-file-edit' ref={editorEl} style={style} ></div>
)
}
}
export function DiffEditor({ width, height, original, modified, language, options = {} }) {
const editorEl = useRef()
useEffect(() => {
if (editorEl.current) {
import(/* webpackChunkName: "monaco-editor" */ 'monaco-editor/esm/vs/editor/editor.api.js').then((mod) => {
monaco = mod
editorEl.current.instance = monaco.editor.createDiffEditor(editorEl.current, {
readOnly: true,
...options,
})
})
}
}, [editorEl.current])
useEffect(() => {
if (editorEl.current) {
let instance = editorEl.current.instance
instance.setModel({
original: monaco.editor.createModel(original, language),
modified: monaco.editor.createModel(modified, language)
})
}
}, [original, modified, language, editorEl.current])
const fixedWidth = processSize(width)
const fixedHeight = processSize(height)
const style = {
width: fixedWidth,
height: fixedHeight
}
return (
<div ref={editorEl} style={style} ></div>
)
}

View File

@ -2,31 +2,56 @@ import React , { Component } from 'react';
import { Dropdown , Icon , Input } from 'antd';
import "./branch.css"
import axios from 'axios';
const $ = window.$;
class SelectBranch extends Component{
constructor(props){
super(props);
this.state={
visible:false,
value:undefined
value:undefined,
search:"branch",
tags:undefined
}
}
componentDidMount() {
document.body.addEventListener('click', e => {
if (e.target && (e.target.matches('#m-btn') || e.target.matches("#input-btn")|| e.target.matches("#ul-btn"))) {
let v= this.state.visible;
let other = e.target && (e.target.matches('#m-btn') || e.target.matches("#navUl-btn") || e.target.matches("#input-btn")|| e.target.matches("#ul-btn"));
let classF = e.target.className === "navs" || e.target.className === "navs active";
if(e.target && e.target.matches("#down-btn")){
this.setState({
visible:!v,
value:undefined
})
return;
}else if (other || classF) {
return;
}
if($(e.target)[0].className === "task-hide ulALink")return;
this.setState({
visible:false,
value:undefined
})
} else{
this.setState({
visible:false,
value:undefined
})
}
});
}
componentDidUpdate=(prevProps)=>{
if(this.props.repo_id && prevProps.repo_id != this.props.repo_id){
this.getTagList();
}
}
ChangeVisible=(visible)=>{
this.setState({
visible:!visible
getTagList=()=>{
const { repo_id } = this.props;
const url = `/repositories/${repo_id}/tags.json`;
axios.get(url).then((result)=>{
if(result){
this.setState({
tags:result.data
})
}
}).catch(error=>{
console.log(error);
})
}
@ -56,15 +81,31 @@ class SelectBranch extends Component{
changeBranch && changeBranch(value);
}
// 切换搜索的列表
changeSearch=(search)=>{
this.setState({
search
})
}
render(){
const { visible , value } = this.state;
const { visible , value , search , tags } = this.state;
const { branchs , branch } = this.props;
let branchsFilter = value ? (branchs && branchs.length>0 && branchs.filter(item=>item.name.indexOf(value)>-1)):branchs;
let array = branchs;
if(search === "tag"){
array = tags;
}
let branchsFilter = value ? (array && array.length>0 && array.filter(item=>item.name.indexOf(value)>-1)) : array;
const menu = (
<div className="branchOptions" id="m-btn" onClick={this.stopPropagations}>
<div className="padding10 bor-bottom-greyE">
<Input placeholder="请输入分支名称进行搜索" autocomplete="off" id="input-btn" value={value} className="OptionsInput" onChange={this.changeValue} onClick={this.InputClick}/>
<Input placeholder="请输入分支或标签名称搜索" autocomplete="off" id="input-btn" value={value} className="OptionsInput" onChange={this.changeValue} onClick={this.InputClick}/>
<ul className="navUl" id="navUl-btn">
<li className={search ==="branch"?"navs active":"navs"} onClick={()=>this.changeSearch("branch")}><i className="iconfont icon-fenzhi1 font-14 mr3"></i></li>
<li className={search ==="tag"?"navs active":"navs"} onClick={()=>this.changeSearch("tag")}><i className="iconfont icon-biaoqian3 font-14 mr3"></i></li>
</ul>
</div>
<ul className="OptionsUl" id="ul-btn">
{
@ -78,11 +119,11 @@ class SelectBranch extends Component{
</div>
);
return(
<div className="branchDropdown f-wrap-alignCenter" onClick={()=>this.ChangeVisible(visible)}>
<div className="branchDropdown f-wrap-alignCenter" >
<Dropdown overlay={menu} trigger={['click']} placement="bottomLeft" visible={visible}>
<span>
<span id="down-btn">
<span>
<span className="color-grey-9 mr3">分支:</span>
<span className="color-grey-9 mr3">{search ==="branch"?"分支":"标签"}:</span>
<a className="ant-dropdown-link">
{branch}
</a>

View File

@ -43,4 +43,16 @@
padding-left: 4px;
line-height: 32px;
width: 100%;
}
.navUl{
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 5px;
}
.navUl li{
cursor: pointer;
}
.navUl li.active{
color:#5091FF;
}

View File

@ -59,17 +59,17 @@ class CoderRootCommit extends Component{
}).catch((error)=>{console.log(error)})
}
// 切换分支
// 切换分支 search:tag为根据标签搜索
changeBranch=(value)=>{
const { branchList } = this.props;
let branchLastCommit = branchList && branchList.filter(item=>item.name === value)[0];
// let branchLastCommit = branchList && branchList.filter(item=>item.name === value)[0];
const { page , limit } = this.state;
this.setState({
isSpin:true,
branch:branchLastCommit.name,
branch:value,
})
this.getCommitList(branchLastCommit.name , page , limit);
this.getCommitList(value , page , limit);
}
ChangePage=(page)=>{
@ -79,8 +79,7 @@ class CoderRootCommit extends Component{
render(){
const { branch , data , dataCount , limit , page , isSpin } = this.state;
const { branchs } = this.props;
const { branchs , projectDetail } = this.props;
const title =()=>{
return(
<div className="f-wrap-between" style={{alignItems:"center"}}>
@ -102,7 +101,7 @@ class CoderRootCommit extends Component{
<React.Fragment>
<div className="main">
<div className="f-wrap-between">
<SelectBranch branch={branch} branchs={branchs} changeBranch={this.changeBranch}></SelectBranch>
<SelectBranch repo_id={projectDetail && projectDetail.repo_id} branch={branch} branchs={branchs} changeBranch={this.changeBranch}></SelectBranch>
</div>
<Spin spinning={isSpin}>
<div className="commonBox">

View File

@ -27,7 +27,6 @@ class CoderRootDirectory extends Component{
address:"http",
branch:"master",
filePath:undefined,
http_url:undefined,
subFileType:undefined,
readMeContent:undefined,
readMeFile: undefined,
@ -253,12 +252,11 @@ class CoderRootDirectory extends Component{
// 选择分支
changeBranch=(value)=>{
const { branchList } = this.props;
let branchLastCommit = branchList && branchList.length >0 && branchList.filter(item=>item.name === value)[0];
if(branchLastCommit){
// let branchLastCommit = branchList && branchList.length >0 && branchList.filter(item=>item.name === value)[0];
// if(branchLastCommit){
this.setState({
branch:value,
branchLastCommit,
http_url:branchLastCommit && branchLastCommit.http_url,
// branchLastCommit,
isSpin: true
})
let { search } = this.props.history.location;
@ -271,11 +269,11 @@ class CoderRootDirectory extends Component{
}else{
this.getProjectRoot( value );
}
}
// }
}
render(){
const { rootList , branch ,filePath , fileDetail , subFileType , readMeContent, isSpin } = this.state;
const { branchLastCommit , http_url , isManager , isDeveloper } = this.props;
const { branchLastCommit , isManager , isDeveloper , projectDetail } = this.props;
const { projectsId } = this.props.match.params;
const columns = [
@ -340,14 +338,13 @@ class CoderRootDirectory extends Component{
}
const urlRoot = filePath === undefined ? '':`/${filePath}`;
const { projectDetail } = this.props;
let array = filePath && filePath.split("/");
return(
<Spin spinning={isSpin}>
<div className="main">
<div className="f-wrap-between mb20">
<div className="f-wrap-alignCenter">
<SelectBranch branch={branch} changeBranch={this.changeBranch} {...this.props} {...this.state}></SelectBranch>
<SelectBranch repo_id={projectDetail && projectDetail.repo_id} branch={branch} changeBranch={this.changeBranch} {...this.props} {...this.state}></SelectBranch>
{
filePath &&
@ -381,7 +378,7 @@ class CoderRootDirectory extends Component{
</p>
}
{
http_url && <CloneAddress http_url={http_url} downloadUrl={downloadUrl} showNotification={this.props.showNotification}></CloneAddress>
projectDetail && projectDetail.clone_url && <CloneAddress http_url={projectDetail.clone_url} downloadUrl={downloadUrl} showNotification={this.props.showNotification}></CloneAddress>
}
</div>
</div>

View File

@ -1,333 +0,0 @@
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 SelectBranch from '../Branch/SelectBranch';
import CloneAddress from '../Branch/CloneAddress';
import RootTable from './RootTable';
import CoderRootFileDetail from './CoderRootFileDetail';
import NullData from './NullData';
import axios from 'axios';
/**
* address:http和SSHhttp_url(对应git地址)
* branch:当前分支
* filePath:点击目录时当前目录的路径
* subfileType:保存当前点击目录的文件类型显示目录列表时才显示新建文件如果点击的是文件就不显示新建文件按钮
* readMeContent:根目录下面的readme文件内容
*/
class CoderRootDirectorytext extends Component{
constructor(props){
super(props);
this.state={
address:"http",
branch:"master",
filePath:[],
http_url:undefined,
subFileType:"",
readMeContent:undefined,
isSpin:true,
branchList:undefined,
fileDetail:undefined,
branchLastCommit:undefined,
rootData:undefined
}
}
changeAddress=(address)=>{
this.setState({
address
})
}
componentDidMount=()=>{
let { search } = this.props.history.location;
let branchName = undefined;
if(search && search.indexOf("branch")>-1){
branchName = search.split("=")[1];
this.setState({
branch:branchName
})
}
const { branch } = this.state;
this.getProjectRoot(branchName || 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:[],
fileDetail:undefined,
isSpin: false
})
this.renderData(result.data);
}
this.setState({
rootData:result.data
})
}
}).catch((error)=>{})
}
ChangeFile=(arr,index)=>{
this.renderUrl(arr.name,arr.path,arr.type);
//点击直接跳转页面 加载一次路由
this.getFileDetail(arr);
this.setState({
subFileType:arr.type
})
}
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
})
})
}else{
list.push({
index:0,
name,path,type
})
}
this.setState({
filePath:list
})
}
// 获取子目录
getFileDetail=(arr)=>{
const { projectsId } = this.props.match.params;
const { branch } = this.state;
const url =`/repositories/${projectsId}/sub_entries.json`;
axios.get(url,{
params:{
filepath:arr.path,
ref:branch
}
}).then((result)=>{
if(result && result.data && result.data.length > 0){
if(arr.type==="file"){
this.setState({
fileDetail:result.data[0],
rootList:undefined
})
}else{
if(arr.type===""){
this.props.showNotification('该文件夹下已无文件')
return
}
this.setState({
fileDetail:undefined
})
this.renderData(result.data)
}
}
}).catch((error)=>{
console.log(error);
})
}
renderData=(data)=>{
const rootList = [];
const readMeContent = [];
data && data.map((item,key)=>{
rootList.push({
key,
...item
})
if(item.name === 'README.md'){
readMeContent.push({...item})
}
})
this.setState({
rootList:rootList,
readMeContent
})
}
// readme文件内容
renderReadMeContent=(readMeContent)=>{
const { fileDetail } = this.state;
if(fileDetail){return;}
if(readMeContent && readMeContent.length > 0){
return(
<div className="commonBox">
<div className="commonBox-title">{readMeContent[0].name}</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.getProjectRoot(branchLastCommit.name);
}
render(){
const { rootList , branch ,filePath , fileDetail , subFileType , readMeContent, isSpin , rootData } = 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.ChangeFile(item)}>
<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>
:""
}
<Link to={``} className="commitKey">{branchLastCommit.last_commit.id}</Link>
<span className="color-blue flex-1 hide-1">{branchLastCommit.last_commit.message}</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 && filePath.length > 0 ? `/${filePath[filePath.length - 1].path}` : "";
return(
<React.Fragment>
{
rootData &&
<React.Fragment>
{
rootData.length > 0 ?
<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 && filePath.length > 0 &&
<span className="ml20 font-16">
<a onClick={()=>this.getProjectRoot(branch)} className="color-blue">{projectsId}</a>
{
filePath.map((item,key)=>{
return(
<React.Fragment>
{
key === filePath.length-1 ?
<span className="color-grey-6 subFileName" key={key}>{item.name}</span>
:
<a onClick={()=>this.ChangeFile(item,key)} className="color-blue subFileName" key={key}>{item.name}</a>
}
</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>
{/* <Link to={``}>上传文件</Link> */}
</p>
}
{
filePath && filePath.length === 0 && <CloneAddress http_url={http_url} downloadUrl={downloadUrl} showNotification={this.props.showNotification}></CloneAddress>
}
</div>
</div>
<Spin spinning={isSpin}>
{/* 文件夹-子目录列表 */}
{
rootList && <RootTable columns = {columns} data={rootList} title={() => title()}></RootTable>
}
{
fileDetail &&
<CoderRootFileDetail detail = {fileDetail} {...this.props} {...this.state}></CoderRootFileDetail>
}
{/* readme.txt */}
{ this.renderReadMeContent(readMeContent) }
</Spin>
</div>
:
<NullData {...this.props} {...this.state} http_url={http_url} ></NullData>
}
</React.Fragment>
}
</React.Fragment>
)
}
}
export default CoderRootDirectorytext;

View File

@ -52,7 +52,7 @@ class CoderRootIndex extends Component{
}
></Route>
{/* diff */}
<Route path="/projects/:projectsId/diff/:commitId"
<Route path="/projects/:projectsId/diff/:sha"
render={
(props) => (<Diff {...this.props} {...props} {...this.state}/>)
}

View File

@ -175,6 +175,7 @@ class Detail extends Component {
watchers_count: result.data.watchers_count,
praises_count: result.data.praises_count,
forked_count: result.data.forked_count,
isSpin:false
})
if (result.data.project_id) {
this.getBranch(result.data.project_id);
@ -284,6 +285,29 @@ class Detail extends Component {
}).catch((error) => { })
}
// 同步镜像
synchronismMirror=()=>{
const { repo_id } = this.state.projectDetail;
this.setState({
isSpin:true
})
const url = `/repositories/${repo_id}/sync_mirror.json`;
axios.post(url).then(result=>{
if(result && result.data && result.data.status === 0){
this.props.showNotification("镜像同步成功!");
this.getDetail();
}else{
this.props.showNotification("镜像同步失败!");
this.setState({
isSpin:false
})
}
}).catch(error=>{
console.log(error);
})
}
render() {
const { projectDetail, watchers_count, praises_count, forked_count, isSpin, isManager, watched, praised } = this.state;
const url = this.props.history.location.pathname;
@ -333,6 +357,10 @@ class Detail extends Component {
</span>
</p>
<span className="df mt25">
{
projectDetail && projectDetail.mirror &&
<a className="synchronism ml30" onClick={this.synchronismMirror}>同步镜像</a>
}
<span className="detail_tag_btn">
<a className="detail_tag_btn_name" onClick={() => this.focusFunc(watched)}>
<img src={watched ? img_focused : img_focus} alt="" width="14px" />
@ -340,8 +368,7 @@ class Detail extends Component {
</a>
<Link className="detail_tag_btn_count" to={{pathname:`/projects/${projectsId}/watch_users`, state}}>
{watchers_count}
</Link>
{/* <span className="detail_tag_btn_count">{watchers_count}</span> */}
</Link>
</span>
<span className="detail_tag_btn">
<a className="detail_tag_btn_name" onClick={() => this.pariseFunc(praised)}>

View File

@ -1,81 +1,193 @@
import React from 'react';
import styled from 'styled-components';
import { Button } from 'antd';
import User from '../Component/User';
import Keys from '../Component/Keys';
import React, { useEffect, useState } from "react";
import styled from "styled-components";
import { Button ,Spin } from "antd";
import { truncateCommitId } from '../common/util';
import Nodata from '../Nodata';
import User from "../Component/User";
import Keys from "../Component/Keys";
import axios from "axios";
const Infos = styled.div`
border:1px solid #DDDDDD;
& .commitinfos{
background-color:#F1F8FF;
border-bottom:1px solid #ddd;
padding:20px;
border: 1px solid #dddddd;
& .commitinfos {
background-color: #f1f8ff;
border-bottom: 1px solid #ddd;
padding: 20px;
}
& > .f-wrap-between{
padding:10px 24px;
& > .f-wrap-between {
padding: 10px 24px;
}
`;
const Operation = styled.p`
border-bottom:1px solid #eee;
padding:12px 0px;
margin-top:10px;
display:flex;
border-bottom: 1px solid #eee;
padding: 12px 0px;
margin-top: 10px;
display: flex;
justify-content: space-between;
align-items: center;
`;
const fileUl = styled.ul`
& li{
display:flex;
const FileUl = styled.ul`
padding-top: 10px;
& li {
display: flex;
justify-content: space-between;
align-items: center;
height:20px;
line-height:20px;
margin-bottom:10px;
height: 20px;
line-height: 20px;
margin-bottom: 10px;
}
`;
const DetailP = styled.p`
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 20px 12px 12px;
background-color: #fafafa;
border: 1px solid #dddddd;
`;
const files = ()=>{
return(
<fileUl>
<li>
<span><i className="iconfont icon-wenjia color-grey-3 font-16 mr8"></i></span>
</li>
</fileUl>
)
}
export default ({ projectDetail, match }) => {
const [data, setData] = useState(undefined);
const [commit, setCommit] = useState(undefined);
const [files, setFiles] = useState(undefined);
const [parents, setParents] = useState(undefined);
const [committer, setCommitter] = useState(undefined);
const [fileflag , setFileflag] = useState(false);
const [isSpin, setIsSpin] = useState(true);
export default () => {
return(
<div className="main">
<Infos>
<div className="commitinfos">
<p className="f-wrap-between">
<span className="font-20 color-grey-3">title</span>
<Button type="primary">浏览代码</Button>
</p>
<pre className="mt10">I wanner be a dancer \n I wanner be a dancer I wanner be a dancer</pre>
</div>
<div className="f-wrap-between" style={{alignItems:'center'}}>
<ul className="df">
<User url="https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg" name="caicai" />
</ul>
<li className="df">
<Keys title="父节点" value={"dddddd"} className="mr20"></Keys>
<Keys title="当前节点" value={"dddddd"}></Keys>
</li>
</div>
</Infos>
<Operation>
<span>
<i className="iconfont icon-triangle mr8 color-grey-9 font-16"></i>
<span className="color-grey-9">
共有<span>3个文件被更改</span>包括<span className="color-green">20次插入</span><span className="color-red">和3次删除</span>
const repo_id = projectDetail && projectDetail.repo_id;
const { sha } = match.params;
useEffect(() => {
if (repo_id && sha) {
const url = `/repositories/${repo_id}/commits/${sha}.json`;
axios
.get(url)
.then(result => {
if (result) {
setData(result.data);
setCommit(result.data.commit);
setFiles(result.data.files);
setParents(result.data.parents);
setCommitter(result.data.committer || (result.data.commit && result.data.commit.committer));
setIsSpin(false);
}
})
.catch(error => {
console.log(error);
});
}
}, [repo_id, sha]);
const renderFiles = () => {
return (
<FileUl>
{
files && files.length > 0 && files.map((item,key)=>{
return(
<li>
<span className="mr30 task-hide flex1">
<i className="iconfont icon-wenjia color-grey-3 font-16 mr8"></i>
{item.Name}
</span>
<span>
<label className="color-green mr20">+{item.Addition}</label>
<label className="color-red">-{item.Deletion}</label>
</span>
</li>
)
})
}
</FileUl>
);
};
function changeFlag(){
let flag = !fileflag;
setFileflag(flag);
}
const filesDetail = () => {
return (
<div>
<DetailP>
<span>
<i className="iconfont icon-youjiantou mr4 font-15 color-grey-9"></i>
<span className="font-16 color-grey-3">README.md</span>
</span>
</span>
<Button>双栏查看</Button>
</Operation>
<Button>查看文件</Button>
</DetailP>
</div>
);
};
return (
<div className="main">
<Spin spinning={isSpin}>
<Infos>
<div className="commitinfos">
<p className="f-wrap-between">
<span className="font-20 color-grey-3">
{ commit && commit.title }
</span>
<Button type="primary">浏览代码</Button>
</p>
{commit && commit.message ? (
<pre className="mt10">{commit.message}</pre>
) : (
""
)}
</div>
<div className="f-wrap-between" style={{ alignItems: "center" }}>
<ul className="df">
<User
url={(committer && committer.image_url)|| "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"}
name={committer && committer.name}
/>
</ul>
<li className="df">
{
parents && parents.length > 0 && parents.map((item,key)=>{
return(
<Keys title="父节点" value={truncateCommitId(item.sha) } className="mr20"></Keys>
)
})
}
<Keys title="当前节点" value={truncateCommitId(sha)}></Keys>
</li>
</div>
</Infos>
{
files && files.length > 0 ?
<React.Fragment>
<Operation>
<span className="files_info" onClick={changeFlag}>
<i className={fileflag ? "iconfont icon-sanjiaoxing-down mr8 color-grey-9 font-16":"iconfont icon-triangle mr8 color-grey-9 font-16"}></i>
<span className="color-grey-9">
共有<span>{files && files.length}个文件被更改</span>包括
{data && data.additions ? (
<span className="color-green">{data.additions}次插入</span>
) : (
""
)}
{data && data.additions && data.deletions ? "和" : ""}
{data && data.deletions ? (
<span className="color-red">{data.deletions}次删除</span>
) : (
""
)}
</span>
</span>
<Button>双栏查看</Button>
</Operation>
{fileflag && renderFiles()}
{filesDetail()}
</React.Fragment>
:
<Nodata _html="暂无文件修改信息!"/>
}
</Spin>
</div>
)
}
);
};

View File

@ -558,6 +558,18 @@
line-height: 50px;
border-bottom: 1px solid #ddd;
}
.synchronism{
display: block;
height: 26px;
line-height: 26px;
padding:0px 15px;
color: #fff!important;
background-color: #28BD6C;
border-radius: 4px;
}
.files_info{
cursor: pointer;
}
.commonBox .commonBox-info{
padding:20px 15px;
}

View File

@ -1,6 +1,7 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { Input, Form, Select, Checkbox, Button, Divider, Spin, AutoComplete } from 'antd';
import { Base64 } from 'js-base64';
import '../css/index.css';
import './new.css'
@ -16,6 +17,8 @@ class Index extends Component {
gitignoreType: "0",
LicensesType: "0",
mirrorCheck:false,
CategoryList: undefined,
LanguageList: undefined,
GitignoreList: undefined,
@ -129,17 +132,19 @@ class Index extends Component {
}
subMitFrom = () => {
this.setState({
isSpin: true
})
this.props.form.validateFieldsAndScroll((err, values) => {
if (!err) {
this.setState({
isSpin: true
})
const { current_user } = this.props;
const { projectsType } = this.props.match.params;
const { project_language_id, project_category_id, license_id, ignore_id } = this.state;
const decoderPass = Base64.encode(values.password);
const url = projectsType === "deposit" ? "/projects.json" : "/projects/migrate.json";
axios.post(url, {
...values,
auth_password:decoderPass,
project_language_id,
project_category_id,
license_id,
@ -204,6 +209,13 @@ class Index extends Component {
callback();
}
changeMirrorCheck=()=>{
const { mirrorCheck } = this.state;
this.setState({
mirrorCheck:!mirrorCheck
})
}
render() {
const { getFieldDecorator } = this.props.form;
// 项目类型deposit-托管项目mirror-镜像项目
@ -228,6 +240,8 @@ class Index extends Component {
project_category_list,
license_list,
ignore_list,
mirrorCheck
} = this.state;
return (
<div className="main back-white">
@ -254,6 +268,39 @@ class Index extends Component {
<p className="formTip color-orange">示例https://github.com/facebook/reack.git</p>
</React.Fragment>
}
{
projectsType !== "deposit" &&
<React.Fragment>
<p className="mt10 mb10 color-grey-3 pointer" onClick={this.changeMirrorCheck}>需要授权验证<i className={mirrorCheck?"iconfont icon-xiajiantou font-13 ml10 color-grey-8":"iconfont icon-youjiantou font-13 ml10 color-grey-8"}></i></p>
{
mirrorCheck &&
<div className="df mb20" style={{alignItems:'center'}}>
<span className="mr10">用户名</span>
<Form.Item
style={{ marginBottom: "0px" }}
label=""
>
{getFieldDecorator('auth_username', {
rules: [],
})(
<Input placeholder="请输入对应平台的登录用户名" style={{width:"240px"}} />
)}
</Form.Item>
<span className="mr10">密码</span>
<Form.Item
style={{ marginBottom: "0px" }}
label=""
>
{getFieldDecorator('password', {
rules: [],
})(
<Input placeholder="请输入对应平台的登录密码" type="password" style={{width:"240px"}}/>
)}
</Form.Item>
</div>
}
</React.Fragment>
}
<Form.Item
label="项目名称"
>
@ -384,6 +431,18 @@ class Index extends Component {
<Checkbox value="limit">将项目设为私有<span className="ml15 font-13 color-grey-9">(只有项目所有人或拥有权限的项目成员才能看到)</span></Checkbox>
)}
</Form.Item >
{
projectsType !== "deposit" &&
<Form.Item
label="迁移类型:"
style={{ margin: "0px" }}
className="privatePart"
>
{getFieldDecorator('is_mirror')(
<Checkbox value="limit">该仓库将是一个<span className="color-blue">镜像</span>(push)</Checkbox>
)}
</Form.Item >
}
<div>
<span className="ant-form-item-required"></span>
</div>

View File

@ -1,6 +1,6 @@
export function truncateCommitId(str) {
if (str.length > 11) {
if (str && str.length > 11) {
return str.substring(0, 10)
}
}

View File

@ -296,13 +296,13 @@ export function TPMIndexHOC(WrappedComponent) {
}
fetchUser = () => {
console.log("`111111");
let url = `/users/get_user_info.json`
let courseId;
let query = this.props.location.pathname;
const type = query.split('/');
if (type[1] == 'classrooms' && type[2]) {
courseId = parseInt(type[2])
// url += `?course_id=${courseId}`
}
var datay = {};
if (JSON.stringify(this.state.dataquerys) === "{}") {
@ -320,25 +320,11 @@ export function TPMIndexHOC(WrappedComponent) {
}
}
axios.get(url, {
params:
datay
params: datay
}).then((response) => {
/*
{
"username": "黄井泉",
"login": "Hjqreturn",
"user_id": 12,
"image_url": "avatar/User/12",
"admin": true,
"is_teacher": false,
"tidding_count": 0
}
*/
if (response === undefined) {
return
}
if (response.data) {
this.initCommonState(response.data)
if (response && response.data) {
console.log("`111111",response.data);
this.initCommonState(response.data);
this.setState({
tpmLoading: false,
coursedata: {
@ -346,12 +332,9 @@ export function TPMIndexHOC(WrappedComponent) {
course_public: response.data.course_public,
name: response.data.course_name,
userid: response.data.user_id
},
}
})
}
}).catch((error) => {
console.log(error)
})