merge gitlink_server 代码
This commit is contained in:
commit
bc4facb87c
|
|
@ -172,7 +172,7 @@
|
|||
"dependencies": {
|
||||
"jsesc": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "http://173.15.15.82:8081/repository/npm-all/jsesc/-/jsesc-2.5.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
|
||||
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
|
||||
}
|
||||
}
|
||||
|
|
@ -245,7 +245,7 @@
|
|||
"dependencies": {
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "http://173.15.15.82:8081/repository/npm-all/chalk/-/chalk-2.4.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
|
|
@ -341,12 +341,12 @@
|
|||
},
|
||||
"globals": {
|
||||
"version": "11.12.0",
|
||||
"resolved": "http://173.15.15.82:8081/repository/npm-all/globals/-/globals-11.12.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
|
||||
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "http://173.15.15.82:8081/repository/npm-all/ms/-/ms-2.1.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
}
|
||||
}
|
||||
|
|
@ -7248,7 +7248,7 @@
|
|||
},
|
||||
"promise": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "http://173.15.15.82:8081/repository/npm-all/promise/-/promise-7.3.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
|
||||
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
|
||||
"requires": {
|
||||
"asap": "~2.0.3"
|
||||
|
|
@ -9677,7 +9677,7 @@
|
|||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "http://173.15.15.82:8081/repository/npm-all/chalk/-/chalk-2.4.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -3373,8 +3373,8 @@ a.edu-greyline-btn:hover {
|
|||
|
||||
.defalutSubmitbtn {
|
||||
display: block;
|
||||
border: 1px solid #4CACFF;
|
||||
background-color: #4CACFF;
|
||||
border: 1px solid #466aff;
|
||||
background-color: #466aff;
|
||||
color: #fff !important;
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
|
|
@ -3382,7 +3382,6 @@ a.edu-greyline-btn:hover {
|
|||
border-radius: 2px;
|
||||
width: 130px;
|
||||
height: 40px;
|
||||
background: rgba(76, 172, 255, 1);
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
font-family: MicrosoftYaHei;
|
||||
|
|
|
|||
|
|
@ -2,16 +2,17 @@
|
|||
<html lang="zh-hans-CN" class="notranslate translated-ltr" translate="no">
|
||||
|
||||
<head>
|
||||
<title>GitLink | 新一代开源创新服务平台</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="Keywords" Content="gitLink,GitLink,gitlink,git,trustie,trustieforge,forge,开源,确实开源,代码托管,Git,开源,内源,项目管理,版本控制,开源代码,代码分享,项目协作,开源项目托管,免费代码托管,Git代码托管,Git托管服务,确实让创建更美好,协同开发平台">
|
||||
<meta name="description" Content="GitLink,新一代开源创新服务平台 分布式协作开发 一站式过程管理 高效流水线运维 多层次代码分析 多维度用户画像 分布式协作开发 基于Git打造分布式代码托管环境">
|
||||
<meta name="Keywords" content="GitLink, git, 开源, 代码托管, 项目管理, 版本控制, 代码分享, 项目协作, 协同开发平台">
|
||||
<meta name="description" content="GitLink 是一个新一代的开源创新服务平台,提供分布式协作开发、流水线运维、代码分析等功能,基于 Git 打造分布式代码托管环境。">
|
||||
<meta property="og:title" content="GitLink | 确实开源" />
|
||||
<meta property="og:type" content="Object" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://gitlink.org.cn/" />
|
||||
<meta property="og:image" content="https://www.gitlink.org.cn/images/logo.png" />
|
||||
<meta property="og:image:alt" content="GitLink | 确实开源" />
|
||||
<meta property="og:site_name" content="GitLink" />
|
||||
<meta property="og:description" content="GitLink,新一代开源创新服务平台 分布式协作开发 一站式过程管理 高效流水线运维 多层次代码分析 多维度用户画像 分布式协作开发 基于Git打造分布式代码托管环境" />
|
||||
<meta property="og:description" content="GitLink 是一个新一代的开源创新服务平台,提供分布式协作开发、流水线运维、代码分析等功能,基于 Git 打造分布式代码托管环境。" />
|
||||
<meta name="hostname" content="gitlink.org.cn">
|
||||
<meta name="keyboard-shortcuts-preference" content="all">
|
||||
<meta name="expected-hostname" content="gitlink.org.cn">
|
||||
|
|
@ -20,14 +21,8 @@
|
|||
<meta name="octolytics-dimension-repository_nwo" content="GitLink"></meta>
|
||||
<meta name="octolytics-dimension-repository_network_root_nwo" content="GitLink"></meta>
|
||||
<meta name="theme-color" content="#000000">
|
||||
<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" /> -->
|
||||
<meta content="IE=edge" http-equiv="X-UA-Compatible">
|
||||
<meta name="twitter:image:src" content="https://www.gitlink.org.cn/images/logo.png">
|
||||
<meta name="twitter:site" content="@gitlink">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="GitLink | 确实开源">
|
||||
<meta name="twitter:description" content="GitLink,新一代开源创新服务平台 分布式协作开发 一站式过程管理 高效流水线运维 多层次代码分析 多维度用户画像 分布式协作开发 基于Git打造分布式代码托管环境">
|
||||
<meta content="always" name="referrer">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="referrer" content="always">
|
||||
<link rel="canonical" href="https://gitlink.org.cn" data-turbo-transient="">
|
||||
<link rel="fluid-icon" href="https://www.gitlink.org.cn/images/logo.png" title="GitLink">
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -32,8 +32,8 @@ export function initAxiosInterceptors(props) {
|
|||
// 判断网络是否连接
|
||||
initOnlineOfflineListener();
|
||||
|
||||
// var proxy = "http://172.20.32.202:4000";
|
||||
var proxy = "https://www.gitlink.org.cn";
|
||||
|
||||
var proxy = "https://testforgeplus.trustie.net";
|
||||
|
||||
//响应前的设置
|
||||
axios.interceptors.request.use(
|
||||
|
|
|
|||
|
|
@ -344,25 +344,21 @@ export function addMeta(name, content){
|
|||
* projectId 项目唯一标识
|
||||
*/
|
||||
export function setSeoMeta(keyWords, title, description, url, owner, projectId) {
|
||||
let keyStatement = ' ';
|
||||
if(owner)keyStatement += owner;
|
||||
if(projectId)keyStatement += `/${projectId}`;
|
||||
|
||||
document.querySelector(`meta[property='og:title']`).content = title + keyStatement + ' for gitlink' + keyStatement + ' for git';
|
||||
document.querySelector(`meta[property='og:url']`).content = window.location.origin + url;
|
||||
document.querySelector(`meta[property='og:description']`).content = description + ' - ' + title + ' for gitlink' + keyStatement + ' for git';
|
||||
document.querySelector(`meta[property='og:image:alt']`).content = description + ' - ' + title + ' for gitlink' + keyStatement + ' for git';
|
||||
document.querySelector('meta[name="Keywords"]').content= `${ keyWords } ${ keyWords ? '' : 'gitLink,GitLink,gitlink,trustie,trustieforge,forge,开源,确实开源,代码托管,Git,开源,内源,项目管理,版本控制,开源代码,代码分享,项目协作,开源项目托管,免费代码托管,Git代码托管,Git托管服务,确实让创建更美好,协同开发平台' }` ;
|
||||
document.querySelector(`meta[name='description']`).content = description + keyStatement + ' for gitlink' + keyStatement + ' for git';
|
||||
document.querySelector(`meta[name='go-import']`).content = window.location.host + url + ' git ' + window.location.origin + url;
|
||||
// 服务端没有location
|
||||
const host = window.location.host
|
||||
const origin = window.location.origin
|
||||
document.querySelector(`meta[property='og:title']`).content = title + ' | GitLink';
|
||||
document.querySelector(`title`).textContent = title + ' | GitLink';
|
||||
document.querySelector(`meta[property='og:url']`).content = origin + url;
|
||||
document.querySelector(`meta[property='og:description']`).content = description + ' | GitLink';
|
||||
document.querySelector(`meta[property='og:image:alt']`).content = description + ' | GitLink';
|
||||
document.querySelector('meta[name="Keywords"]').content= `${ keyWords },${ keyWords ? '' : 'GitLink, git, 开源, 代码托管, 项目管理, 版本控制, 代码分享, 项目协作, 协同开发平台' }` ;
|
||||
document.querySelector(`meta[name='description']`).content = description + ' | GitLink';
|
||||
document.querySelector(`meta[name='go-import']`).content = host + url + ' git ' + origin + url;
|
||||
document.querySelector(`meta[name='octolytics-dimension-user_login']`).content = owner;
|
||||
if (projectId) {
|
||||
document.querySelector(`meta[name='octolytics-dimension-repository_nwo']`).content = owner + '/' + projectId;
|
||||
document.querySelector(`meta[name='octolytics-dimension-repository_network_root_nwo']`).content = owner + '/' + projectId;
|
||||
}
|
||||
document.querySelector(`meta[name='twitter:title']`).content = title + keyStatement + ' for gitlink' + keyStatement + ' for git';
|
||||
document.querySelector(`meta[name='twitter:description']`).content = description + ' - ' + title + keyStatement + ' for gitlink' + keyStatement + ' for git';
|
||||
|
||||
document.querySelector(`link[rel='canonical']`).href = window.location.origin + url;
|
||||
|
||||
document.querySelector(`link[rel='canonical']`).href = origin + url;
|
||||
}
|
||||
|
|
@ -14,9 +14,10 @@ function Index(props){
|
|||
const [ content , setContent ] = useState(undefined);
|
||||
const [ edit , setEdit ] = useState(false);
|
||||
const [ fileList , setFileList ] = useState(undefined);
|
||||
const [ editOpration , setEditOpration ] = useState(false);
|
||||
// const [ editOpration , setEditOpration ] = useState(false);
|
||||
const { owner , projectsId } = props.match.params;
|
||||
const { isManager , isDeveloper , current_user, projectDetail } = props;
|
||||
const editOpration = current_user && current_user.login && isManager
|
||||
|
||||
useEffect(()=>{
|
||||
if(owner && projectsId && projectDetail){
|
||||
|
|
@ -25,11 +26,11 @@ function Index(props){
|
|||
}
|
||||
},[owner,projectsId, projectDetail])
|
||||
|
||||
useEffect(()=>{
|
||||
if( (current_user && current_user.login) && (isManager === true || isDeveloper === true)){
|
||||
setEditOpration(true);
|
||||
}
|
||||
},[isManager , isDeveloper])
|
||||
// useEffect(()=>{
|
||||
// if( (current_user && current_user.login) && (isManager === true || isDeveloper === true)){
|
||||
// setEditOpration(true);
|
||||
// }
|
||||
// },[isManager , isDeveloper])
|
||||
function Init(){
|
||||
const url = `/${owner}/${projectsId}/about.json`;
|
||||
axios.get(url).then(result=>{
|
||||
|
|
|
|||
|
|
@ -18,11 +18,12 @@ function Index(props){
|
|||
<img src={logo} alt="" height="48px" />
|
||||
</div>
|
||||
<div className={"content"}>
|
||||
<p>关联账号</p>
|
||||
<p>关联第三方账号</p>
|
||||
<div className="panels">
|
||||
<p className="tips">您已完成头歌/github/gitee/qq/中国研究生赛事平台授权,请补充Gitlink登录信息以完成第三方账号绑定</p>
|
||||
<Menu selectedKeys={[key]} mode={`horizontal`} className="panelsMenu" onClick={chooseMenuFunc}>
|
||||
<Menu.Item key="0">已有账号,进行绑定</Menu.Item>
|
||||
<Menu.Item key="1">无账号,注册并绑定</Menu.Item>
|
||||
<Menu.Item key="0">已有Gitlink账号,进行绑定</Menu.Item>
|
||||
<Menu.Item key="1">无Gitlink账号,注册并绑定</Menu.Item>
|
||||
</Menu>
|
||||
{
|
||||
key === "0" ?
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ function Bind(props){
|
|||
<Input.Password autoComplete="new-password" addonBefore={<img src={lock} alt="" width="13px" />} className="psd" size="large" placeholder="请输入登录密码" />,
|
||||
)}
|
||||
</Form.Item>
|
||||
<Button type="primary" disabled={bindFlag} size="large" style={{width:"100%",marginTop:"40px"}} onClick={bindloginFunc}>
|
||||
<Button type="primary" disabled={bindFlag} size="large" style={{width:"100%",marginTop:"20px"}} onClick={bindloginFunc}>
|
||||
绑定并登录
|
||||
</Button>
|
||||
</Form>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,17 @@
|
|||
.panels{
|
||||
background-color: #fff;
|
||||
border-radius:6.6px;
|
||||
padding:32px 42px;
|
||||
padding:40px 32px;
|
||||
.tips{
|
||||
border:1px solid #FF6F00;
|
||||
color: #FF6F00;
|
||||
background: rgba(255,111,0,0.1);
|
||||
padding:5px 15px;
|
||||
border-radius: 3px;
|
||||
line-height: 22px;
|
||||
font-size: 13px;
|
||||
margin-bottom: 15px!important;
|
||||
}
|
||||
.panelsMenu{
|
||||
border-bottom: none!important;
|
||||
margin-bottom: 36px!important;
|
||||
|
|
@ -33,7 +43,7 @@
|
|||
}
|
||||
}
|
||||
.bind_form{
|
||||
padding-bottom: 48px;
|
||||
padding-bottom: 10px;
|
||||
.has-error .ant-input:focus,.has-error .ant-input, .has-error .ant-input:hover{
|
||||
border-color: #ff4d4f!important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ function Bind(props){
|
|||
<Input.Password autoComplete="new-password" addonBefore={<img src={lock} alt="" width="13px" />} className="psd" size="large" placeholder="请确认登录密码" />,
|
||||
)}
|
||||
</Form.Item>
|
||||
<Button type="primary" disabled={bindFlag} size="large" style={{width:"100%",marginTop:"40px"}} onClick={bindRegFunc}>
|
||||
<Button type="primary" disabled={bindFlag} size="large" style={{width:"100%",marginTop:"20px"}} onClick={bindRegFunc}>
|
||||
注册并登录
|
||||
</Button>
|
||||
</Form>
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ import './branch.scss';
|
|||
import SelectOverlay from './SelectOverlay';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import { turnbar } from 'educoder';
|
||||
import { truncateCommitId } from "../common/util";
|
||||
|
||||
export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true })=>{
|
||||
export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true , commitflag=false })=>{
|
||||
const [ showValue , setShowValue ] = useState(branch);
|
||||
const [ visible , setVisible ] = useState(false);
|
||||
|
||||
|
|
@ -34,10 +35,11 @@ export default (({ projectsId , branch , owner , changeBranch , branchList , tag
|
|||
setShowValue(branch);
|
||||
},[branch])
|
||||
|
||||
function ChangeB(params) {
|
||||
function ChangeB(params,type) {
|
||||
setVisible(false);
|
||||
let en = turnbar(params);
|
||||
changeBranch(en);
|
||||
// let en = turnbar(params);
|
||||
changeBranch(params);
|
||||
setShowValue(type ? truncateCommitId(params) : params);
|
||||
}
|
||||
|
||||
const menu = (
|
||||
|
|
@ -46,6 +48,7 @@ export default (({ projectsId , branch , owner , changeBranch , branchList , tag
|
|||
visible={visible}
|
||||
changeBranch={ChangeB}
|
||||
tagflag={tagflag}
|
||||
commitflag={commitflag}
|
||||
projectsId={projectsId}
|
||||
owner={owner}
|
||||
branchList={branchList}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
import React , { useState , useEffect } from 'react';
|
||||
import { Input , Spin , Menu } from 'antd';
|
||||
import { getBranch , getTag } from '../GetData/getData';
|
||||
import { getBranch , getTag , getCommit } from '../GetData/getData';
|
||||
import { truncateCommitId } from "../common/util";
|
||||
|
||||
function SelectOverlay({ changeBranch , tagflag , projectsId , owner , visible }) {
|
||||
function SelectOverlay({ changeBranch , tagflag , commitflag , projectsId , owner , visible }) {
|
||||
const [ inputValue , setInputValue] = useState(undefined);
|
||||
const [ nav , setNav ] = useState(0);
|
||||
const [ isSpin , setIsSpin ] = useState(true);
|
||||
|
||||
const [ data , setData ] = useState(undefined);
|
||||
const [ commitData , setCommitData ] = useState(undefined);
|
||||
const [ datas , setDatas ] = useState(undefined);
|
||||
const [ keys ,setKeys] = useState("branch");
|
||||
|
||||
|
|
@ -31,33 +33,68 @@ function SelectOverlay({ changeBranch , tagflag , projectsId , owner , visible }
|
|||
setDatas(result);
|
||||
setIsSpin(false);
|
||||
}
|
||||
function chooseitem(value){
|
||||
changeBranch(value);
|
||||
async function getCommits(id,owner,search){
|
||||
let result = await getCommit(id,owner,search);
|
||||
setCommitData(result.data && result.data.commits);
|
||||
setIsSpin(false);
|
||||
}
|
||||
function chooseitem(value,type){
|
||||
changeBranch(value,type);
|
||||
}
|
||||
function changeInputValue(e){
|
||||
setInputValue(e.target.value);
|
||||
let filter = e.target.value ? data && data.length>0 && data.filter(item=>item.name.indexOf(e.target.value)>-1) : data;
|
||||
setDatas(filter);
|
||||
if(keys ==="commit"){
|
||||
// 调用接口搜索
|
||||
getCommits(projectsId,owner,e.target.value);
|
||||
}else{
|
||||
let filter = e.target.value ? data && data.length>0 && data.filter(item=>item.name.indexOf(e.target.value)>-1) : data;
|
||||
setDatas(filter);
|
||||
}
|
||||
}
|
||||
|
||||
function changeNav(e){
|
||||
setKeys(e.key);
|
||||
setIsSpin(true);
|
||||
setInputValue(undefined);
|
||||
if(e.key === "branch"){
|
||||
getBranchs(projectsId,owner);
|
||||
setNav(0);
|
||||
}else{
|
||||
}else if(e.key === "commit"){
|
||||
getCommits(projectsId,owner);
|
||||
setNav(2);
|
||||
}
|
||||
else{
|
||||
getTags(projectsId,owner);
|
||||
setNav(1);
|
||||
}
|
||||
}
|
||||
|
||||
const commitEle =(ele)=> (
|
||||
ele && ele.length>0 ?
|
||||
<ul className="commitUl">
|
||||
{
|
||||
ele.map((i,k)=>{
|
||||
return(
|
||||
<li onClick={()=>chooseitem(i.sha,"commit")}>
|
||||
<span style={{color:"#111"}}>{truncateCommitId(i.sha)}</span>
|
||||
<div className="commitMsg">
|
||||
<div className="task-hide">{i.commit_message}</div> @ {i.time_from_now}
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
:
|
||||
<div style={{padding:"10px 20px"}}>暂无提交数据~</div>
|
||||
)
|
||||
|
||||
return(
|
||||
<div className="overlayBranch">
|
||||
<div className="padding15" style={{paddingBottom:"0px"}}>
|
||||
<Input
|
||||
prefix={<i className="iconfont icon-sousuo_icon1 font-14"></i>}
|
||||
placeholder={`请输入分支${tagflag ? "或标签" :""}名称搜索`}
|
||||
placeholder={keys === "commit" ?"搜索提交":`请输入分支${tagflag ? "或标签" :""}名称搜索`}
|
||||
autocomplete="off" className="OptionsInput"
|
||||
value={inputValue}
|
||||
onChange={changeInputValue}
|
||||
|
|
@ -66,23 +103,27 @@ function SelectOverlay({ changeBranch , tagflag , projectsId , owner , visible }
|
|||
<Menu mode="horizontal" className="navUl" selectedKeys={[keys]} onClick={changeNav}>
|
||||
<Menu.Item key={"branch"}>分支</Menu.Item>
|
||||
{ tagflag && <Menu.Item key={"tag"}>标签</Menu.Item> }
|
||||
{commitflag && <Menu.Item key={"commit"}>最近提交</Menu.Item> }
|
||||
</Menu>
|
||||
<Spin spinning={isSpin}>
|
||||
<ul className="OptionsUl" id="ul-btn">
|
||||
{
|
||||
datas && datas.length>0 &&
|
||||
datas.map((item,key)=>{
|
||||
return(
|
||||
<li key={key} onClick={()=>chooseitem(item.name)}><a className="task-hide ulALink">{item.name}</a></li>
|
||||
)
|
||||
})
|
||||
|
||||
}
|
||||
{
|
||||
datas && datas.length === 0 &&
|
||||
<p className="listTips">暂无{inputValue}{nav === 0 ?"分支":"标签"}~</p>
|
||||
}
|
||||
</ul>
|
||||
{
|
||||
keys === "commit" ? commitEle(commitData)
|
||||
:
|
||||
<ul className="OptionsUl" id="ul-btn">
|
||||
{
|
||||
datas && datas.length>0 &&
|
||||
datas.map((item,key)=>{
|
||||
return(
|
||||
<li key={key} onClick={()=>chooseitem(item.name)}><a className="task-hide ulALink">{item.name}</a></li>
|
||||
)
|
||||
})
|
||||
}
|
||||
{
|
||||
datas && datas.length === 0 &&
|
||||
<p className="listTips">暂无{inputValue}{nav === 0 ?"分支":"标签"}~</p>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</Spin>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
background: #fff;
|
||||
max-height: 300px;
|
||||
}
|
||||
.OptionsUl{
|
||||
.OptionsUl,.commitUl{
|
||||
min-height: 50px;
|
||||
max-height: 220px;
|
||||
overflow-y: auto;
|
||||
|
|
@ -46,6 +46,26 @@
|
|||
line-height: 32px;
|
||||
width: 100%;
|
||||
}
|
||||
.commitUl{
|
||||
padding:0px 20px;
|
||||
}
|
||||
.commitUl li{
|
||||
padding:15px 0px;
|
||||
border-bottom: 1px dashed rgba(168,168,168,0.31);
|
||||
&:last-child{
|
||||
border:none;
|
||||
}
|
||||
cursor: pointer;
|
||||
}
|
||||
.commitUl .commitMsg{
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
div{
|
||||
word-break: break-all;
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
.branch-tagBox{
|
||||
border:1px solid #D0D0D0;
|
||||
border-radius: 3px;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ function Releases({ owner, projectsId, releaseVersions, distribution }) {
|
|||
:
|
||||
<div className="mt8">
|
||||
暂无发行版
|
||||
{distribution && <Link className="color-blue ml20" to={{pathname:`/${owner}/${projectsId}/releases/new`,state:{stable:true}}}>创建新版本</Link>}
|
||||
{distribution && <Link className="color-blue ml20" to={{pathname:`/${owner}/${projectsId}/releases/new`,state:{stable:true}}}>发布新版本</Link>}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,146 @@
|
|||
import React, { useState , useEffect } from 'react';
|
||||
import { Button , Table , Tooltip } from 'antd';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import paperImg from './image/paperImg.png';
|
||||
import NewModal from './component/new';
|
||||
import { Link } from 'react-router-dom';
|
||||
import "./index.scss";
|
||||
import axios from 'axios';
|
||||
|
||||
function Index(props){
|
||||
const { project , match , current_user , projectDetail , getProject } =props;
|
||||
const permission = current_user && current_user.login ? (projectDetail && projectDetail.permission):"";
|
||||
const { owner ,projectsId } = match && match.params;
|
||||
const [ dataSource , setDataSource ] = useState([]);
|
||||
const [ empty , setEmpty ] = useState(project && (!project.has_dataset));
|
||||
const [ total , setTotal ] = useState(0);
|
||||
const [ page , setPage ] = useState(1);
|
||||
const [ visible , setVisible ] = useState(false);
|
||||
const [ detail , setDetail ] = useState({});
|
||||
const pageSize = 10;
|
||||
|
||||
useEffect(()=>{
|
||||
if(!empty){
|
||||
Init();
|
||||
}
|
||||
},[empty,page])
|
||||
|
||||
function Init(){
|
||||
const url = `/v1/${owner}/${projectsId}/dataset`;
|
||||
|
||||
axios.get(url,{
|
||||
params:{
|
||||
page,limit:pageSize
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result) {
|
||||
setDetail(result.data);
|
||||
setDataSource(result.data && result.data.attachments);
|
||||
setTotal(result.data.attachment_total_count);
|
||||
}
|
||||
}).catch((error) => { })
|
||||
}
|
||||
|
||||
const columns=[
|
||||
{
|
||||
title:"文件名称",
|
||||
dataIndex:"title",
|
||||
key:1,
|
||||
ellipsis:true,
|
||||
width:"25%"
|
||||
},
|
||||
{
|
||||
title:"描述",
|
||||
dataIndex:"description",
|
||||
key:2,
|
||||
ellipsis:true,
|
||||
width:"30%",
|
||||
render:(value)=>{
|
||||
return <Tooltip title={value}>{value}</Tooltip>
|
||||
}
|
||||
},
|
||||
{
|
||||
title:"创建者",
|
||||
dataIndex:"creator",
|
||||
key:3,
|
||||
width:"10%",
|
||||
render:(value,item)=>{
|
||||
return <Link to={`/${value.login}`}><img src={getImageUrl(`/${value.image_url}`)} alt="" style={{borderRadius:"50%"}} width="32px" height="32px" /></Link>
|
||||
}
|
||||
},
|
||||
{
|
||||
title:"上传时间",
|
||||
dataIndex:"created_on",
|
||||
key:4,
|
||||
width:"15%"
|
||||
},
|
||||
{
|
||||
title:"大小",
|
||||
dataIndex:"filesize",
|
||||
key:5,
|
||||
},
|
||||
{
|
||||
title:"操作",
|
||||
dataIndex:"url",
|
||||
key:6,
|
||||
width:"10%",
|
||||
render:(value,item)=>{
|
||||
return <a href={value} className="color-blue">下载</a>
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
// 添加成功
|
||||
function addFunc(){
|
||||
setEmpty(false);
|
||||
setVisible(false);
|
||||
getProject && getProject();
|
||||
detail && detail.id && Init();
|
||||
}
|
||||
return(
|
||||
<div className={`dataset`}>
|
||||
<NewModal visible={visible} detail={detail} owner={owner} repo={projectsId} onCancel={()=>setVisible(false)} onOk={addFunc}/>
|
||||
<div className={`mnistData`}>
|
||||
{empty ?
|
||||
<span className="font-16">数据集</span>
|
||||
:
|
||||
<React.Fragment>
|
||||
<div style={{width:0,flex:1}} className="mr20">
|
||||
<div className="df mb15" style={{alignItems:"center"}}><p className="font-16 weight500 task-hide">{detail.title}</p>{ detail.license_name ? <span className="license ml20">许可证 : {detail.license_name}</span> :""}</div>
|
||||
<p style={{wordBreak:"break-all"}}>{detail.description}</p>
|
||||
</div>
|
||||
{(permission && permission!== "") ? <div className="df">
|
||||
<Button type="primary" ghost onClick={()=>{setVisible(true)}}><i className="iconfont icon-a-bianji12 color-blue mr5 font-12"></i>编辑</Button>
|
||||
<Link className="ml20 operateButton" to={`/${owner}/${projectsId}/dataset/upload`}><i className="iconfont icon-a-shangchuan2x color-white mr5 font-13"></i>上传文件</Link>
|
||||
</div>:""}
|
||||
</React.Fragment>
|
||||
}
|
||||
</div>
|
||||
{
|
||||
empty?
|
||||
<div className={"emtpyData"}>
|
||||
<img src={require('./image/empty.png')} alt="" width="68px"/>
|
||||
<span className="font-22 weight400 color-grey-3">暂无数据集</span>
|
||||
{ (permission && permission!== "") ? <p className="mt25 font-15 color-grey-6 weight400">我们非常欢迎您创建并分享您的数据集,以便与其他用户共同促进开源社区的发展</p> :"" }
|
||||
{ (permission && permission!== "") ? <Button type="primary" className="mt15" onClick={()=>{setVisible(true)}}>创建数据集</Button> :""}
|
||||
</div>
|
||||
:
|
||||
<Table
|
||||
className={`datasetTable`}
|
||||
columns={columns}
|
||||
dataSource={dataSource}
|
||||
pagination={{total,pageSize,current:page,hideOnSinglePage:true,onChange:(p)=>setPage(p)}}
|
||||
/>
|
||||
}
|
||||
{
|
||||
detail.paper_content ?
|
||||
<div className="mt25">
|
||||
<p className="mb15 df" style={{alignItems:'center'}}><img src={paperImg} width={24} className="mr10" alt="" /><span className="font-16">研究论文</span></p>
|
||||
<div className={`mnistData`}>{ detail.paper_content }</div>
|
||||
</div>
|
||||
:""
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Index;
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Modal ,Form ,Input , AutoComplete , Button , Select } from 'antd';
|
||||
import '../index.scss';
|
||||
import axios from 'axios';
|
||||
|
||||
const { TextArea } = Input;
|
||||
const Option = Select.Option;
|
||||
|
||||
function New(props){
|
||||
const { form , visible , onCancel , onOk , owner , repo , detail } = props;
|
||||
const [ licenseId , setLicenseId ] =useState(undefined);
|
||||
const [ licensesList , setLicensesList] =useState([]);
|
||||
const [ filterLicensesList , setFilterLicensesList ] =useState([]);
|
||||
|
||||
const { getFieldDecorator , setFieldsValue } = form;
|
||||
|
||||
useEffect(()=>{
|
||||
if(detail && detail.id){
|
||||
setFieldsValue({...detail,license_id:detail.license_name});
|
||||
setLicenseId(detail.license_id);
|
||||
}
|
||||
},[detail])
|
||||
|
||||
useEffect(()=>{
|
||||
getLicenses();
|
||||
},[])
|
||||
|
||||
function getLicenses(){
|
||||
const url = `/licenses.json`
|
||||
axios.get(url).then((result) => {
|
||||
if (result) {
|
||||
setLicensesList(result.data.licenses);
|
||||
setFilterLicensesList(result.data.licenses);
|
||||
}
|
||||
}).catch((error) => { })
|
||||
}
|
||||
|
||||
|
||||
function submit(){
|
||||
form.validateFields((err, values) => {
|
||||
if(!err){
|
||||
const url = `/v1/${owner}/${repo}/dataset.json`;
|
||||
if(detail && detail.id){
|
||||
axios.put(url,{
|
||||
...values,license_id:licenseId
|
||||
}).then((result) => {
|
||||
if (result) {
|
||||
onOk && onOk();
|
||||
}
|
||||
}).catch((error) => { })
|
||||
}else{
|
||||
axios.post(url,{
|
||||
...values,license_id:licenseId
|
||||
}).then((result) => {
|
||||
if (result) {
|
||||
onOk && onOk();
|
||||
}
|
||||
}).catch((error) => { })
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function ChangePlatform(value){
|
||||
let _data = [];
|
||||
if (licensesList.length>0) {
|
||||
_data = licensesList.filter(item => item.name.toLowerCase().indexOf(value.toLowerCase()) > -1);
|
||||
}
|
||||
setFilterLicensesList(_data);
|
||||
}
|
||||
|
||||
function checkId(rule, value, callback, list, title){
|
||||
let filter = list.filter(item => item.name === value);
|
||||
if(!value){
|
||||
callback();
|
||||
}
|
||||
if (filter && filter.length > 0) {
|
||||
callback();
|
||||
} else {
|
||||
callback('请在下拉选项中选择正确的' + title + "!");
|
||||
}
|
||||
callback();
|
||||
}
|
||||
return(
|
||||
<Modal
|
||||
title={`${detail && detail.id?"编辑":"新建"}数据集`}
|
||||
width="648px"
|
||||
visible={visible}
|
||||
footer={null}
|
||||
className="newBoxForm"
|
||||
centered={true}
|
||||
closable={true}
|
||||
onCancel={onCancel}
|
||||
>
|
||||
<Form>
|
||||
<Form.Item label="数据集名称">
|
||||
{getFieldDecorator('title', {
|
||||
rules: [
|
||||
{
|
||||
required:true,
|
||||
message:"请输入数据集名称"
|
||||
}
|
||||
],
|
||||
})(
|
||||
<Input placeholder="请输入数据集名称" maxLength={100} />,
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label="开源许可证">
|
||||
{getFieldDecorator('license_id', {
|
||||
rules: [{
|
||||
validator: (rule, value, callback) => checkId(rule, value, callback, licensesList, '开源许可证')
|
||||
}],
|
||||
})(
|
||||
<AutoComplete
|
||||
placeholder="请选择开源许可证"
|
||||
onChange={ChangePlatform}
|
||||
className="plateAutoComplete"
|
||||
onSelect={(e,e1)=>{e1.props && setLicenseId(e1.props.id)}}
|
||||
>
|
||||
{
|
||||
filterLicensesList && filterLicensesList.map((item) => (
|
||||
<Option key={item.id} value={item.name} id={item.id}>
|
||||
{item.name}
|
||||
</Option>
|
||||
))
|
||||
}
|
||||
</AutoComplete>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label="数据集描述">
|
||||
{getFieldDecorator('description', {
|
||||
rules: [
|
||||
{
|
||||
required:true,
|
||||
message:"请输入描述内容"
|
||||
}
|
||||
]})(
|
||||
<TextArea maxLength={500} placeholder="请输入描述内容" autosize={{ minRows: 5, maxRows: 5 }} showCount/>,
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label="研究论文">
|
||||
{getFieldDecorator('paper_content', {rules:[]})(
|
||||
<TextArea maxLength={500} placeholder="请输入研究论文" autosize={{ minRows: 5, maxRows: 5 }} showCount/>,
|
||||
)}
|
||||
</Form.Item>
|
||||
<div className="center">
|
||||
<Button style={{width:"95px"}} onClick={onCancel}>取消</Button>
|
||||
<Button type="primary" className="ml20" style={{width:"95px"}} onClick={submit}>确定</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export default Form.create({ name: 'New' })(New);;
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Upload ,Form ,Input , Button , message } from 'antd';
|
||||
import '../index.scss';
|
||||
import { Link } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
|
||||
const { Dragger } = Upload;
|
||||
const { TextArea } = Input;
|
||||
|
||||
function UploadModal(props){
|
||||
const { match , form ,history } =props;
|
||||
const { owner ,projectsId } = match && match.params;
|
||||
const [fileList, setFileList] = useState([]);
|
||||
const [ detail , setDetail ] = useState({});
|
||||
const [ loading , setLoading ] = useState(false);
|
||||
const { getFieldDecorator } = form;
|
||||
|
||||
useEffect(()=>{
|
||||
Init();
|
||||
},[])
|
||||
function Init(){
|
||||
const url = `/v1/${owner}/${projectsId}/dataset`;
|
||||
|
||||
axios.get(url).then((result) => {
|
||||
if (result) {
|
||||
setDetail(result.data);
|
||||
}
|
||||
}).catch((error) => { })
|
||||
}
|
||||
|
||||
function submit(){
|
||||
form.validateFields((err, values) => {
|
||||
if(!err){
|
||||
const url = `/attachments.json`;
|
||||
const { description ,files } = values;
|
||||
setLoading(true);
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("container_type","ProjectDataset");
|
||||
formData.append("description",description);
|
||||
formData.append("container_id",detail && detail.id);
|
||||
formData.append("file",files.file);
|
||||
|
||||
const config = {
|
||||
headers: { "Content-Type": "multipart/form-data" }
|
||||
};
|
||||
axios.post(url,formData,config).then((result) => {
|
||||
if (result) {
|
||||
setLoading(false);
|
||||
history.push(`/${owner}/${projectsId}/dataset`);
|
||||
}
|
||||
}).catch((error) => { })
|
||||
}
|
||||
})
|
||||
}
|
||||
function isFolder(fileName) {
|
||||
// 获取文件名中最后一个点的位置
|
||||
const lastDotIndex = fileName.lastIndexOf('.');
|
||||
// 获取文件名中最后一个斜杠(如果有的话)之后的部分
|
||||
const nameAfterLastSlash = fileName.substring(fileName.lastIndexOf('/') + 1);
|
||||
// 如果最后一个点之后有内容,且该部分不是文件夹名称的一部分,则可能是文件
|
||||
return lastDotIndex !== -1 && nameAfterLastSlash.includes('.');
|
||||
}
|
||||
|
||||
const upload= {
|
||||
name: 'file',
|
||||
multiple: false,
|
||||
maxCount:1,
|
||||
type:"file",
|
||||
beforeUpload: file => {
|
||||
const isDirectory = file.type;
|
||||
const name = file.name;
|
||||
if (!isDirectory && !isFolder(name)) {
|
||||
message.error('不能上传文件夹!');
|
||||
}else{
|
||||
setFileList([file]);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
onRemove: file => {
|
||||
const index = fileList.indexOf(file);
|
||||
const newFileList = fileList.slice();
|
||||
newFileList.splice(index, 1);
|
||||
setFileList(newFileList);
|
||||
},
|
||||
fileList,
|
||||
};
|
||||
return(
|
||||
<div className={`dataset`}>
|
||||
<p className="font-18 fileTitle">上传数据集文件</p>
|
||||
<Form className="newBoxForm">
|
||||
<Form.Item label="文件描述">
|
||||
{getFieldDecorator('description', {
|
||||
rules: [
|
||||
{
|
||||
required:true,
|
||||
message:"请输入文件描述"
|
||||
}
|
||||
],
|
||||
})(
|
||||
<TextArea autosize={{minRows:5,maxRows:5}} placeholder="描述字数不超过255个字符" maxLength={255} />,
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label="数据上传">
|
||||
{getFieldDecorator('files', {
|
||||
rules: [
|
||||
{
|
||||
required:true,
|
||||
message:"请上传文件"
|
||||
}
|
||||
],
|
||||
})(
|
||||
<Dragger {...upload} className={"drag"}>
|
||||
<p className="ant-upload-hint font-15">点击添加文件或直接拖拽文件到此处</p>
|
||||
</Dragger>,
|
||||
)}
|
||||
</Form.Item>
|
||||
<div>
|
||||
<Link className="btn-83" to={`/${owner}/${projectsId}/dataset`}>取消</Link>
|
||||
<Button loading={loading} type="primary" className="ml5" style={{width:"95px"}} onClick={submit}>确定</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Form.create({ name: 'UploadModal' })(UploadModal);;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 468 B |
|
|
@ -0,0 +1,73 @@
|
|||
.dataset{
|
||||
margin:0px auto;
|
||||
width: 1200px;
|
||||
padding:25px 0px;
|
||||
.mnistData{
|
||||
background: #FAFCFF;
|
||||
border-radius: 3px;
|
||||
border: 1px solid rgba(42,97,255,0.23);
|
||||
padding:20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
p{
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
color: #202D40;
|
||||
line-height: 22px;
|
||||
&:first-child{
|
||||
max-width: 600px;
|
||||
}
|
||||
}
|
||||
.license{
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
background: #ECEFFE;
|
||||
border-radius: 6px 6px 6px 6px;
|
||||
padding:0px 12px;
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
color: #202D40;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.datasetTable{
|
||||
.ant-table-thead > tr > th{
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.emtpyData{
|
||||
background: #FAFCFF;
|
||||
border-radius: 4px 4px 0px 0px;
|
||||
min-height: 356px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 25px;
|
||||
}
|
||||
}
|
||||
.newBoxForm{
|
||||
.ant-row.ant-form-item{
|
||||
margin-bottom: 20px!important;
|
||||
position: relative;
|
||||
}
|
||||
.ant-col.ant-form-item-label{
|
||||
line-height: unset;
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
color: #4C5B76;
|
||||
}
|
||||
.ant-form-explain{
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
.fileTitle{
|
||||
line-height: 25px;
|
||||
padding-bottom: 22px;
|
||||
margin-bottom: 15px!important;
|
||||
border-bottom:1px solid rgba(167,178,194,0.44);
|
||||
}
|
||||
.drag{
|
||||
height: 110px!important;
|
||||
}
|
||||
|
|
@ -8,6 +8,10 @@ export const getBranch = async (id,owner)=>{
|
|||
export const getTag = async (id,owner)=>{
|
||||
return (await axios.get(`/${owner}/${id}/tags.json`,{params:{only_name:true}})).data.tags;
|
||||
}
|
||||
// 获取提交记录
|
||||
export const getCommit = async(id,owner,search)=>{
|
||||
return await axios.get(`/v1/${owner}/${id}/commits/recent`,{params:{keyword:search}})
|
||||
}
|
||||
// 获取hooks(仓库设置-管理web钩子)列表
|
||||
export const getHooks = async (id,params)=>{
|
||||
return (await axios.get(`/projects/${id}/hooks.json`,{params})).data;
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ function NewPanel(props,ref){
|
|||
|
||||
const { form: { getFieldDecorator, validateFields , setFieldsValue } } = props;
|
||||
useState(()=>{
|
||||
title && setTimeout(()=>{
|
||||
setFieldsValue({subject:title});
|
||||
setTimeout(()=>{
|
||||
title && setFieldsValue({subject:title});
|
||||
desc && onContentChange(desc);
|
||||
},100)
|
||||
files && setAttachments(files);
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ function CoderDepot(props){
|
|||
let search = props.history.location.search
|
||||
const { platform , mirror_status , bannerList , projectDetail } = props ;
|
||||
//distribution:判断此用户是否可以创建发行版
|
||||
const distribution = projectDetail && projectDetail.type ===0 && ( projectDetail.permission && projectDetail.permission !== "Reporter");
|
||||
const distribution = projectDetail && ( projectDetail.permission && projectDetail.permission !== "Reporter");
|
||||
|
||||
useEffect(()=>{
|
||||
if(bannerList && bannerList.length>0){
|
||||
|
|
@ -109,9 +109,9 @@ function CoderDepot(props){
|
|||
const { author, name, description, default_branch} = projectDetail;
|
||||
if(branchName && branchName !== default_branch){
|
||||
// 处于某分支/标签
|
||||
document.title = `${author.name}/${name}-${branchName}-for gitlink;for git`;
|
||||
document.title = `${author.name}/${name}-${branchName} | GitLink`;
|
||||
}else{
|
||||
document.title = `${author.name}/${name}${description?': '+description:''}-for gitlink;for git` ;
|
||||
document.title = `${author.name}/${name}${description?': '+description:''} | GitLink` ;
|
||||
}
|
||||
}
|
||||
}, [treeValuePath, projectDetail, branchName])
|
||||
|
|
|
|||
|
|
@ -99,7 +99,14 @@ const TrendsIndex = Loadable({
|
|||
loader: () => import('../Activity/Activity'),
|
||||
loading: Loading,
|
||||
})
|
||||
|
||||
const DataSetIndex = Loadable({
|
||||
loader: () => import('../Dataset/Index'),
|
||||
loading: Loading,
|
||||
})
|
||||
const DataSetUpload = Loadable({
|
||||
loader: () => import('../Dataset/component/uploadModal'),
|
||||
loading: Loading,
|
||||
})
|
||||
const DevAbout = Loadable({
|
||||
loader: () => import('../About/Index'),
|
||||
loading: Loading,
|
||||
|
|
@ -153,6 +160,8 @@ function checkPathname(projectsId, owner, pathname) {
|
|||
name = "activity"
|
||||
} else if (url.indexOf("/settings") > -1) {
|
||||
name = "settings"
|
||||
} else if (url.indexOf("/dataset") > -1) {
|
||||
name = "dataset"
|
||||
} else if (url.indexOf(`/devops`) > -1) {
|
||||
name = "devops"
|
||||
} else if (url.indexOf(`/source`) > -1) {
|
||||
|
|
@ -555,6 +564,7 @@ class Detail extends Component {
|
|||
const common = {
|
||||
getDetail: this.getDetail,
|
||||
getBanner: this.getBanner,
|
||||
getProject:this.getProject,
|
||||
changeOpenDevops: this.changeOpenDevops,
|
||||
defaultBranch
|
||||
}
|
||||
|
|
@ -701,6 +711,18 @@ class Detail extends Component {
|
|||
() => (<DevAbout {...this.props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
|
||||
{/* 数据集 */}
|
||||
<Route path="/:owner/:projectsId/dataset/upload"
|
||||
render={
|
||||
(props) => (<DataSetUpload {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/:owner/:projectsId/dataset"
|
||||
render={
|
||||
(props) => (<DataSetIndex {...this.props} {...props} {...this.state} {...common}/>)
|
||||
}
|
||||
></Route>
|
||||
{/* wiki新增文件 */}
|
||||
<Route path="/:owner/:projectsId/wiki/add"
|
||||
render={
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 898 B |
|
|
@ -228,7 +228,7 @@
|
|||
li{
|
||||
text-align: center;
|
||||
padding:0px;
|
||||
margin-right: 35px;
|
||||
margin-right: 30px;
|
||||
display: flex;
|
||||
& > a{
|
||||
position: relative;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Skeleton , Tooltip} from 'antd';
|
|||
import { Link } from 'react-router-dom';
|
||||
import { numFormat } from 'educoder';
|
||||
import QuitBox from './quit';
|
||||
import datasetImg from '../img/dataset.jpg';
|
||||
import axios from 'axios';
|
||||
|
||||
function DetailBanner({ history,list , owner , projectsId ,showNotification , url , pathname , state , urlFlag , projectDetail , platform ,open_devops ,current_user, showNpsModal }){
|
||||
|
|
@ -104,6 +105,16 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
|
|||
</li>
|
||||
:""
|
||||
}
|
||||
{
|
||||
item.menu_name === "dataset" ?
|
||||
<li className={pathname==="dataset" ? "active" : ""}>
|
||||
<Link className='newTab' to={{ pathname: `/${owner}/${projectsId}/dataset`, state:{...state,open_devops} }}>
|
||||
<img src={datasetImg} height={15} alt="" className="mr5 mt5"/>数据集
|
||||
{projectDetail && projectDetail.ops_count ? <span>{projectDetail.ops_count}</span> : ""}
|
||||
</Link>
|
||||
</li>
|
||||
:""
|
||||
}
|
||||
{/* {
|
||||
item.menu_name === "resources" &&
|
||||
<li className={pathname==="source" ? "active" : ""}>
|
||||
|
|
@ -168,6 +179,7 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
|
|||
)
|
||||
})
|
||||
}
|
||||
|
||||
</ul>
|
||||
:
|
||||
<Skeleton paragraph={false} active={true}/>
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ function Index(props) {
|
|||
dataIndex: "commit",
|
||||
key: 3,
|
||||
ellipsis: true,
|
||||
width: "240px",
|
||||
width: "260px",
|
||||
render: (txt, item) => {
|
||||
return (
|
||||
<div className='treeinfo'>
|
||||
|
|
@ -97,7 +97,7 @@ function Index(props) {
|
|||
dataIndex: "commit_id",
|
||||
key: 4,
|
||||
ellipsis: true,
|
||||
width: "250px",
|
||||
width: "225px",
|
||||
render: (txt, item) => {
|
||||
return <div className="treecopy">
|
||||
<div className='treeCopyBox'>
|
||||
|
|
@ -110,54 +110,57 @@ function Index(props) {
|
|||
</div>
|
||||
</div>
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "分支类型",
|
||||
dataIndex: "default_branch",
|
||||
key: 5,
|
||||
width: "150px",
|
||||
render: (txt, item) => {
|
||||
return isManager ? txt === item.name ? <a className='btn-83' style={{width: '93px'}}>默认分支</a> : <Select value={1} onChange={(value)=>{updateDefaultBranch(value, item)}}>
|
||||
<Select.Option value={0}>默认分支</Select.Option>
|
||||
<Select.Option value={1}>普通分支</Select.Option>
|
||||
</Select> : txt === item.name ? '默认分支' : '普通分支'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
dataIndex: "name",
|
||||
key: 6,
|
||||
align: "center",
|
||||
width: "300px",
|
||||
className: "branchActionColumn",
|
||||
render: (txt, item,key) => {
|
||||
return (
|
||||
// item.is_deleted ?
|
||||
// <div style={{textAlign:"right"}}>
|
||||
// <Popover content={<span>将基于 Commits<span className="color-blue ml3 mr3">{truncateCommitId(item.commit_id)}</span>创建分支</span>}>
|
||||
// <Button onClick={()=>restoreBranch(item.branch_id,item.name)}>恢复分支</Button>
|
||||
// </Popover>
|
||||
// </div>:
|
||||
<div className="treeabout">
|
||||
{
|
||||
(isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) &&
|
||||
<Tooltip title={`以${txt}为源分支创建一个合并请求`}><Link to={
|
||||
// 如果项目是fork的项目,pr自动指向源仓库,否则指向本仓库默认分支
|
||||
projectDetail && projectDetail.fork_info?
|
||||
`/${projectDetail.fork_info.fork_project_user_login}/${projectDetail.fork_info.fork_project_identifier}/compare/${turnbar(txt || defaultBranch)}...${owner + ':' + turnbar(txt)}`
|
||||
:`/${owner}/${projectsId}/compare/${turnbar(defaultBranch)}...${turnbar(txt)}`
|
||||
} className="btn-83">+ 合并请求</Link></Tooltip>
|
||||
}
|
||||
<Dropdown overlay={menu(item.zip_url,item.tar_url)} trigger={['click']} placement="bottomRight">
|
||||
<a className="btn-83" style={{width: '76px'}}>下载<i className="iconfont icon-sanjiaoxing-down font-14"></i></a>
|
||||
</Dropdown>
|
||||
{isManager && (txt === item.default_branch ? <Tooltip title={`该分支为默认分支,不支持删除操作`}><Button style={{width: '76px'}} disabled>删除</Button></Tooltip> : <Button className='f6_bor_but' style={{width: '76px'}} onClick={()=>{setVisible(item)}}>删除</Button>)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const mergeCol = {
|
||||
title: "分支类型",
|
||||
dataIndex: "default_branch",
|
||||
key: 5,
|
||||
width:"150px",
|
||||
render: (txt, item) => {
|
||||
return isManager ? txt === item.name ? <a className='btn-83' style={{width: '93px'}}>默认分支</a> : <Select value={1} onChange={(value)=>{updateDefaultBranch(value, item)}}>
|
||||
<Select.Option value={0}>默认分支</Select.Option>
|
||||
<Select.Option value={1}>普通分支</Select.Option>
|
||||
</Select> : txt === item.name ? '默认分支' : '普通分支'
|
||||
}
|
||||
}
|
||||
|
||||
const operCol ={
|
||||
title: "操作",
|
||||
dataIndex: "name",
|
||||
key: 6,
|
||||
align: "center",
|
||||
width: "300px",
|
||||
className: "branchActionColumn",
|
||||
render: (txt, item,key) => {
|
||||
return (
|
||||
item.is_deleted ?
|
||||
isManager ? <div style={{textAlign:"right"}}>
|
||||
<Popover content={<span>将基于 Commits<span className="color-blue ml3 mr3">{truncateCommitId(item.commit_id)}</span>恢复分支</span>}>
|
||||
<Button onClick={()=>restoreBranch(item.branch_id,item.name)}>恢复分支</Button>
|
||||
</Popover>
|
||||
</div>:""
|
||||
:
|
||||
<div className="treeabout">
|
||||
{
|
||||
(isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) &&
|
||||
<Tooltip title={`以${txt}为源分支创建一个合并请求`}><Link to={
|
||||
// 如果项目是fork的项目,pr自动指向源仓库,否则指向本仓库默认分支
|
||||
projectDetail && projectDetail.fork_info?
|
||||
`/${projectDetail.fork_info.fork_project_user_login}/${projectDetail.fork_info.fork_project_identifier}/compare/${turnbar(txt || defaultBranch)}...${owner + ':' + turnbar(txt)}`
|
||||
:`/${owner}/${projectsId}/compare/${turnbar(defaultBranch)}...${turnbar(txt)}`
|
||||
} className="btn-83">+ 合并请求</Link></Tooltip>
|
||||
}
|
||||
<Dropdown overlay={menu(item.zip_url,item.tar_url)} trigger={['click']} placement="bottomRight">
|
||||
<a className="btn-83" style={{width: '76px'}}>下载<i className="iconfont icon-sanjiaoxing-down font-14"></i></a>
|
||||
</Dropdown>
|
||||
{isManager && (txt === item.default_branch ? <Tooltip title={`该分支为默认分支,不支持删除操作`}><Button style={{width: '76px'}} disabled>删除</Button></Tooltip> : <Button className='f6_bor_but' style={{width: '76px'}} onClick={()=>{setVisible(item)}}>删除</Button>)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function restoreBranch(id,name){
|
||||
const url = `/v1/${owner}/${projectsId}/branches/restore.json`;
|
||||
Axios.post(url,{
|
||||
|
|
@ -216,9 +219,10 @@ function Index(props) {
|
|||
}).then(res=>{
|
||||
if(res && res.data){
|
||||
// 重新请求仓库详情接口,更新分支总数信息
|
||||
setIsSpin(true);
|
||||
getDetail();
|
||||
setReload(Math.random());
|
||||
setAddBranch(false);
|
||||
setTimeout(()=>{getList()},1500);
|
||||
message.success('新建分支成功');
|
||||
}
|
||||
})
|
||||
|
|
@ -292,10 +296,10 @@ function Index(props) {
|
|||
<div>
|
||||
<Input.Search placeholder='请输入分支名称' style={{width: '354px'}} className='searchBranch' onSearch={(value)=>{setCurrent(1);setName(value)}} allowClear/>
|
||||
|
||||
{/* <Radio.Group value={chooseStatus} buttonStyle="solid" onChange={(v)=>{setChooseStatus(v.target.value)}} style={{marginLeft:"25px"}}>
|
||||
<Radio.Group value={chooseStatus} buttonStyle="solid" onChange={(v)=>{setChooseStatus(v.target.value)}} style={{marginLeft:"25px"}}>
|
||||
<Radio.Button value="all">代码库分支</Radio.Button>
|
||||
<Radio.Button value="deleted">已删除分支</Radio.Button>
|
||||
</Radio.Group> */}
|
||||
</Radio.Group>
|
||||
</div>
|
||||
<div>
|
||||
{isManager && <Link to={`/${owner}/${projectsId}/settings/branches`} className="btn-83" style={{width: '102px'}}><i className="iconfont icon-xuanzhongjibenshezhiicon font-14 mr5"></i>分支设置</Link>}
|
||||
|
|
@ -306,7 +310,7 @@ function Index(props) {
|
|||
rowKey={'name'}
|
||||
className='branchListTable'
|
||||
dataSource={list}
|
||||
columns={columns}
|
||||
columns={chooseStatus==="deleted"?[...columns,operCol]:[...columns,mergeCol,operCol]}
|
||||
pagination={{current: current,
|
||||
pageSize: pageSize,
|
||||
total: total,
|
||||
|
|
@ -396,7 +400,7 @@ function Index(props) {
|
|||
>
|
||||
<div className="contents mb30" style={{justifyContent: 'flex-start'}}>
|
||||
<i className='iconfont icon-shanchu_tc_icon1 font-36 mr18' style={{color: '#ca0002'}}></i>
|
||||
<p style={{color: '#333'}}>删除分支,本操作将会关闭已开启的Pull Request</p>
|
||||
<p style={{color: '#333'}}>删除分支,本操作将会关闭已开启的合并请求(PR)</p>
|
||||
</div>
|
||||
</Modals>
|
||||
<Modal
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export default Form.create()(
|
|||
const [tagList, setTagList] = useState(undefined);
|
||||
const [desc, setDesc] = useState(null);
|
||||
const [branch, setBranch ] = useState(null);
|
||||
const [saveBranch, setSaveBranch ] = useState(null);
|
||||
const [fileList, setFileList] = useState(undefined);
|
||||
const [attachment, setAttachment] = useState(undefined);
|
||||
const [options , setOptions] = useState(undefined);
|
||||
|
|
@ -104,7 +105,7 @@ export default Form.create()(
|
|||
...value,
|
||||
body: desc,
|
||||
attachment_ids: fileList,
|
||||
target_commitish:branch
|
||||
target_commitish:saveBranch
|
||||
})
|
||||
.then(result => {
|
||||
if (result) {
|
||||
|
|
@ -118,7 +119,7 @@ export default Form.create()(
|
|||
...value,
|
||||
body: desc,
|
||||
attachment_ids: fileList,
|
||||
target_commitish:branch
|
||||
target_commitish:saveBranch
|
||||
})
|
||||
.then(result => {
|
||||
if (result) {
|
||||
|
|
@ -138,7 +139,8 @@ export default Form.create()(
|
|||
}
|
||||
|
||||
function changeBranch(params) {
|
||||
setBranch(params);
|
||||
// setBranch(params);
|
||||
setSaveBranch(params)
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -177,6 +179,7 @@ export default Form.create()(
|
|||
owner={owner}
|
||||
history={history}
|
||||
tagflag={false}
|
||||
commitflag={true}
|
||||
branchList={projectDetail && projectDetail.branches && projectDetail.branches.list}
|
||||
></SelectBranch>
|
||||
<p className="font-12 color-grey-6 weight400">选择一个已经存在的标签,或者在发布时新建一个标签</p>
|
||||
|
|
@ -214,7 +217,7 @@ export default Form.create()(
|
|||
icon={
|
||||
<i className="iconfont icon-shangchuanicon dragIcon" />
|
||||
}
|
||||
size={100}
|
||||
size={300}
|
||||
showNotification={showNotification}
|
||||
/>
|
||||
{versionId && attachment && attachment.length > 0 ? (
|
||||
|
|
@ -264,7 +267,7 @@ export default Form.create()(
|
|||
<div className="infosTip">
|
||||
<p className="font-16 mb14 weight">附件大小说明</p>
|
||||
<p>
|
||||
单个附件不能超过 100M,每个仓库总附件不可超过
|
||||
单个附件不能超过 300M,每个仓库总附件不可超过
|
||||
1G。附件总容量统计包括仓库附件和发行版附件。
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ function version(props) {
|
|||
<div className="versionName">
|
||||
<Link onClick={()=>{window.scrollTo(0,0)}} to={`/${owner}/${projectsId}/tree/${item.tag_name}`} className="task-hide color-blue hover font-18">{item.name}</Link>
|
||||
<span>
|
||||
{data && data.user_admin_permission && type !== 2 && <Link to={{pathname:`/${owner}/${projectsId}/releases/${item.version_id}/update`,state:{"stable":item.draft==="稳定"}}} className="ml15"><i className="iconfont icon-a-bianji1 font-16 color-grey-6"></i></Link>}
|
||||
{data && data.user_admin_permission && type !== 2 &&
|
||||
{data && data.user_admin_permission && <Link to={{pathname:`/${owner}/${projectsId}/releases/${item.version_id}/update`,state:{"stable":item.draft==="稳定"}}} className="ml15"><i className="iconfont icon-a-bianji1 font-16 color-grey-6"></i></Link>}
|
||||
{data && data.user_admin_permission &&
|
||||
<Popconfirm
|
||||
placement="bottom"
|
||||
title={'您确定要删除当前发行版吗?'}
|
||||
|
|
@ -131,7 +131,7 @@ function version(props) {
|
|||
return (
|
||||
<React.Fragment>
|
||||
{
|
||||
data && data.user_permission && type !== 2 &&
|
||||
data && data.user_permission &&
|
||||
<div className="addReleaseBtn">
|
||||
<Button type={"primary"} onClick={addFunc} className="btnblue" style={{height:"36px"}}>发布新版本</Button>
|
||||
</div>
|
||||
|
|
@ -144,7 +144,7 @@ function version(props) {
|
|||
} else if (releases && releases.length === 0) {
|
||||
return (
|
||||
<Empty
|
||||
operation={data && data.user_permission && type !== 2}
|
||||
operation={data && data.user_permission}
|
||||
addFunc={addFunc}
|
||||
/>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ function Files({ data,history,owner,projectsId , parentsSha }){
|
|||
)
|
||||
|
||||
function subStrContent(content){
|
||||
return content ? content.slice(1) :"";
|
||||
return content ? " " + content.slice(1) :"";
|
||||
}
|
||||
|
||||
return(
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ const menu = [
|
|||
{name:"疑修 (Issue)",index:"issues"},
|
||||
{name:"合并请求 (PR)",index:"pulls"},
|
||||
{name:"引擎 (Engine)",index:"devops"},
|
||||
{name:"数据集",index:"dataset"},
|
||||
// {name:"资源库",index:"resources"},
|
||||
{name:"里程碑",index:"versions"},
|
||||
{name:"维基 (Wiki)",index:"wiki"},
|
||||
|
|
@ -163,13 +164,16 @@ class Setting extends Component {
|
|||
update=(values)=>{
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
const { private_check , project_units } = this.state;
|
||||
const {project_language_id, project_category_id, pr_view_admin} = values;
|
||||
const url = `/${owner}/${projectsId}.json`;
|
||||
axios.put(url, {
|
||||
axios.patch(url, {
|
||||
name: values.project_name,
|
||||
description: values.project_description,
|
||||
private: private_check,
|
||||
identifier:values.project_identifier,
|
||||
...values,
|
||||
project_language_id,
|
||||
project_category_id,
|
||||
pr_view_admin
|
||||
}).then((result) => {
|
||||
if (result) {
|
||||
this.props.showNotification(`仓库信息修改成功!`);
|
||||
|
|
@ -394,7 +398,7 @@ class Setting extends Component {
|
|||
{getFieldDecorator("project_units", {
|
||||
rules: [],
|
||||
})(
|
||||
<Checkbox.Group>
|
||||
<Checkbox.Group className="unitStyle">
|
||||
{
|
||||
menu.map((item,key)=>{
|
||||
return(
|
||||
|
|
|
|||
|
|
@ -348,4 +348,11 @@
|
|||
border-top: 1px solid rgba(90, 117, 193, 0.23)
|
||||
}
|
||||
}
|
||||
}
|
||||
.unitStyle{
|
||||
.ant-checkbox-wrapper + .ant-checkbox-wrapper{
|
||||
margin-left: 0px;
|
||||
margin-right: 8px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
|
@ -77,7 +77,7 @@ export default Form.create()(
|
|||
callback("只能以数字或字母开头,仅支持横杠、下划线、点三种符号,不允许符号连续排列,长度4-50个字符");
|
||||
}
|
||||
if(value && (value.length<4 || value.length>50)){
|
||||
callback("只能以数字或字母开头,仅支持横杠、下划线、点三种符号,不允许符号连续排列,长度4-50个字符12");
|
||||
callback("只能以数字或字母开头,仅支持横杠、下划线、点三种符号,不允许符号连续排列,长度4-50个字符");
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,9 +141,9 @@ export default Form.create()(
|
|||
"name",
|
||||
[
|
||||
{ required: true, message: "请输入组织账号" },
|
||||
{
|
||||
validator:checkname
|
||||
}
|
||||
// {
|
||||
// validator:checkname
|
||||
// }
|
||||
],
|
||||
<Input placeholder="请输入组织账号" disabled/>,true
|
||||
)}
|
||||
|
|
@ -170,7 +170,7 @@ export default Form.create()(
|
|||
"官方网站:",
|
||||
"website",
|
||||
[],
|
||||
<Input placeholder="请输入官方网站" />
|
||||
<Input placeholder="请输入官方网站" maxLength={100}/>
|
||||
)}
|
||||
{helper(
|
||||
'所在地区:',
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
|
|||
let wikiName = ''
|
||||
let key = '';
|
||||
if (!pathname.endsWith('/wiki/add')) {
|
||||
wikiName = decodeURI(pathname.split('/')[4]);
|
||||
wikiName = pathname.split('/')[4];
|
||||
key = pathname.split('/')[5];
|
||||
}else{
|
||||
key = search.split('=').pop();
|
||||
|
|
@ -116,12 +116,6 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
|
|||
};
|
||||
validateFields((err, values) => {
|
||||
if (!err) {
|
||||
let regEn = /[\\/:*?"<>|[\]-]/g;
|
||||
if (regEn.test(values.title)) {
|
||||
message.error('文件名不能有特殊字符: \\ / : * ? \" < > | [ \] -');
|
||||
setOperateFlag(false);
|
||||
return;
|
||||
}
|
||||
const {md_content, title} = values;
|
||||
if (wikiName && search!== "?copy") {
|
||||
updateWiki({
|
||||
|
|
@ -130,7 +124,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
|
|||
projectId: project.id,
|
||||
pageName: wikiName,
|
||||
title,
|
||||
commit_message: '',
|
||||
message: '',
|
||||
content_base64: Base64.encode(md_content)
|
||||
}).then(res => dealRes(res, title));
|
||||
} else {
|
||||
|
|
@ -223,7 +217,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
|
|||
projectId: project.id,
|
||||
pageName: '_Sidebar',
|
||||
title: '_Sidebar',
|
||||
commit_message: '',
|
||||
message: '',
|
||||
content_base64: Base64.encode(content)
|
||||
}).then(res => {
|
||||
if (res && res.message === "200") {
|
||||
|
|
@ -333,7 +327,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
|
|||
"title",
|
||||
[
|
||||
{ required: true, message: "请输入标题" },
|
||||
// { pattern: /[^`\[\]\/:*?''<>|%-+_]/g, message: '不允许部分特殊字符' }
|
||||
{ pattern: /^(?!-).*$/, message: '不能以-开头' }
|
||||
],
|
||||
<Input
|
||||
placeholder={"请输入标题"}
|
||||
|
|
@ -360,7 +354,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
|
|||
})(<Input style={{ display: 'none' }} />)}
|
||||
</Form.Item>
|
||||
|
||||
<Checkbox checked={modal} onChange={changeModal}>添加模版</Checkbox>
|
||||
<Checkbox checked={modal} onChange={changeModal} className='mt10'>添加模版</Checkbox>
|
||||
|
||||
<Radio.Group onChange={changeModalType} value={modalType}>
|
||||
<Radio value='周报'>周报</Radio>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import CopyTool from '../Component/CopyTool';
|
|||
import Welcome from './Welcome';
|
||||
import RenderHtml from "../../components/render-html";
|
||||
|
||||
import { wikiPages, getWiki, parseSidebar, updateWiki, treeToMd } from './api';
|
||||
import { wikiPages, getWiki, parseSidebar, updateWiki, treeToMd, deleteSameKey } from './api';
|
||||
import { httpUrl } from './fetch';
|
||||
import './Index.scss';
|
||||
import './components/ModalFun/index.scss';
|
||||
|
|
@ -38,18 +38,9 @@ export default (props) => {
|
|||
const [addMenuError, setAddMenuError] = useState(undefined);
|
||||
const [sidebar, setSidebar] = useState(undefined);
|
||||
const [defaultSelectedKeys, setDefaultSelectedKeys] = useState(undefined);
|
||||
const [masterProtected, setMasterProtected] = useState(false);
|
||||
|
||||
useEffect(()=>{
|
||||
window.scrollTo(0,0);
|
||||
// 获取仓库分支信息,判断master是否设置了分支保护
|
||||
if(projectsId && owner){
|
||||
axios.get(`/v1/${owner}/${projectsId}/branches.json`, {keyword: 'master'}).then(res=>{
|
||||
if(res && res.data && res.data.total_count === 1){
|
||||
setMasterProtected(res.data.branches[0].protected);
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(()=>{
|
||||
|
|
@ -84,9 +75,9 @@ export default (props) => {
|
|||
setSidebar(sidebar)
|
||||
setFileList(menuList);
|
||||
let firstWikiNode = undefined;
|
||||
const arr = pathname.split('/');
|
||||
if(!pathname.endsWith('/wiki')){
|
||||
firstWikiNode = findNodeByName(menuList, arr[arr.length-2]);
|
||||
const {wikiName} = match.params;
|
||||
firstWikiNode = findNodeByName(menuList, wikiName);
|
||||
} else{
|
||||
// 找到目录树中第一个[[页面]]
|
||||
firstWikiNode = findFirstWiki(menuList);
|
||||
|
|
@ -95,14 +86,14 @@ export default (props) => {
|
|||
!firstWikiNode && (firstWikiNode = findFirstWiki(menuList));
|
||||
// 设置目录 选中节点初始化
|
||||
setDefaultSelectedKeys([firstWikiNode.key+""]);
|
||||
const title = firstWikiNode.title.trim().substring(2,firstWikiNode.title.trim().length-2);
|
||||
const title = firstWikiNode.titleStr;
|
||||
const firstWiki = res.data.filter(item => { return title === item.name })[0];
|
||||
setCheckItem({
|
||||
...firstWiki,
|
||||
key: firstWikiNode.key
|
||||
})
|
||||
if(window.location.pathname.indexOf('/wiki') === -1) return
|
||||
history.push(`/${owner}/${projectsId}/wiki/${title}/${firstWikiNode.key}`);
|
||||
history.push(encodeURI(`/${owner}/${projectsId}/wiki/${firstWiki.sub_url}/${firstWikiNode.key}`));
|
||||
} else {
|
||||
setFileArr([]);
|
||||
setFileArrInit([]);
|
||||
|
|
@ -110,12 +101,12 @@ export default (props) => {
|
|||
});
|
||||
}, [project, reload])
|
||||
|
||||
// 加载单个wiki详情,参数尽量用驼峰,此处由于后端太麻烦所以不标准
|
||||
// 加载单个wiki详情,sub_url: 后端转义的字符串
|
||||
useEffect(() => {
|
||||
project && checkItem.name && getWiki({
|
||||
project && checkItem.sub_url && getWiki({
|
||||
owner: owner,
|
||||
repo: projectsId,
|
||||
pageName: checkItem.name,
|
||||
pageName: checkItem.sub_url,
|
||||
projectId: project.id
|
||||
}).then(res => {
|
||||
if (res && res.message === "200") {
|
||||
|
|
@ -190,11 +181,6 @@ export default (props) => {
|
|||
setAddMenuError("不能仅输入空格");
|
||||
return;
|
||||
}
|
||||
const regEn = /[\\/:*?"<>|[\]-]/g;
|
||||
if (regEn.test(menuName)) {
|
||||
setAddMenuError("不能有特殊字符: \\ / : * ? \" < > | [ \] -");
|
||||
return;
|
||||
}
|
||||
// 校验一级目录中是否有相同名称
|
||||
const oneMenuList = fileList.filter(item=>!item.title.trim().startsWith('[[')).map(i=>i.title.trim())
|
||||
if(oneMenuList.includes(`- ${menuName}`)){
|
||||
|
|
@ -215,7 +201,7 @@ export default (props) => {
|
|||
projectId: project.id,
|
||||
pageName: '_Sidebar',
|
||||
title: '_Sidebar',
|
||||
commit_message: '',
|
||||
message: '',
|
||||
content_base64: Base64.encode(treeToMd(sidebarList))
|
||||
}).then(res => {
|
||||
if (res && res.message === "200") {
|
||||
|
|
@ -233,11 +219,11 @@ export default (props) => {
|
|||
}
|
||||
|
||||
function goEdit(params) {
|
||||
history.push(`/${owner}/${projectsId}/wiki/${encodeURI(checkItem.name)}/${checkItem.key}/edit${params}`);
|
||||
history.push(encodeURI(`/${owner}/${projectsId}/wiki/${checkItem.sub_url}/${checkItem.key}/edit${params}`));
|
||||
}
|
||||
|
||||
function preview() {
|
||||
window.open(`/${owner}/${projectsId}/wiki/preview/${encodeURI(project.name)}/${project.id}`);
|
||||
window.open(encodeURI(`/${owner}/${projectsId}/wiki/preview/${project.name}/${project.id}`));
|
||||
}
|
||||
|
||||
// 支持 Markdown,Html,Pdf格式文件
|
||||
|
|
@ -262,11 +248,18 @@ export default (props) => {
|
|||
function changeitem(item){
|
||||
const {name, key} = item;
|
||||
const wiki = fileArrInit.filter(item => { return item.name == name })[0];
|
||||
if(!wiki){
|
||||
// 不存在的wiki,修正sidebarfindSameKeyByDel
|
||||
const menuListByDel = deleteSameKey(fileList, key);
|
||||
updateWikiFun(menuListByDel);
|
||||
message.success("不存在的wiki")
|
||||
return
|
||||
}
|
||||
setCheckItem({
|
||||
...wiki,
|
||||
key
|
||||
})
|
||||
history.push(`/${owner}/${projectsId}/wiki/${name}/${key}`);
|
||||
history.push(encodeURI(`/${owner}/${projectsId}/wiki/${name}/${key}`));
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -302,7 +295,7 @@ export default (props) => {
|
|||
<div className="wiki-nav">
|
||||
|
||||
{/* 读sidebar转换成目录树 */}
|
||||
<Sidebar fileList = {fileList} changeitem={changeitem} projectsId={projectsId} owner={owner} project={project} setReload={setReload} sidebar={sidebar} history={history} permission={permission} defaultSelectedKeys={defaultSelectedKeys} fileArrInit={fileArrInit} masterProtected={masterProtected}/>
|
||||
<Sidebar fileList = {fileList} changeitem={changeitem} projectsId={projectsId} owner={owner} project={project} setReload={setReload} sidebar={sidebar} history={history} permission={permission} defaultSelectedKeys={defaultSelectedKeys} fileArrInit={fileArrInit}/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -332,7 +325,7 @@ export default (props) => {
|
|||
{permission && <Button type="primary" onClick={()=>{goEdit("")}}>编辑</Button>}
|
||||
</div>
|
||||
|
||||
{itemDetail&&itemDetail.md_content&&<RenderHtml className="wiki-content-detail editor-content-panel imageLayerParent" value={ itemDetail && Base64.decode(itemDetail.md_content) } url={history.location}/>}
|
||||
{itemDetail && itemDetail.md_content && <RenderHtml className="wiki-content-detail editor-content-panel imageLayerParent" value={Base64.decode(itemDetail.md_content) } url={history.location}/>}
|
||||
</div>
|
||||
</div>
|
||||
</div >
|
||||
|
|
|
|||
|
|
@ -102,13 +102,13 @@ body {
|
|||
font-family: "PingFangSC-Regular";
|
||||
}
|
||||
|
||||
.has-error .ant-form-explain,
|
||||
.has-error .ant-form-split {
|
||||
position: absolute;
|
||||
}
|
||||
.wiki-md .ant-form-explain{
|
||||
bottom: -6px;
|
||||
}
|
||||
// .has-error .ant-form-explain,
|
||||
// .has-error .ant-form-split {
|
||||
// position: absolute;
|
||||
// }
|
||||
// .wiki-md .ant-form-explain{
|
||||
// bottom: -6px;
|
||||
// }
|
||||
.wiki-nav {
|
||||
max-height: 60vh;
|
||||
.wiki-search {
|
||||
|
|
|
|||
|
|
@ -60,10 +60,10 @@ export default (props) => {
|
|||
|
||||
|
||||
useEffect(() => {
|
||||
projectsId && checkItem.name && getWiki({
|
||||
projectsId && checkItem.sub_url && getWiki({
|
||||
owner: owner,
|
||||
repo: projectsId,
|
||||
pageName: checkItem.name,
|
||||
pageName: checkItem.sub_url,
|
||||
projectId: projectId,
|
||||
}).then(res => {
|
||||
if (res && res.message === "200") {
|
||||
|
|
@ -111,12 +111,13 @@ export default (props) => {
|
|||
}
|
||||
|
||||
function selectTree(keys,event){
|
||||
let {title, key} = event.node.props.dataRef;
|
||||
title = title.trim()
|
||||
const isFile = title.startsWith('[[') && title.endsWith(']]');
|
||||
let {isFile, key, titleStr} = event.node.props.dataRef;
|
||||
if(isFile){
|
||||
title = title.substring(2,title.length-2);
|
||||
setCheckItem({name: title, key});
|
||||
const wiki = fileArr.filter(item => { return item.name == titleStr })[0];
|
||||
setCheckItem({
|
||||
...wiki,
|
||||
key
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ export async function parseSidebar(wikiList, info){
|
|||
})
|
||||
}
|
||||
ReInfo={
|
||||
menuList: markdownToTree(list.length ? `${sidebarCont}${wikiSidebar}` : sidebarCont),
|
||||
menuList: markdownToTree(list.length ? `${sidebarCont}${wikiSidebar}` : sidebarCont, wikiList),
|
||||
sidebar: sidebarCont
|
||||
}
|
||||
}
|
||||
|
|
@ -96,14 +96,14 @@ export async function parseSidebar(wikiList, info){
|
|||
content_base64: Base64.encode(wikiSidebarStr)
|
||||
})
|
||||
ReInfo={
|
||||
menuList: markdownToTree(wikiSidebarStr),
|
||||
menuList: markdownToTree(wikiSidebarStr, wikiList),
|
||||
sidebar: wikiSidebarStr
|
||||
}
|
||||
}
|
||||
return ReInfo;
|
||||
}
|
||||
|
||||
export function markdownToTree(markdownText){
|
||||
export function markdownToTree(markdownText, wikiList){
|
||||
const lines = markdownText.split('\n');
|
||||
let key = -1;
|
||||
// stack: [{一级目录},{二级目录}]
|
||||
|
|
@ -113,16 +113,23 @@ export function markdownToTree(markdownText){
|
|||
children: [],
|
||||
key: key++
|
||||
}
|
||||
const wikiNameAndSubUrl = {}
|
||||
wikiList && wikiList.map(item=>{
|
||||
return wikiNameAndSubUrl[item.name] = item.sub_url
|
||||
})
|
||||
lines.map((item, index) =>{
|
||||
const title = item.trim();
|
||||
const isFile = title.startsWith('[[') && title.endsWith(']]');
|
||||
const titleStr = isFile ? title.substring(2, title.length - 2) : title.substring(2, title.length)
|
||||
const node = {
|
||||
// 带空格+[[]]或者- 标识
|
||||
title: item,
|
||||
children: [],
|
||||
key: undefined,
|
||||
// 纯内容
|
||||
titleStr: isFile ? title.substring(2, title.length - 2) : title.substring(2, title.length),
|
||||
titleStr,
|
||||
// 编码后的title,获取wiki内容用title_sub
|
||||
title_sub: wikiNameAndSubUrl[titleStr],
|
||||
// 是否是wiki文件
|
||||
isFile: isFile
|
||||
}
|
||||
|
|
@ -253,4 +260,17 @@ export function findFirstWiki(list){
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 递归过滤相同key值的节点
|
||||
export function deleteSameKey(list, key){
|
||||
return list.filter(item => {
|
||||
if (item.key === key) {
|
||||
return false
|
||||
}
|
||||
if(item.children && item.children.length > 0){
|
||||
item.children = deleteSameKey(item.children , key)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ const {DirectoryTree, TreeNode} = Tree;
|
|||
|
||||
// wiki目录树
|
||||
export default function Sidebar(props) {
|
||||
const {fileList, changeitem, owner, projectsId, project, setReload, sidebar, history, permission, defaultSelectedKeys, fileArrInit, masterProtected} = props;
|
||||
const {fileList, changeitem, owner, projectsId, project, setReload, sidebar, history, permission, defaultSelectedKeys, fileArrInit} = props;
|
||||
const {location:{pathname}} = history;
|
||||
const [initMenuList, setInitMenuList] = useState(undefined);
|
||||
const [menuList, setMenuList] = useState(undefined);
|
||||
|
|
@ -66,10 +66,7 @@ export default function Sidebar(props) {
|
|||
</a>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
{
|
||||
masterProtected && item.children.length ? <a onClick={() => { message.error("由于master分支设置了分支保护,不允许删除wiki") }}>删除</a> :
|
||||
<a onClick={(e) => { deleteFileModal(e, title, isFile, item) }}>删除</a>
|
||||
}
|
||||
<a onClick={(e) => { deleteFileModal(e, title, isFile, item) }}>删除</a>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
};
|
||||
|
|
@ -82,10 +79,7 @@ export default function Sidebar(props) {
|
|||
</a>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
{
|
||||
masterProtected ? <a onClick={() => { message.error("由于master分支设置了分支保护,不允许删除wiki") }}>删除</a> :
|
||||
<a onClick={(e) => { deleteFileModal(e, title, isFile, item) }}>删除</a>
|
||||
}
|
||||
<a onClick={(e) => { deleteFileModal(e, title, isFile, item) }}>删除</a>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
};
|
||||
|
|
@ -163,7 +157,7 @@ export default function Sidebar(props) {
|
|||
const {node, children, key} = item;
|
||||
if(isFile){
|
||||
// 删除页面
|
||||
deleteWiki({owner: owner, repo: projectsId, projectId: project.id, pageName: title}).then(res => {
|
||||
deleteWiki({owner: owner, repo: projectsId, projectId: project.id, pageName: item.title_sub}).then(res => {
|
||||
if(res && res.message === "204"){
|
||||
// 递归过滤相同key值的节点,执行删除操作
|
||||
const menuListByDel = findSameKeyByDel(menuList, key);
|
||||
|
|
@ -267,7 +261,7 @@ export default function Sidebar(props) {
|
|||
projectId: project.id,
|
||||
pageName: '_Sidebar',
|
||||
title: '_Sidebar',
|
||||
commit_message: '',
|
||||
message: '',
|
||||
content_base64: Base64.encode(content)
|
||||
}).then(res => {
|
||||
if (res && res.message === "200") {
|
||||
|
|
@ -303,20 +297,18 @@ export default function Sidebar(props) {
|
|||
e.stopPropagation();
|
||||
setVisible(item);
|
||||
setIsEditName(type);
|
||||
let title = item.title.trim();
|
||||
const isFile = title.startsWith('[[') && title.endsWith(']]');
|
||||
title = isFile ? title.substring(2,title.length-2) : title.substring(2, title.length);
|
||||
const {titleStr, title_sub} = item;
|
||||
type === 2 && getWiki({
|
||||
owner: owner,
|
||||
repo: projectsId,
|
||||
pageName: title,
|
||||
pageName: title_sub,
|
||||
projectId: project.id
|
||||
}).then(res => {
|
||||
if (res && res.message === "200") {
|
||||
setWikiContent(res.data.md_content);
|
||||
}
|
||||
})
|
||||
setMenuName(title);
|
||||
setMenuName(titleStr);
|
||||
}
|
||||
|
||||
// 新增子目录 或者 重命名目录
|
||||
|
|
@ -329,9 +321,8 @@ export default function Sidebar(props) {
|
|||
setAddMenuError("不能仅输入空格");
|
||||
return;
|
||||
}
|
||||
const regEn = /[\\/:*?"<>|[\]-]/g;
|
||||
if (regEn.test(menuName)) {
|
||||
setAddMenuError('不能有特殊字符: \\ / : * ? \" < > | [ \] -');
|
||||
if (isEditName === 2 && /^-/.test(menuName)) {
|
||||
setAddMenuError('不能以-开头');
|
||||
return;
|
||||
}
|
||||
if(!isEditName){
|
||||
|
|
@ -356,14 +347,15 @@ export default function Sidebar(props) {
|
|||
}else{
|
||||
// isEditName 1 编辑目录名称 2编辑页面名称
|
||||
const titleToJudge = isEditName === 2 ? `[[${menuName}]]` : `- ${menuName}`;
|
||||
const {title, key} = visible;
|
||||
if(title.trim() === titleToJudge){
|
||||
const {key, titleStr, title_sub} = visible;
|
||||
// 判断是否有修改名称
|
||||
if(titleStr === menuName){
|
||||
setAddMenuError("请修改名称");
|
||||
return
|
||||
}
|
||||
// 找兄弟节点
|
||||
const list = findBrotherNodesByKey(menuList, key) || [];
|
||||
if(list.map(item=>item.title.trim()).includes(titleToJudge)){
|
||||
if(list.map(item=>item.titleStr).includes(menuName)){
|
||||
setAddMenuError("不能与同级目录名称相同");
|
||||
return
|
||||
}
|
||||
|
|
@ -381,17 +373,16 @@ export default function Sidebar(props) {
|
|||
})
|
||||
if(isEditName === 2){
|
||||
// 编辑页面名称-> 修改wiki
|
||||
const oldTitle = title.substring(title.indexOf('[[')+2, title.indexOf(']]'))
|
||||
updateWiki({
|
||||
owner,
|
||||
repo: projectsId,
|
||||
projectId: project.id,
|
||||
// 原名称
|
||||
pageName: oldTitle,
|
||||
pageName: title_sub,
|
||||
// 现名称
|
||||
title: menuName,
|
||||
content_base64: wikiContent,
|
||||
commit_message: '',
|
||||
message: '',
|
||||
}).then(res=>{
|
||||
if(res && res.message === '200'){
|
||||
// 修改wiki名称接口请求成功,更新sidebar
|
||||
|
|
|
|||
|
|
@ -59,10 +59,8 @@ export default function UploadWiki(props) {
|
|||
message.error('只能上传md、txt文件');
|
||||
return false;
|
||||
}
|
||||
|
||||
let regEn = /[\\/:*?"<>|[\]-]/g;
|
||||
if (regEn.test(file.name)) {
|
||||
message.error('文件名不能有特殊字符: \\ / : * ? \" < > | [ \] -');
|
||||
if (/^-/.test(file.name)) {
|
||||
message.error('文件名不能以-开头');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +84,7 @@ export default function UploadWiki(props) {
|
|||
projectId: project.id,
|
||||
pageName: '_Sidebar',
|
||||
title: '_Sidebar',
|
||||
commit_message: '',
|
||||
message: '',
|
||||
content_base64: Base64.encode(treeToMd(sidebarList))
|
||||
}).then(res => {
|
||||
if (res && res.message === "200") {
|
||||
|
|
|
|||
|
|
@ -81,8 +81,8 @@ li {
|
|||
|
||||
|
||||
.markdown-body {
|
||||
text-align: justify;
|
||||
word-break: break-all;
|
||||
text-align: left;
|
||||
word-break: unset;
|
||||
}
|
||||
|
||||
/* !!覆盖之前的样式*/
|
||||
|
|
|
|||
|
|
@ -2139,7 +2139,8 @@ input.ant-input-number-input:focus {
|
|||
}
|
||||
|
||||
/* md代码类样式渲染 */
|
||||
.new_li .markdown-body ul>li ,.markdown-body ul>li {
|
||||
/* issues/3984: ,.markdown-body ul>li */
|
||||
.new_li .markdown-body ul>li {
|
||||
list-style-type: disc !important;
|
||||
margin-bottom: 0 !important;
|
||||
white-space: pre-wrap;
|
||||
|
|
|
|||
|
|
@ -19,13 +19,13 @@ function LoginRegisterPage(props){
|
|||
<img src={banner} className="banner" alt="" />
|
||||
</div>
|
||||
<div className="login_register_right">
|
||||
{props.location.pathname === "/login" ?
|
||||
<Login {...props}/>
|
||||
{props.location.pathname === "/resetPassword" ?
|
||||
<ResetPassword mygetHelmetapi={mygetHelmetapi}/>
|
||||
:
|
||||
props.location.pathname === "/register" ?
|
||||
<Register mygetHelmetapi={mygetHelmetapi}/>
|
||||
:
|
||||
<ResetPassword mygetHelmetapi={mygetHelmetapi}/>
|
||||
<Login {...props}/>
|
||||
}
|
||||
<img src={img1} className="img1" alt="" />
|
||||
<img src={img2} className="img2" alt="" />
|
||||
|
|
|
|||
Loading…
Reference in New Issue