forked from Gitlink/forgeplus-react
Merge pull request 'FIX 代码库二级页面升级改版' (#121) from feature_repo_second_page into pre_develop_dev
This commit is contained in:
commit
3be536d37a
|
@ -0,0 +1,2 @@
|
|||
{
|
||||
}
|
|
@ -3425,9 +3425,9 @@
|
|||
"integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw=="
|
||||
},
|
||||
"clipboard": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz",
|
||||
"integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==",
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz",
|
||||
"integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==",
|
||||
"requires": {
|
||||
"good-listener": "^1.2.2",
|
||||
"select": "^1.1.2",
|
||||
|
@ -7286,7 +7286,8 @@
|
|||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
|
@ -7703,7 +7704,8 @@
|
|||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
|
@ -7759,6 +7761,7 @@
|
|||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
|
@ -7802,12 +7805,14 @@
|
|||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"case-sensitive-paths-webpack-plugin": "2.1.1",
|
||||
"chalk": "1.1.3",
|
||||
"classnames": "^2.2.5",
|
||||
"clipboard": "^2.0.6",
|
||||
"clipboard": "^2.0.8",
|
||||
"code-prettify": "^0.1.0",
|
||||
"codemirror": "^5.53.0",
|
||||
"connected-react-router": "4.4.1",
|
||||
|
@ -125,7 +125,7 @@
|
|||
"scripts": {
|
||||
"start": "node --max_old_space_size=15360 scripts/start.js",
|
||||
"build": "cross-env NODE_ENV=production node --max_old_space_size=15360 scripts/build.js",
|
||||
"test-build": "NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js",
|
||||
"test-build": "cross-env NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js",
|
||||
"pre-build": "NODE_ENV=preBuild node --max_old_space_size=15360 scripts/build.js",
|
||||
"gen_stats": "NODE_ENV=production webpack --profile --config=./config/webpack.config.prod.js --json > stats.json",
|
||||
"ana": "webpack-bundle-analyzer ./stats.json",
|
||||
|
|
|
@ -1520,7 +1520,15 @@ a.edu-txt-w80,
|
|||
.font-16 {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
.weight400{
|
||||
font-weight: 400;
|
||||
}
|
||||
.weight500{
|
||||
font-weight: 500;
|
||||
}
|
||||
.weight{
|
||||
font-weight: bold;
|
||||
}
|
||||
.font-17 {
|
||||
font-size: 17px !important;
|
||||
}
|
||||
|
@ -1540,6 +1548,9 @@ a.edu-txt-w80,
|
|||
.font-25 {
|
||||
font-size: 25px !important;
|
||||
}
|
||||
.font-26 {
|
||||
font-size: 26px !important;
|
||||
}
|
||||
|
||||
.font-24 {
|
||||
font-size: 24px !important;
|
||||
|
@ -1561,6 +1572,9 @@ a.edu-txt-w80,
|
|||
font-size: 36px !important;
|
||||
}
|
||||
|
||||
.font-40 {
|
||||
font-size: 40px !important;
|
||||
}
|
||||
.font-50 {
|
||||
font-size: 50px !important;
|
||||
}
|
||||
|
@ -1746,6 +1760,14 @@ a.decoration {
|
|||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mb12 {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.mb13 {
|
||||
margin-bottom: 13px;
|
||||
}
|
||||
|
||||
.mb14 {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
@ -1927,7 +1949,9 @@ a.decoration {
|
|||
}
|
||||
|
||||
.mr20 {
|
||||
margin-right: 20px;
|
||||
margin-right: 10px;
|
||||
margin-left: 10px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.mr25 {
|
||||
|
@ -1935,7 +1959,7 @@ a.decoration {
|
|||
}
|
||||
|
||||
.mr30 {
|
||||
margin-right: 30px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.mr35 {
|
||||
|
@ -2460,7 +2484,7 @@ a:hover{
|
|||
.color-grey-B3 {
|
||||
color: #B3B3B3 !important;
|
||||
}
|
||||
`
|
||||
|
||||
.color-grey-B4 {
|
||||
color: #B4B4B4 !important;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2340181 */
|
||||
src: url('iconfont.woff2?t=1631773579834') format('woff2'),
|
||||
url('iconfont.woff?t=1631773579834') format('woff'),
|
||||
url('iconfont.ttf?t=1631773579834') format('truetype');
|
||||
src: url('iconfont.woff2?t=1632964996877') format('woff2'),
|
||||
url('iconfont.woff?t=1632964996877') format('woff'),
|
||||
url('iconfont.ttf?t=1632964996877') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
|
@ -13,6 +13,30 @@
|
|||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-wenjian7:before {
|
||||
content: "\e8e0";
|
||||
}
|
||||
|
||||
.icon-xiangyoujiantou:before {
|
||||
content: "\e8de";
|
||||
}
|
||||
|
||||
.icon-xiangzuojiantou:before {
|
||||
content: "\e8df";
|
||||
}
|
||||
|
||||
.icon-a-liulanicon2x:before {
|
||||
content: "\e8dd";
|
||||
}
|
||||
|
||||
.icon-wenjianicon:before {
|
||||
content: "\e8dc";
|
||||
}
|
||||
|
||||
.icon-a-yuanquan2x:before {
|
||||
content: "\e8db";
|
||||
}
|
||||
|
||||
.icon-xiangmubiaoqian:before {
|
||||
content: "\e8da";
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,6 +5,48 @@
|
|||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "24656750",
|
||||
"name": "文件",
|
||||
"font_class": "wenjian7",
|
||||
"unicode": "e8e0",
|
||||
"unicode_decimal": 59616
|
||||
},
|
||||
{
|
||||
"icon_id": "630094",
|
||||
"name": "向右箭头",
|
||||
"font_class": "xiangyoujiantou",
|
||||
"unicode": "e8de",
|
||||
"unicode_decimal": 59614
|
||||
},
|
||||
{
|
||||
"icon_id": "630095",
|
||||
"name": "向左箭头",
|
||||
"font_class": "xiangzuojiantou",
|
||||
"unicode": "e8df",
|
||||
"unicode_decimal": 59615
|
||||
},
|
||||
{
|
||||
"icon_id": "24600282",
|
||||
"name": "浏览icon@2x",
|
||||
"font_class": "a-liulanicon2x",
|
||||
"unicode": "e8dd",
|
||||
"unicode_decimal": 59613
|
||||
},
|
||||
{
|
||||
"icon_id": "24567893",
|
||||
"name": "文件icon",
|
||||
"font_class": "wenjianicon",
|
||||
"unicode": "e8dc",
|
||||
"unicode_decimal": 59612
|
||||
},
|
||||
{
|
||||
"icon_id": "24527422",
|
||||
"name": "圆圈@2x",
|
||||
"font_class": "a-yuanquan2x",
|
||||
"unicode": "e8db",
|
||||
"unicode_decimal": 59611
|
||||
},
|
||||
{
|
||||
"icon_id": "24378423",
|
||||
"name": "项目标签",
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -69,7 +69,7 @@ export function appendFileSizeToUploadFile(item) {
|
|||
}
|
||||
export function appendFileSizeToUploadFileAll(fileList) {
|
||||
return fileList.map(item => {
|
||||
if (item.name.indexOf(uploadNameSizeSeperator) == -1) {
|
||||
if (item.name.indexOf(uploadNameSizeSeperator) === -1) {
|
||||
return Object.assign({}, item, { name: `${item.name}${uploadNameSizeSeperator}${bytesToSize(item.size)}` })
|
||||
}
|
||||
return item
|
||||
|
|
|
@ -1,32 +1,60 @@
|
|||
import React , { useState , useEffect } from 'react';
|
||||
import { Popover , Dropdown , Input , Spin } from 'antd';
|
||||
import React , { useState , useEffect , useRef } from 'react';
|
||||
import { Dropdown} from 'antd';
|
||||
import './branch.scss';
|
||||
import { getBranch , getTag } from '../GetData/getData';
|
||||
import SelectOverlay from './SelectOverlay';
|
||||
|
||||
import { findDOMNode } from 'react-dom';
|
||||
|
||||
export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true })=>{
|
||||
const [ showValue , setShowValue ] = useState(branch);
|
||||
const [ visible , setVisible ] = useState(false);
|
||||
|
||||
const refFa = useRef(null);
|
||||
const refBox = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('click', clickMe , false);
|
||||
}, [])
|
||||
|
||||
const clickMe = ({ target }) => {
|
||||
// 查找父组件
|
||||
const faComponent = findDOMNode(refFa.current);
|
||||
const boxComponent = findDOMNode(refBox.current);
|
||||
|
||||
if (faComponent && boxComponent) {
|
||||
const isChild = faComponent.contains(target);
|
||||
const isBox = boxComponent.contains(target);
|
||||
if(!isChild && !isBox){
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
setShowValue(branch);
|
||||
},[branch])
|
||||
|
||||
function ChangeB(params) {
|
||||
setVisible(false);
|
||||
changeBranch(params);
|
||||
}
|
||||
|
||||
const menu = (
|
||||
<SelectOverlay
|
||||
changeBranch={changeBranch}
|
||||
tagflag={tagflag}
|
||||
projectsId={projectsId}
|
||||
owner={owner}
|
||||
branchList={branchList}
|
||||
<div ref={refFa}>
|
||||
<SelectOverlay
|
||||
changeBranch={ChangeB}
|
||||
tagflag={tagflag}
|
||||
projectsId={projectsId}
|
||||
owner={owner}
|
||||
branchList={branchList}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
return(
|
||||
<Dropdown placement='bottomLeft' overlay={menu} overlayClassName="branch-tagBox-list" trigger={['click']} >
|
||||
<div className="branch-tagBox">
|
||||
<Dropdown placement='bottomLeft' visible={visible} overlay={menu} overlayClassName="branch-tagBox-list" trigger={['click']} >
|
||||
<div className="branch-tagBox" ref={refBox} onClick={()=>setVisible(visible ? false : true)}>
|
||||
{/* {nav === 0 ?"分支":"标签"} */}
|
||||
<span className="color-grey-9 mr3 ml8"><i className="iconfont icon-fenzhi2 font-18"></i></span>
|
||||
<span className="ant-dropdown-link task-hide" style={{fontWeight:"500"}}>
|
||||
<span className="ant-dropdown-link task-hide" style={{fontWeight:"500",minWidth:"45px",maxWidth:"270px"}}>
|
||||
{showValue}
|
||||
</span>
|
||||
<i className="showtag iconfont icon-sanjiaoxing-down font-15 color-grey-9 mr5 ml5 mt1" />
|
||||
|
|
|
@ -55,7 +55,7 @@ function SelectOverlay({ changeBranch , tagflag , branchList , projectsId , owne
|
|||
<div className="padding15" style={{paddingBottom:"0px"}}>
|
||||
<Input
|
||||
prefix={<i className="iconfont icon-sousuo_icon1 font-14"></i>}
|
||||
placeholder="请输入分支或标签名称搜索"
|
||||
placeholder={`请输入分支${tagflag ? "或标签" :""}名称搜索`}
|
||||
autocomplete="off" className="OptionsInput"
|
||||
value={inputValue}
|
||||
onChange={changeInputValue}
|
||||
|
|
|
@ -87,6 +87,13 @@
|
|||
line-height: 30px;
|
||||
padding:0px 5px;
|
||||
margin-left: 20px!important;
|
||||
&.ant-menu-item-selected{
|
||||
border-color:#466aff!important;
|
||||
color:#466aff!important;
|
||||
}
|
||||
&.ant-menu-item-active{
|
||||
border-color:transparent ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +116,7 @@
|
|||
color: #333;
|
||||
}
|
||||
&.ant-menu-item-selected{
|
||||
border-color:#1890ff!important;
|
||||
border-color:#466aff!important;
|
||||
}
|
||||
&.ant-menu-item-active{
|
||||
border-color:transparent ;
|
||||
|
|
|
@ -2,8 +2,7 @@ import React from 'react';
|
|||
import { AlignTop } from '../Component/layout';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
function Releases({owner,projectsId,releaseVersions , baseOperate , projectType}){
|
||||
|
||||
function Releases({ owner, projectsId, releaseVersions, distribution }) {
|
||||
return(
|
||||
<div>
|
||||
<Link to={`/${owner}/${projectsId}/releases`} className="font-16 color-ooo hoverA">
|
||||
|
@ -16,8 +15,9 @@ function Releases({owner,projectsId,releaseVersions , baseOperate , projectType}
|
|||
return(
|
||||
key === 0 &&<AlignTop className="mt10">
|
||||
<div>
|
||||
<p className="font-16 color-grey-6">
|
||||
<Link to={`/${owner}/${projectsId}/releases`}>{item.name}</Link>
|
||||
<p className="font-16 color-grey-6" style={{display:'flex',alignItems:'center'}}>
|
||||
{/* 如果是点击最新则发行版列表页只展示最新的一个 */}
|
||||
<Link to={{pathname:`/${owner}/${projectsId}/releases`,query:{turnFromNew:true}}} style={{maxWidth:'200px',overflow: 'hidden',whiteSpace: 'nowrap',textOverflow:'ellipsis'}}>{item.name}</Link>
|
||||
<span className="font-12 laterest ml5">最新</span>
|
||||
</p>
|
||||
<p className="color-grey-3 font-12">{item.created_at}</p>
|
||||
|
@ -27,7 +27,8 @@ function Releases({owner,projectsId,releaseVersions , baseOperate , projectType}
|
|||
})
|
||||
:
|
||||
<div className="mt8">
|
||||
您暂未发布任何版本{baseOperate && projectType !==2 && <Link className="color-blue ml20" to={`/${owner}/${projectsId}/releases/new`}>创建新版本</Link>}
|
||||
您暂未发布任何版本
|
||||
{distribution && <Link className="color-blue ml20" to={{pathname:`/${owner}/${projectsId}/releases/new`,state:{stable:true}}}>创建新版本</Link>}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import { Link } from 'react-router-dom';
|
|||
export default ({ url , name , column , id , login })=>{
|
||||
const Img = styled.span`
|
||||
display:flex;
|
||||
font-weight: bold;
|
||||
${column && "flex-direction: column;text-align:center;"}
|
||||
align-items: center;
|
||||
& img{
|
||||
|
|
|
@ -51,7 +51,7 @@ function PipelineName({visible,onCancel,onOk,value ,branchList}){
|
|||
})
|
||||
}
|
||||
</Select>
|
||||
<Select mode="multiple" allowClear value={eventValue} dropdownClassName="chooseCon" style={{width:"180px",marginLeft:"10px"}} onChange={(e)=>{console.log(e);setEventValue(e)}}>
|
||||
<Select mode="multiple" allowClear value={eventValue} dropdownClassName="chooseCon" style={{width:"180px",marginLeft:"10px"}} onChange={(e)=>{setEventValue(e)}}>
|
||||
{
|
||||
EVENT.map((item,key)=>{
|
||||
return(
|
||||
|
|
|
@ -24,7 +24,6 @@ function onLayout(term, el) {
|
|||
entry.target.offsetHeight,
|
||||
term,
|
||||
);
|
||||
console.log('cols, rows', cols, rows);
|
||||
term.resize(cols, rows);
|
||||
mediator.publish('ssh-xterm-resize', {
|
||||
columns: cols,
|
||||
|
@ -139,12 +138,10 @@ export default ({ sshConfigData, sid }) => {
|
|||
}, 1000);
|
||||
}
|
||||
isFirstConnected.current = true;
|
||||
console.log('event:', event);
|
||||
|
||||
const data = Base64.decode(event.data.toString());
|
||||
let w = term._core._renderService.dimensions.actualCellWidth || 9.5;
|
||||
|
||||
console.log('data:', data, w, term);
|
||||
term.write(data);
|
||||
};
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ function Footer(){
|
|||
|
||||
return(
|
||||
<div>
|
||||
<div style={{height:"497px"}}></div>
|
||||
<div style={{height:"543px"}}></div>
|
||||
<div className="newFooter edu-txt-center">
|
||||
{value && showhtml(value)}
|
||||
{/* <div className="footerInfos">
|
||||
|
|
|
@ -120,7 +120,6 @@ class NewHeader extends Component {
|
|||
})
|
||||
};
|
||||
HideAddcoursestypess = (i) => {
|
||||
console.log("调用了");
|
||||
this.setState({
|
||||
Addcoursestypes: false,
|
||||
mydisplay: true,
|
||||
|
@ -269,7 +268,7 @@ class NewHeader extends Component {
|
|||
)
|
||||
})
|
||||
}
|
||||
<li><Link to={`/settings/profile`}>设置</Link></li>
|
||||
{/* <li><Link to={`/settings/profile`}>设置</Link></li> */}
|
||||
<Menu.Item><a onClick={() => this.educoderloginysl()}>退出</a></Menu.Item>
|
||||
</Menu>
|
||||
)
|
||||
|
|
|
@ -67,6 +67,7 @@ function CoderDepot(props){
|
|||
const [ editReadme , setEditReadme ] = useState(false);
|
||||
const [ pullsFlag , setPullsFlag ] = useState(true);
|
||||
const [ issuesFlag , setIssuesFlag ] = useState(true);
|
||||
const [ releaseVersions , setReleaseVersions] = useState(undefined);
|
||||
|
||||
const owner = props.match.params.owner;
|
||||
const projectsId = props.match.params.projectsId;
|
||||
|
@ -74,7 +75,8 @@ function CoderDepot(props){
|
|||
branchName = returnbar(branchName);
|
||||
const details = props.projectDetail;
|
||||
let pathname = props.history.location.pathname;
|
||||
|
||||
//distribution:判断此用户是否可以创建发行版
|
||||
const distribution = details && details.type != 2 && (details.permission === "Admin" || details.permission === "Owner" || details.permission === "Manager");
|
||||
const { bannerList } = props;
|
||||
|
||||
useEffect(()=>{
|
||||
|
@ -119,14 +121,47 @@ function CoderDepot(props){
|
|||
setTreeValue(url);
|
||||
getFileInfo(url,branchName);
|
||||
setType("file");
|
||||
// getReadmeInfo(url,branchName);
|
||||
// setReadme(undefined);
|
||||
}else{
|
||||
setTreeValue(undefined);
|
||||
getDirInfo(branchName || defaultBranch);
|
||||
setType("dir");
|
||||
// getReadmeInfo('', branchName || defaultBranch);
|
||||
}
|
||||
}
|
||||
},[projectsId,owner,pathname,defaultBranch])
|
||||
|
||||
useEffect(()=>{
|
||||
axios.get(`/${owner}/${projectsId}/releases.json`).then((result)=>{
|
||||
if(result && result.data){
|
||||
const release = {
|
||||
"list":result.data.releases,
|
||||
"total_count":result.data.releases.length
|
||||
}
|
||||
setReleaseVersions(release);
|
||||
}
|
||||
})
|
||||
},[])
|
||||
|
||||
// 获取readme信息
|
||||
function getReadmeInfo(path, ref) {
|
||||
axios.get(`/${owner}/${projectsId}/readme.json`, {
|
||||
params:{
|
||||
owner: owner,
|
||||
repo: projectsId,
|
||||
filepath:path,
|
||||
ref:ref || branchName
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result) {
|
||||
setReadme(result.data);
|
||||
} else {
|
||||
setReadme(undefined);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 获取主目录列表
|
||||
function getDirInfo(branch){
|
||||
setIsSpin(true);
|
||||
|
@ -146,9 +181,10 @@ function CoderDepot(props){
|
|||
setLastCommitAuthor(c && c.committer);
|
||||
setMainFlag(true);
|
||||
setReadOnly(true);
|
||||
setReadme(result.data.readme);
|
||||
// setReadme(result.data.readme);
|
||||
setEditReadme(false);
|
||||
setHide(true);
|
||||
getReadmeInfo('', branchName || defaultBranch);
|
||||
}
|
||||
setTimeout(function(){setIsSpin(false);},500);
|
||||
}).catch(error=>{setIsSpin(false);})
|
||||
|
@ -181,15 +217,18 @@ function CoderDepot(props){
|
|||
setDirInfo(undefined);
|
||||
setFileInfo(en);
|
||||
setType(en.type);
|
||||
setReadme(undefined);
|
||||
}else{
|
||||
setFileInfo(undefined);
|
||||
setDirInfo(en);
|
||||
setType("dir");
|
||||
getReadmeInfo(path, branchName || defaultBranch);
|
||||
}
|
||||
let c = result.data.last_commit
|
||||
setLastCommit(c && c.commit);
|
||||
setLastCommitAuthor(c && c.committer);
|
||||
setMainFlag(false);
|
||||
setReadOnly(true);
|
||||
setReadOnly(!editReadme);
|
||||
setHide(true);
|
||||
}
|
||||
|
@ -301,6 +340,7 @@ function CoderDepot(props){
|
|||
const mdFlag = n && n.substring(n.length-3,n.length) === ".md";
|
||||
|
||||
const { current_user } = props;
|
||||
const baseOper = projectDetail && projectDetail.permission;
|
||||
const baseOperate = projectDetail && projectDetail.permission && projectDetail.permission !=="Reporter";
|
||||
const fileOperate = type === "dir" && projectDetail && projectDetail.type !== 2 && ((projectDetail.permission && projectDetail.permission !=="Reporter") || (current_user && current_user.admin));
|
||||
|
||||
|
@ -348,34 +388,47 @@ function CoderDepot(props){
|
|||
branchList={projectDetail && projectDetail.branches && projectDetail.branches.list}
|
||||
></SelectBranch>
|
||||
:
|
||||
<span>分支:<span className="color-grey-6">{branchName || defaultBranch}</span></span>
|
||||
<span>分支:<span className="color-grey-6">{branchName || defaultBranch}</span></span>
|
||||
}
|
||||
</div>
|
||||
<AlignCenter className="mr20">
|
||||
<Link to={`/${owner}/${projectsId}/branches`} className="iconBtn">
|
||||
<i className="iconfont icon-master_icon font-16"></i>
|
||||
<span>分支</span>
|
||||
<span>{projectDetail && projectDetail.branches && projectDetail.branches.total_count}</span>
|
||||
</Link>
|
||||
</AlignCenter>
|
||||
<AlignCenter className="mr20">
|
||||
<Link to={`/${owner}/${projectsId}/tags`} className="iconBtn">
|
||||
<i className="iconfont icon-biaoqianicon font-16"></i>
|
||||
<span>标签</span>
|
||||
<span>{projectDetail && projectDetail.tags && projectDetail.tags.total_count}</span>
|
||||
</Link>
|
||||
</AlignCenter>
|
||||
{
|
||||
treeValuePath && treeValuePath.length > 0 ?
|
||||
<Path
|
||||
identifier={projectDetail && projectDetail.identifier}
|
||||
treeValuePath={treeValuePath}
|
||||
returnUlr={returnUlr}
|
||||
returnMain={returnMain}
|
||||
getPathUrl={getPathUrl}
|
||||
/>
|
||||
:
|
||||
<div>
|
||||
<AlignCenter className="mr20">
|
||||
<Link to={`/${owner}/${projectsId}/branches`} className="iconBtn">
|
||||
<i className="iconfont icon-master_icon font-16"></i>
|
||||
<span>分支</span>
|
||||
<span>{projectDetail && projectDetail.branches && projectDetail.branches.total_count}</span>
|
||||
</Link>
|
||||
</AlignCenter>
|
||||
<AlignCenter className="mr20">
|
||||
<Link to={`/${owner}/${projectsId}/tags`} className="iconBtn">
|
||||
<i className="iconfont icon-biaoqianicon font-16"></i>
|
||||
<span>标签</span>
|
||||
<span>{projectDetail && projectDetail.tags && projectDetail.tags.total_count}</span>
|
||||
</Link>
|
||||
</AlignCenter>
|
||||
</div>
|
||||
}
|
||||
</AlignCenter>
|
||||
<AlignCenter className="depotBtn">
|
||||
{
|
||||
baseOperate && ((projectDetail.type !== 2 && pullsFlag) || issuesFlag )&&
|
||||
((baseOperate && projectDetail.type !== 2 && pullsFlag) || (baseOper && issuesFlag)) &&
|
||||
<div className="addOptionBtn">
|
||||
{
|
||||
projectDetail.type !== 2 && pullsFlag &&
|
||||
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/pulls/new`)} >+ 合并请求</CheckProfile>
|
||||
baseOperate && projectDetail.type !== 2 && pullsFlag &&
|
||||
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/pulls/new/${branchName || defaultBranch}`)} >+ 合并请求</CheckProfile>
|
||||
}
|
||||
{
|
||||
issuesFlag &&
|
||||
baseOper && issuesFlag &&
|
||||
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/issues/new`)} >+ 易修</CheckProfile>
|
||||
}
|
||||
</div>
|
||||
|
@ -403,8 +456,8 @@ function CoderDepot(props){
|
|||
lastCommit &&
|
||||
<div className="listtablehead">
|
||||
<User url={getImageUrl(`/${lastCommitAuthor && lastCommitAuthor.image_url}`)} name={lastCommitAuthor && lastCommitAuthor.name} id={lastCommitAuthor && lastCommitAuthor.id} login={lastCommitAuthor && lastCommitAuthor.login}/>
|
||||
<div onClick={()=>props.history.push(`/${owner}/${projectsId}/commits/${truncateCommitId(lastCommit.sha)}`)} className={hideBtn && hide ? "ellipsistxt hidetxt" :"ellipsistxt"}>
|
||||
<pre id="ptxt">{lastCommit.message}</pre>
|
||||
<div className={hideBtn && hide ? "ellipsistxt hidetxt" :"ellipsistxt"}>
|
||||
<pre id="ptxt"><Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(lastCommit.sha)}`}>{lastCommit.message}</Link></pre>
|
||||
</div>
|
||||
{ hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> }
|
||||
|
||||
|
@ -418,16 +471,6 @@ function CoderDepot(props){
|
|||
</div>
|
||||
}
|
||||
<ul className="listtablebody">
|
||||
{
|
||||
treeValuePath && treeValuePath.length > 0 &&
|
||||
<Path
|
||||
identifier={projectDetail && projectDetail.identifier}
|
||||
treeValuePath={treeValuePath}
|
||||
returnUlr={returnUlr}
|
||||
returnMain={returnMain}
|
||||
getPathUrl={getPathUrl}
|
||||
/>
|
||||
}
|
||||
{
|
||||
dirInfo && dirInfo.length > 0 &&
|
||||
dirInfo.map((item,key)=>{
|
||||
|
@ -461,11 +504,11 @@ function CoderDepot(props){
|
|||
(dirInfo && dirInfo.length === 0) && !fileInfo ? <Nodata _html="暂未发现文件"/> :""
|
||||
}
|
||||
{/* readme文件显示(显示文件详情时不显示readme文件) */}
|
||||
{ dirInfo && (readme && readme.content) ? <ReadMe ChangeFile={ChangeFile} readme={readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
|
||||
{ (readme && readme.content) ? <ReadMe ChangeFile={ChangeFile} readme={readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
|
||||
</div>
|
||||
</LongWidth>
|
||||
{
|
||||
!fileInfo &&
|
||||
(!(treeValuePath && treeValuePath.length > 0) && !fileInfo) &&
|
||||
<ShortWidth>
|
||||
<Gap style={{paddingLeft:"30px"}}>
|
||||
<div className="panelmenu">
|
||||
|
@ -516,16 +559,15 @@ function CoderDepot(props){
|
|||
}
|
||||
{/* 发布 */}
|
||||
{
|
||||
projectDetail && projectDetail.release_versions &&
|
||||
releaseVersions &&
|
||||
<React.Fragment>
|
||||
<Divider />
|
||||
<Releases
|
||||
owner={owner}
|
||||
projectsId={projectsId}
|
||||
releaseVersions={projectDetail.release_versions}
|
||||
releaseVersions={releaseVersions}
|
||||
history={props.history}
|
||||
baseOperate={baseOperate}
|
||||
projectType={projectDetail.type}
|
||||
distribution={distribution}
|
||||
/>
|
||||
</React.Fragment>
|
||||
}
|
||||
|
@ -535,7 +577,7 @@ function CoderDepot(props){
|
|||
<Contributors contributors={projectDetail.contributors} owner={owner} projectsId={projectsId} />
|
||||
}
|
||||
{/* 语言 */}
|
||||
{ projectDetail && projectDetail.languages &&
|
||||
{ projectDetail && projectDetail.languages &&
|
||||
<React.Fragment>
|
||||
<Divider />
|
||||
<LanguagePower languages={projectDetail.languages}/>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { result } from 'lodash';
|
||||
import React from 'react';
|
||||
|
||||
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
import React , { useState, useEffect } from 'react';
|
||||
import { Link } from "react-router-dom";
|
||||
import { Dropdown , Menu , Icon , Tooltip , Spin } from 'antd';
|
||||
import { truncateCommitId } from '../common/util';
|
||||
import { getBranch } from '../GetData/getData';
|
||||
import Nodata from '../Nodata';
|
||||
import './list.scss';
|
||||
|
||||
function turnbar(str){
|
||||
if(str && str.length>0 && str.indexOf("/")>-1){
|
||||
return str.replaceAll('/','%2F');
|
||||
}
|
||||
return str;
|
||||
}
|
||||
export default ((props)=>{
|
||||
const [ data , setData ] =useState(undefined);
|
||||
const [ isSpin , setIsSpin ] =useState(true);
|
||||
|
||||
const { projectsId , owner } = props.match.params;
|
||||
const { isManager , isDeveloper , projectDetail } = props;
|
||||
useEffect(()=>{
|
||||
getBranchs(projectsId, owner);
|
||||
},[projectsId])
|
||||
|
||||
async function getBranchs(id,owner){
|
||||
let result = await getBranch(id,owner);
|
||||
setData(result);
|
||||
setIsSpin(false);
|
||||
}
|
||||
|
||||
const list =()=>{
|
||||
if(data && data.length>0){
|
||||
return(
|
||||
<React.Fragment>
|
||||
<ul className="branchUl">
|
||||
{
|
||||
data.map((item,key)=>{
|
||||
return(
|
||||
<li key={key}>
|
||||
<div>
|
||||
<Link to={`/${owner}/${projectsId}/tree/${turnbar(item.name)}`} className="color-blue font-15" style={{"maxWidth":"100px"}}>{item.name}</Link>
|
||||
<p className="f-wrap-alignCenter mt15">
|
||||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.last_commit.sha}`)}`} className="mr5 commitKey" style={{marginLeft:0}}>{item.last_commit && truncateCommitId(item.last_commit.sha)}</Link>
|
||||
<span className="color-grey-3 hide-1 messages leftPoint">{item.last_commit && item.last_commit.message}</span>
|
||||
<span className="color-grey-8 ml30">最后更新于{item.last_commit && item.last_commit.time_from_now}</span>
|
||||
</p>
|
||||
</div>
|
||||
<span>
|
||||
{
|
||||
(isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) &&
|
||||
<Link to={`/${owner}/${projectsId}/pulls/new/${item.name}`} className="mr20 color-blue mr30">创建合并请求</Link>
|
||||
}
|
||||
<Dropdown overlay={menu(item.zip_url,item.tar_url)} trigger={['click']} placement="bottomRight" className="color-green-file">
|
||||
<a className="ant-dropdown-link">
|
||||
<Tooltip title={`下载分支${item.name}`}><Icon type="cloud-download" className="font-18"/></Tooltip>
|
||||
</a>
|
||||
</Dropdown>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</React.Fragment>
|
||||
)
|
||||
}else if(data && data.length === 0){
|
||||
return ( <Nodata _html="暂无数据"/>)
|
||||
}
|
||||
}
|
||||
const menu =(zip_url,tar_url)=> (
|
||||
<Menu>
|
||||
<Menu.Item key={'0'}><a href={zip_url}>ZIP</a></Menu.Item>
|
||||
<Menu.Item key={'1'}><a href={tar_url}>TAR.GZ</a></Menu.Item>
|
||||
</Menu>
|
||||
)
|
||||
|
||||
return(
|
||||
<React.Fragment>
|
||||
<div className="main">
|
||||
<Spin spinning={isSpin}>
|
||||
<div className="branchTable">
|
||||
<p className="branchTitle bor-bottom-greyE">分支列表</p>
|
||||
<div style={{minHeight:"400px"}}>{list()}</div>
|
||||
</div>
|
||||
</Spin>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
|
|
@ -1,13 +1,18 @@
|
|||
import React , { Component } from 'react';
|
||||
import { Spin , Pagination } from 'antd';
|
||||
import { Spin , Pagination, Timeline } from 'antd';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import { truncateCommitId } from '../common/util';
|
||||
import { truncateCommitId ,timeFormat } from '../common/util';
|
||||
import { AlignTop } from '../Component/layout';
|
||||
import SelectBranch from '../Branch/Select';
|
||||
import Nodata from '../Nodata';
|
||||
|
||||
import User from '../Component/User'
|
||||
import Tree from './img/tree.png';
|
||||
import axios from 'axios';
|
||||
import {Link} from "react-router-dom";
|
||||
import CopyTool from '../Component/CopyTool';
|
||||
|
||||
import './tree/Index.scss'
|
||||
|
||||
function returnbar(str){
|
||||
if(str && str.length>0 && str.indexOf("%2F")>-1){
|
||||
|
@ -15,14 +20,16 @@ function returnbar(str){
|
|||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
//代码库--提交页面
|
||||
class CoderRootCommit extends Component{
|
||||
constructor(props){
|
||||
super(props)
|
||||
super(props);
|
||||
this.state={
|
||||
commitDatas:undefined,
|
||||
dataCount:undefined,
|
||||
limit:20,
|
||||
page:1,
|
||||
limit:10,
|
||||
page: 1,
|
||||
isSpining:false,
|
||||
branchList:undefined
|
||||
}
|
||||
|
@ -50,20 +57,34 @@ class CoderRootCommit extends Component{
|
|||
this.Init();
|
||||
}
|
||||
}
|
||||
|
||||
UrlParamHash(url){
|
||||
const params = {};
|
||||
let h;
|
||||
let hash = url.slice(url.indexOf('?')+1).split('&');
|
||||
for(let i = 0; i<hash.length;i++){
|
||||
h = hash[i].split('=');
|
||||
params[h[0]] = h[1];
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
Init =()=>{
|
||||
const { branchName } = this.props.match.params;
|
||||
const { page , limit } = this.state;
|
||||
const { limit } = this.state;
|
||||
const {search} = this.props.location;
|
||||
const realPage = (search && this.UrlParamHash(search).page) ? parseInt(this.UrlParamHash(search).page) : 1;
|
||||
this.setState({
|
||||
isSpining:true
|
||||
isSpining:true,
|
||||
page:realPage
|
||||
})
|
||||
this.getCommitList( branchName , page , limit );
|
||||
this.getCommitList( branchName , realPage , limit );
|
||||
}
|
||||
|
||||
getCommitList=(branch , page , limit)=>{
|
||||
this.setState({
|
||||
isSpining:true
|
||||
})
|
||||
console.log(returnbar(branch));
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
const url = `/${owner}/${projectsId}/commits.json`;
|
||||
axios.get(url,{
|
||||
|
@ -86,7 +107,8 @@ class CoderRootCommit extends Component{
|
|||
image_url:item.author && item.author.image_url,
|
||||
sha:item.sha,
|
||||
time_from_now:item.time_from_now,
|
||||
message:item.message
|
||||
message:item.message,
|
||||
timestamp:item.timestamp
|
||||
})
|
||||
})
|
||||
this.setState({
|
||||
|
@ -105,10 +127,9 @@ class CoderRootCommit extends Component{
|
|||
}
|
||||
|
||||
ChangePage=(page)=>{
|
||||
const { branchName } = this.props.match.params;
|
||||
const { limit } = this.state;
|
||||
this.getCommitList(branchName , page , limit);
|
||||
this.props.history.push({pathname: this.props.history.location.pathname,search: `page=${page}`})
|
||||
}
|
||||
|
||||
render(){
|
||||
const { commitDatas , dataCount , limit , page , isSpining , branchList } = this.state;
|
||||
const { projectDetail, commit_class , defaultBranch } = this.props;
|
||||
|
@ -129,46 +150,50 @@ class CoderRootCommit extends Component{
|
|||
></SelectBranch>
|
||||
</div>
|
||||
<Spin spinning={isSpining}>
|
||||
<div className="commonBox">
|
||||
<div className="commonBox-title">
|
||||
<div className="f-wrap-between" style={{alignItems:"center"}}>
|
||||
<span className="font-16">{dataCount}次提交代码({branch})</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="commitList">
|
||||
{
|
||||
commitDatas && commitDatas.length > 0 && commitDatas.map((item,k)=>{
|
||||
return(
|
||||
<div key={k}>
|
||||
<AlignTop>
|
||||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="commitKey" style={{marginLeft:0,marginTop:"3px"}}>{truncateCommitId(`${item.sha}`)}</Link>
|
||||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="commitDesc">{item.message}</Link>
|
||||
</AlignTop>
|
||||
<p className="f-wrap-alignCenter mt15">
|
||||
{
|
||||
item.id ?
|
||||
<Link to={`/${item.login}`} className="show-user-link">
|
||||
{item.image_url?<img src={getImageUrl(`/${item.image_url}`)} alt="" width="28px" height="28px" className="mr15 radius"/>:""}
|
||||
<label className="font-14 color-grey-6" style={{verticalAlign:'middle'}}>{item.name ?`${item.name}:`:""}提交于 {item.time_from_now}</label>
|
||||
</Link>:
|
||||
<span className="show-user-link">
|
||||
{item.image_url?<img src={getImageUrl(`/${item.image_url}`)} alt="" width="28px" height="28px" className="mr15 radius"/>:""}
|
||||
<label className="font-14 color-grey-6" style={{verticalAlign:'middle'}}>{item.name ?`${item.name}:`:""}提交于 {item.time_from_now}</label>
|
||||
</span>
|
||||
}
|
||||
|
||||
</p>
|
||||
<Timeline className="commitList">
|
||||
{
|
||||
commitDatas && commitDatas.length > 0 && commitDatas.map((item,k)=>{
|
||||
return(
|
||||
<Timeline.Item key={k} dot={page ===1 && k===0 ?<span className="new-conmmit">最新</span>:<i className="iconfont icon-a-yuanquan2x"></i>}>
|
||||
<div className="commitList-item f-wrap-between">
|
||||
<div>
|
||||
<AlignTop>
|
||||
<div className="commitDesc"><Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="font-14 color-grey-3 font-bd">{item.message}</Link></div>
|
||||
</AlignTop>
|
||||
<p className="f-wrap-alignCenter mt15 pb5">
|
||||
<User
|
||||
id={item.id}
|
||||
url={(item.image_url && getImageUrl(`/${item.image_url}`)) || "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"}
|
||||
name={item.name}
|
||||
login={item.login}
|
||||
/>
|
||||
{item.timestamp && <label className="font-14 color-grey-3 ml3">提交于 {timeFormat(item.timestamp)}</label>}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<div className="treecopy">
|
||||
<div>
|
||||
<span className="treecopy-cont shadow">
|
||||
<img src={Tree} alt="sha" width={"16px"}/>
|
||||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`}>{truncateCommitId(`${item.sha}`)}</Link>
|
||||
<input type="text" id={`value${k}`} value={`${truncateCommitId(`${item.sha}`)}`}/>
|
||||
</span>
|
||||
<CopyTool beforeText="复制commit id" afterText="复制成功" inputId={`value${k}`}/>
|
||||
</div>
|
||||
<button className="btn-83" onClick={()=>{window.location.href=`/${owner}/${projectsId}/tree/${truncateCommitId(item.sha)}`}}>浏览文件</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
{commitDatas && commitDatas.length === 0 && <Nodata _html="暂无数据"/>}
|
||||
</div>
|
||||
</div>
|
||||
</Timeline.Item>
|
||||
)
|
||||
})
|
||||
}
|
||||
{commitDatas && commitDatas.length === 0 && <Nodata _html="暂无数据"/>}
|
||||
</Timeline>
|
||||
{
|
||||
dataCount > limit ?
|
||||
<div className="edu-txt-center pt30 mb30">
|
||||
<Pagination simple defaultCurrent={page} total={dataCount} pageSize={limit} onChange={this.ChangePage}></Pagination>
|
||||
<Pagination simple current={page} total={dataCount} pageSize={limit} onChange={this.ChangePage}></Pagination>
|
||||
</div>
|
||||
:""
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import React, { Component } from "react";
|
||||
import { Popconfirm , Select } from "antd";
|
||||
import { Popconfirm , Select , Dropdown , Spin , Anchor } from "antd";
|
||||
import "./list.scss";
|
||||
import axios from "axios";
|
||||
import Meditor from "../Newfile/m_editor";
|
||||
import RenderHtml from "../../components/render-html";
|
||||
import ReadmeCatelogue from "./sub/ReadmeCatelogue";
|
||||
|
||||
const $ = window.$;
|
||||
function bytesToSize(bytes) {
|
||||
if (bytes === 0) return "0 B";
|
||||
let k = 1024,
|
||||
|
@ -19,7 +21,8 @@ class CoderRootFileDetail extends Component {
|
|||
value: undefined,
|
||||
language: undefined,
|
||||
languages: undefined,
|
||||
description: props.detail.content
|
||||
description: props.detail.content,
|
||||
menuList:undefined
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -169,6 +172,31 @@ class CoderRootFileDetail extends Component {
|
|||
});
|
||||
};
|
||||
|
||||
renderMenulist=()=>{
|
||||
const { description } = this.state;
|
||||
if(description){
|
||||
const items = $.map($("#files-md").find("h1,h2,h3,h4,h5,h6"), function (el, _) {
|
||||
const anchor = el.id;
|
||||
const level = el.tagName.replace("H", "");
|
||||
const href = `#${anchor}`;
|
||||
return { href:`${href}`,text:el.textContent , level:level }
|
||||
});
|
||||
return items;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
menu=()=>{
|
||||
const menuList = this.renderMenulist();
|
||||
if(menuList && menuList.length > 0){
|
||||
return(
|
||||
<ReadmeCatelogue menuList={menuList} hash={this.props.history.location.hash}/>
|
||||
)
|
||||
}else{
|
||||
return <Spin />
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
readOnly,
|
||||
|
@ -186,79 +214,88 @@ class CoderRootFileDetail extends Component {
|
|||
const Option = Select.Option;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="grid-item branchTitle">
|
||||
<div className="grid-item">
|
||||
<span className="ml20 color-grey-6 font-16">
|
||||
<Anchor className="griditemAnchor" offsetTop={70} targetOffset={160}>
|
||||
<div className="griditemCate">
|
||||
{
|
||||
md && readOnly &&
|
||||
<Dropdown overlay={this.menu()} trigger={['hover']} overlayClassName="menuslist">
|
||||
<span className="catelogue mr20">
|
||||
<i className="iconfont icon-muluicon font-12 mr5"></i>
|
||||
<span>目录</span>
|
||||
</span>
|
||||
</Dropdown>
|
||||
}
|
||||
<span className="color-grey-6 font-16">
|
||||
{bytesToSize(detail && detail.size)}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-right">
|
||||
{flag && platform && (
|
||||
<div>
|
||||
{readOnly ? (
|
||||
<span>
|
||||
{
|
||||
!detail.direct_download?
|
||||
<span>
|
||||
<a onClick={() => this.DownLoadFile(detail.download_url)} className="ml20">
|
||||
<i className="iconfont icon-xiazai1 font-15 color-grey-6"></i>
|
||||
</a>
|
||||
{
|
||||
type !==2 &&
|
||||
<a onClick={() => this.EditFile(false)} className="ml20">
|
||||
<i className="iconfont icon-bianji1 font-15 color-grey-6"></i>
|
||||
{flag && platform && (
|
||||
<div>
|
||||
{readOnly ? (
|
||||
<span>
|
||||
{
|
||||
!detail.direct_download?
|
||||
<span>
|
||||
<a onClick={() => this.DownLoadFile(detail.download_url)} className="ml20">
|
||||
<i className="iconfont icon-xiazai1 font-15 color-grey-6"></i>
|
||||
</a>
|
||||
}
|
||||
</span>:""
|
||||
}
|
||||
</span>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<Select
|
||||
showSearch={true}
|
||||
placeholder={"请选择文本语言"}
|
||||
style={{ width: 200 }}
|
||||
value={language}
|
||||
onChange={this.select_language}
|
||||
>
|
||||
<Option value={undefined}>请选择文本语言</Option>
|
||||
{languages &&
|
||||
languages.map((item, key) => {
|
||||
return (
|
||||
<Option value={item} key={key}>
|
||||
{item}
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
<button
|
||||
type="button"
|
||||
className="ant-btn ant-btn-sm ml20"
|
||||
onClick={() => this.EditFile(true)}
|
||||
>
|
||||
<span>取 消</span>
|
||||
</button>
|
||||
</React.Fragment>
|
||||
)}
|
||||
{
|
||||
type !==2 &&
|
||||
<Popconfirm
|
||||
title="确认删除这个文件?"
|
||||
className="ml20"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
onConfirm={this.deleteFile}
|
||||
>
|
||||
<a>
|
||||
<i className="iconfont icon-shanchu font-15 color-grey-6"></i>
|
||||
</a>
|
||||
</Popconfirm>
|
||||
}
|
||||
|
||||
</div>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
{
|
||||
type !==2 &&
|
||||
<a onClick={() => this.EditFile(false)} className="ml20">
|
||||
<i className="iconfont icon-bianji1 font-15 color-grey-6"></i>
|
||||
</a>
|
||||
}
|
||||
</span>:""
|
||||
}
|
||||
</span>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<Select
|
||||
showSearch={true}
|
||||
placeholder={"请选择文本语言"}
|
||||
style={{ width: 200 }}
|
||||
value={language}
|
||||
onChange={this.select_language}
|
||||
>
|
||||
<Option value={undefined}>请选择文本语言</Option>
|
||||
{languages &&
|
||||
languages.map((item, key) => {
|
||||
return (
|
||||
<Option value={item} key={key}>
|
||||
{item}
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
<button
|
||||
type="button"
|
||||
className="ant-btn ant-btn-sm ml20"
|
||||
onClick={() => this.EditFile(true)}
|
||||
>
|
||||
<span>取 消</span>
|
||||
</button>
|
||||
</React.Fragment>
|
||||
)}
|
||||
{
|
||||
type !==2 &&
|
||||
<Popconfirm
|
||||
title="确认删除这个文件?"
|
||||
className="ml20"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
onConfirm={this.deleteFile}
|
||||
>
|
||||
<a>
|
||||
<i className="iconfont icon-shanchu font-15 color-grey-6"></i>
|
||||
</a>
|
||||
</Popconfirm>
|
||||
}
|
||||
|
||||
</div>
|
||||
)}
|
||||
</p>
|
||||
</Anchor>
|
||||
<div>
|
||||
{detail.image_type ? (
|
||||
<div className="edu-txt-center pt20 pb20">
|
||||
|
@ -272,7 +309,7 @@ class CoderRootFileDetail extends Component {
|
|||
</div>
|
||||
) : (
|
||||
md && readOnly ?
|
||||
<div className="files-md">
|
||||
<div className="files-md" id="files-md">
|
||||
<RenderHtml className="file-md imageLayerParent" value={description} url={this.props.history.location}/>
|
||||
</div>
|
||||
:
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import React , { Component } from 'react';
|
||||
import { Route , Switch } from 'react-router-dom';
|
||||
import Top from './DetailTop';
|
||||
// import Top from './DetailTop';
|
||||
import Loadable from 'react-loadable';
|
||||
import Loading from '../../Loading';
|
||||
import axios from 'axios';
|
||||
import './Index.scss';
|
||||
|
||||
const FileNew = Loadable({
|
||||
loader: () => import('../Newfile/Index'),
|
||||
|
@ -18,25 +19,25 @@ const CoderRootCommit = Loadable({
|
|||
loading: Loading,
|
||||
})
|
||||
const CoderRootBranch = Loadable({
|
||||
loader: () => import('./CoderRootBranch'),
|
||||
loader: () => import('./tree/Index'),
|
||||
loading: Loading,
|
||||
})
|
||||
const CoderRootTag = Loadable({
|
||||
loader: () => import('./CoderRootTag'),
|
||||
loader: () => import('./tag/Index'),
|
||||
loading: Loading,
|
||||
})
|
||||
const CoderRootVersion = Loadable({
|
||||
loader: () => import('../Version/version'),
|
||||
loading: Loading,
|
||||
})
|
||||
const CoderRootVersionNew = Loadable({
|
||||
loader: () => import('../Version/New'),
|
||||
loading: Loading,
|
||||
})
|
||||
const CoderRootVersionUpdate = Loadable({
|
||||
loader: () => import('../Version/New'),
|
||||
loader: () => import('./version/Index'),
|
||||
loading: Loading,
|
||||
})
|
||||
// const CoderRootVersionNew = Loadable({
|
||||
// loader: () => import('./version/New'),
|
||||
// loading: Loading,
|
||||
// })
|
||||
// const CoderRootVersionUpdate = Loadable({
|
||||
// loader: () => import('./version/New'),
|
||||
// loading: Loading,
|
||||
// })
|
||||
const Diff = Loadable({
|
||||
loader: () => import('./Diff'),
|
||||
loading: Loading,
|
||||
|
@ -83,8 +84,8 @@ class CoderRootIndex extends Component{
|
|||
}
|
||||
render(){
|
||||
return(
|
||||
<div>
|
||||
<Top {...this.props} {...this.state}/>
|
||||
<div className="coderSubPage">
|
||||
{/* <Top {...this.props} {...this.state}/> */}
|
||||
<Switch {...this.props}>
|
||||
{/* 新建文件 */}
|
||||
<Route path="/:owner/:projectsId/:branch/newfile/:path"
|
||||
|
@ -117,7 +118,7 @@ class CoderRootIndex extends Component{
|
|||
() => (<CoderRootCommit {...this.props} {...this.state} commit_class="main" getTopCount={this.getTopCount} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/:owner/:projectsId/releases/:versionId/update"
|
||||
{/* <Route path="/:owner/:projectsId/releases/:versionId/update"
|
||||
render={
|
||||
(props) => (<CoderRootVersionUpdate {...this.props} {...this.state} {...props} />)
|
||||
}
|
||||
|
@ -126,7 +127,7 @@ class CoderRootIndex extends Component{
|
|||
render={
|
||||
() => (<CoderRootVersionNew {...this.props} {...this.state} />)
|
||||
}
|
||||
></Route>
|
||||
></Route> */}
|
||||
<Route path="/:owner/:projectsId/releases"
|
||||
render={
|
||||
() => (<CoderRootVersion {...this.props} {...this.state} />)
|
||||
|
|
|
@ -1,35 +1,55 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import { Button ,Spin } from "antd";
|
||||
import { truncateCommitId } from '../common/util';
|
||||
import { timeFormat, truncateCommitId } from '../common/util';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import Files from '../Merge/Files';
|
||||
|
||||
import Tree from "./img/tree.png";
|
||||
import User from "../Component/User";
|
||||
import Keys from "../Component/Keys";
|
||||
|
||||
import axios from "axios";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
const Infos = styled.div`
|
||||
border: 1px solid #dddddd;
|
||||
border: 1px solid #FAFCFF;
|
||||
margin-bottom:15px;
|
||||
& .commitinfos {
|
||||
background-color: #f1f8ff;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding: 20px;
|
||||
border: 1px solid rgba(42, 97, 255, 0.23);
|
||||
border-radius: 3px 3px 0px 0px;
|
||||
padding: 10px 20px 10px 16px;
|
||||
& .f-wrap-between{
|
||||
align-items: center;
|
||||
}
|
||||
& .task-hide{
|
||||
width: 65rem;
|
||||
overflow:hidden;
|
||||
white-space:normal;
|
||||
word-break:break-all;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
& > .f-wrap-between {
|
||||
padding: 10px 20px;
|
||||
padding: 14px 20px 14px 16px;
|
||||
border-radius: 3px 3px 0px 0px;
|
||||
border: 1px solid #D0D0D0;
|
||||
.df{
|
||||
align-items: center;
|
||||
& .underline:hover{
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default ({ match , history }) => {
|
||||
//提交详情页
|
||||
export default (props) => {
|
||||
const {match , history } = props;
|
||||
const [data, setData] = useState({undefined});
|
||||
const [commit, setCommit] = useState(undefined);
|
||||
const [parents, setParents] = useState(undefined);
|
||||
const [committer, setCommitter] = useState(undefined);
|
||||
const [isSpin, setIsSpin] = useState(true);
|
||||
|
||||
const { sha , projectsId, owner } = match.params;
|
||||
useEffect(() => {
|
||||
if (projectsId && owner && sha) {
|
||||
|
@ -43,6 +63,7 @@ export default ({ match , history }) => {
|
|||
setParents(result.data.parents);
|
||||
setCommitter(result.data.committer || (result.data.commit && result.data.commit.committer));
|
||||
setIsSpin(false);
|
||||
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
|
@ -56,29 +77,42 @@ export default ({ match , history }) => {
|
|||
<Infos>
|
||||
<div className="commitinfos">
|
||||
<div className="f-wrap-between">
|
||||
{commit && commit.message &&
|
||||
<pre className="task-hide" style={{marginBottom:"0px",height:"28px",whiteSpace:"pre-wrap"}}>{commit.message}</pre>
|
||||
}
|
||||
<Button type="primary" onClick={()=>{history.push(`/${owner}/${projectsId}/tree/${truncateCommitId(sha)}`)}} className="ml30">浏览代码</Button>
|
||||
<div>
|
||||
{commit && commit.message &&
|
||||
<pre className="task-hide">{commit.message}</pre>
|
||||
}
|
||||
<Link to={`/${owner}/${projectsId}/tree/${data.branch}`}><i className="iconfont icon-fenzhi2 font-18"></i>{data.branch}</Link>
|
||||
</div>
|
||||
<Button type="primary" onClick={()=>{history.push(`/${owner}/${projectsId}/tree/${truncateCommitId(sha)}`)}} className="btnblue" style={{height:"36px"}}>浏览文件</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="f-wrap-between" style={{ alignItems: "center" }}>
|
||||
<ul className="df">
|
||||
<User
|
||||
url={(committer && getImageUrl(`/${committer.image_url}`))|| "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"}
|
||||
id = {committer && committer.id}
|
||||
url={(committer && getImageUrl(`/${committer.image_url}`))}
|
||||
name={committer && committer.name}
|
||||
login={committer && committer.login}
|
||||
/>
|
||||
{committer && committer.time_from_now && <li className="ml20 mt2">{committer.time_from_now}</li>}
|
||||
{commit && commit.timestamp && <li className="ml4">提交于{timeFormat(commit.timestamp)}</li>}
|
||||
</ul>
|
||||
<li className="df">
|
||||
{
|
||||
parents && parents.length > 0 && parents.map((item,key)=>{
|
||||
return(
|
||||
<Keys title="父节点" value={truncateCommitId(item.sha)} key={key} className="mr20"></Keys>
|
||||
<div className="ml40 f-wrap-alignCenter">
|
||||
<label className="mr8">父节点</label>
|
||||
<img src={Tree} alt="sha" width={"16px"} className="mr4"/>
|
||||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}/${data.branch}`} className="underline">{truncateCommitId(item.sha)}</Link>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
<Keys title="当前节点" value={truncateCommitId(sha)}></Keys>
|
||||
<div className="ml40 f-wrap-alignCenter">
|
||||
<label className="mr8">当前节点</label>
|
||||
<img src={Tree} alt="sha" width={"16px"} className="mr4"/>
|
||||
<span>{truncateCommitId(sha)}</span>
|
||||
</div>
|
||||
</li>
|
||||
</div>
|
||||
</Infos>
|
||||
|
@ -87,6 +121,7 @@ export default ({ match , history }) => {
|
|||
data={data}
|
||||
owner={owner}
|
||||
projectsId={projectsId}
|
||||
parentsSha={parents && parents.length > 0 && parents[0].sha}
|
||||
/>
|
||||
</Spin>
|
||||
</div>
|
||||
|
|
|
@ -189,13 +189,13 @@
|
|||
flex-wrap: wrap;
|
||||
padding-bottom: 2px;
|
||||
a{
|
||||
margin: 0px 17px 0px 0px;
|
||||
margin: 0px 17px 10px 0px;
|
||||
img{
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
&:nth-child(6){
|
||||
&:nth-child(5){
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
|
@ -253,7 +253,7 @@
|
|||
background-color: #FAFCFF;
|
||||
.ellipsistxt{
|
||||
margin-top: 6px;
|
||||
cursor: pointer;
|
||||
// cursor: pointer;
|
||||
#ptxt{
|
||||
margin-bottom: 0px;
|
||||
word-break: break-all;
|
||||
|
@ -402,6 +402,16 @@
|
|||
cursor: pointer;
|
||||
background: #FAFBFC;
|
||||
border-radius: 4px;
|
||||
.ant-dropdown-menu-item{
|
||||
border-radius: 8px;
|
||||
text-align: left!important;
|
||||
a{
|
||||
width: 350px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
border: 1px solid #D0D0D0;
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
|
@ -447,4 +457,28 @@
|
|||
.ant-anchor-ink::before{
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.coderSubPage{
|
||||
width: 1200px;
|
||||
margin:0px auto;
|
||||
}
|
||||
.griditemAnchor{
|
||||
margin-left: 0px;
|
||||
padding: 0px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
.ant-anchor{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
.griditemCate{
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.catelogue{
|
||||
margin-left: 0px;
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 631 B |
Binary file not shown.
After Width: | Height: | Size: 590 B |
|
@ -575,6 +575,9 @@
|
|||
border:1px solid #ddd;
|
||||
margin-top: 18px;
|
||||
border-radius: 4px;
|
||||
.ant-anchor-wrapper{
|
||||
overflow: unset!important;
|
||||
}
|
||||
}
|
||||
.commonBox .commonBox-title{
|
||||
padding:0px 20px;
|
||||
|
@ -719,12 +722,76 @@ a.color-grey-ccc:hover{
|
|||
padding:0px 30px;
|
||||
min-height: 400px;
|
||||
}
|
||||
.commitList > div{
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
padding:16px 0px;
|
||||
}
|
||||
.commitList > div:last-child{
|
||||
border-bottom: none;
|
||||
|
||||
.main{
|
||||
margin: 30px auto;
|
||||
.ant-timeline{
|
||||
margin-top: 28px;
|
||||
.commitList-item{
|
||||
position: relative;
|
||||
padding: 20px 20px;
|
||||
background: #FAFCFF;
|
||||
border: 1px solid rgba(42, 97, 255, 0.23);
|
||||
border-radius: 4px;
|
||||
margin-left: 16px;
|
||||
align-items: center;
|
||||
&:after,&:before{
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -10px;
|
||||
top: 10px;
|
||||
border-top: 6px solid transparent;
|
||||
border-bottom: 6px solid transparent;
|
||||
border-right: 10px solid rgba(42, 97, 255, 0.23);
|
||||
}
|
||||
&:after{
|
||||
left: -8px;
|
||||
border-right: 10px solid #FAFCFF;
|
||||
&:hover{
|
||||
border-right: 10px solid #EEF6FF;
|
||||
}
|
||||
}
|
||||
&:hover{
|
||||
background: #EEF6FF;
|
||||
border: 1px solid rgba(42, 97, 255, 0.58);
|
||||
&:after{
|
||||
border-right: 10px solid #EEF6FF;
|
||||
}
|
||||
&:before{
|
||||
border-right: 10px solid rgba(42, 97, 255, 0.58);
|
||||
}
|
||||
}
|
||||
.treecopy-cont{
|
||||
padding: 4px 15px;
|
||||
}
|
||||
.btn-83{
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
.ant-timeline-item{
|
||||
padding: 8px 0 20px;
|
||||
}
|
||||
.ant-timeline-item-tail{
|
||||
height: calc(100% - 20px);
|
||||
border-left: 2px solid #EEEEEE;
|
||||
top: 12px;
|
||||
&:after{
|
||||
content: ' ';
|
||||
height: 0;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
border: 7px solid transparent;
|
||||
border-top-color: #EEEEEE;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
margin-left: -8px;
|
||||
}
|
||||
}
|
||||
.ant-timeline-item-head-custom{
|
||||
top:20px;
|
||||
padding: 0 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
|
|||
</li>
|
||||
:""
|
||||
}
|
||||
{
|
||||
{/* {
|
||||
item.menu_name === "resources" &&
|
||||
<li className={pathname==="source" ? "active" : ""}>
|
||||
<Link to={{ pathname: `/${owner}/${projectsId}/source`, state }}>
|
||||
|
@ -95,7 +95,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
|
|||
{projectDetail && projectDetail.source_count ? <span className="num">{projectDetail.source_count}</span> :""}
|
||||
</Link>
|
||||
</li>
|
||||
}
|
||||
} */}
|
||||
{
|
||||
item.menu_name === "versions" &&
|
||||
<li className={pathname==="milestones" ? "active" : ""}>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React , { useState , useEffect } from 'react';
|
||||
import React , { useState } from 'react';
|
||||
import { Anchor , Input } from 'antd';
|
||||
import './sub.scss';
|
||||
import { Base64 } from 'js-base64';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
|
@ -18,7 +18,7 @@ function ReadmeCatelogue({ menuList , hash }) {
|
|||
function changeValue(e) {
|
||||
setValue(e.target.value);
|
||||
if(e.target.value){
|
||||
let m = menuList.filter(i=>i.text.indexOf(e.target.value)>-1);
|
||||
let m = menuList.filter(i=>i.text.toLowerCase().indexOf(e.target.value.toLowerCase())>-1);
|
||||
setMenu(m);
|
||||
}else{
|
||||
setMenu(menuList);
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import'./sub.scss'
|
||||
|
||||
function SubMenu({tab,owner,projectsId}) {
|
||||
return(
|
||||
<ul className="subMenu">
|
||||
<Link to={`/${owner}/${projectsId}/tags`} className={tab==="tags"?"active":""}>标签</Link>
|
||||
<Link to={`/${owner}/${projectsId}/releases`} className={tab==="releases"?"active":""}>发行版</Link>
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
export default SubMenu;
|
|
@ -64,4 +64,28 @@
|
|||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.subMenu{
|
||||
display: flex;
|
||||
padding-top: 30px;
|
||||
a{
|
||||
width: 83px;
|
||||
font-weight: 500;
|
||||
line-height: 30px;
|
||||
height: 32px;
|
||||
color: #333333!important;
|
||||
text-align: center;
|
||||
border: 1px solid #D0D0D0;
|
||||
border-radius: 0px 4px 4px 0px;
|
||||
background: rgba(250, 251, 252, 0);
|
||||
&:first-child{
|
||||
border-right: none;
|
||||
border-radius: 4px 0px 0px 4px;
|
||||
}
|
||||
&.active{
|
||||
background-color: #466AFF;
|
||||
color: #fff!important;
|
||||
border-color: #466AFF;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
import React,{ useEffect , useState } from 'react';
|
||||
import SubMenu from '../sub/SubMenu';
|
||||
import { Table , Tooltip } from 'antd';
|
||||
import axios from 'axios';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { truncateCommitId } from '../../common/util';
|
||||
import './Index.scss';
|
||||
import Tree from '../img/tree.png'
|
||||
import moment from 'moment';
|
||||
|
||||
|
||||
function Tags(props) {
|
||||
|
||||
const [ source , setSource ] = useState([]);
|
||||
|
||||
const { projectsId , owner } = props.match.params;
|
||||
|
||||
useEffect(() => {
|
||||
if (projectsId) {
|
||||
const url = `/${owner}/${projectsId}/tags.json`;
|
||||
axios.get(url).then((result) => {
|
||||
if (result) {
|
||||
setSource(result.data);
|
||||
}
|
||||
}).catch(error => {})
|
||||
}
|
||||
}, [owner, projectsId]);
|
||||
|
||||
const columns=[
|
||||
{
|
||||
title:"标签名",
|
||||
dataIndex:"name",
|
||||
key:1,
|
||||
ellipsis:true,
|
||||
render:(txt,item)=>{
|
||||
return <Link className="hover" to={`/${owner}/${projectsId}/tree/${item.name}`} >{item.name}</Link>
|
||||
}
|
||||
},
|
||||
{
|
||||
title:"创建时间",
|
||||
dataIndex:"time_ago",
|
||||
key:2,
|
||||
ellipsis:true,
|
||||
render:(txt,item)=>{
|
||||
return (
|
||||
<span className="color-grey-3">
|
||||
<Link className="mr3" style={{fontWeight:"500"}} to={`/${item.commit && item.commit.login}`} >{item.commit && item.commit.name}</Link>
|
||||
<span>创建于{txt}</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title:"提交ID",
|
||||
dataIndex:"id",
|
||||
key:3,
|
||||
ellipsis:true,
|
||||
render:(txt,item)=>{
|
||||
return (
|
||||
<Tooltip placement="top" title={`最后提交日期:${item.created_at_unix ? moment(item.created_at_unix*1000).format('YYYY-MM-DD'):''}`}>
|
||||
<img src={Tree} alt="提交ID" width="22px" className="mr4"/>
|
||||
<Link className="hover color-blue" to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.id}`)}`}>{truncateCommitId(item.id)}</Link>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title:"描述信息",
|
||||
dataIndex:"message",
|
||||
key:4,
|
||||
ellipsis:true,
|
||||
render:(txt,item)=>{
|
||||
return item.message || "--"
|
||||
}
|
||||
},
|
||||
{
|
||||
title:"下载",
|
||||
dataIndex:"stage_type",
|
||||
key:5,
|
||||
ellipsis:true,
|
||||
align:"center",
|
||||
width:"181px",
|
||||
render:(txt,item)=>{
|
||||
return (
|
||||
<div>
|
||||
|
||||
<a href={`${item.tarball_url}`} download className="btn-83">
|
||||
<i className="iconfont icon-xiazai-icon font-16 mr5"></i>TAR
|
||||
</a>
|
||||
<a href={`${item.zipball_url}`} download className="btn-83">
|
||||
<i className="iconfont icon-xiazai-icon font-16 mr5"></i>ZIP
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
return(
|
||||
<div>
|
||||
<SubMenu tab={"tags"} projectsId={projectsId} owner={owner}/>
|
||||
<Table className="tagTable" dataSource={source} columns={columns} pagination={false}></Table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Tags;
|
|
@ -0,0 +1,31 @@
|
|||
.tagTable{
|
||||
margin-top: 30px;
|
||||
thead{
|
||||
tr th{
|
||||
background-color: #fff;
|
||||
padding:5px 0px;
|
||||
.ant-table-column-title{
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
}
|
||||
tbody{
|
||||
tr{
|
||||
&:hover td{
|
||||
background-color: #fff!important;
|
||||
}
|
||||
td{
|
||||
padding:0px;
|
||||
height: 69px;
|
||||
line-height: 69px;
|
||||
}
|
||||
&:last-child{
|
||||
td{
|
||||
border-bottom: none!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
import React , { useEffect , useState } from 'react';
|
||||
import CopyTool from '../../Component/CopyTool';
|
||||
import { truncateCommitId } from '../../common/util';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import { Dropdown , Menu , Spin } from 'antd';
|
||||
import './Index.scss';
|
||||
|
||||
import Tree from '../img/tree.png';
|
||||
import Axios from 'axios';
|
||||
|
||||
function turnbar(str){
|
||||
if(str && str.length>0 && str.indexOf("/")>-1){
|
||||
return str.replaceAll('/','%2F');
|
||||
}
|
||||
return str;
|
||||
}
|
||||
function Index(props) {
|
||||
const [ list , setList ] = useState([]);
|
||||
const [ isSpin , setIsSpin ] = useState(true);
|
||||
|
||||
const { projectsId , owner } = props.match.params;
|
||||
const { isManager , isDeveloper , projectDetail } = props;
|
||||
|
||||
useEffect(()=>{
|
||||
getList();
|
||||
},[])
|
||||
|
||||
|
||||
const menu =(zip_url,tar_url)=> (
|
||||
<Menu>
|
||||
<Menu.Item key={'0'}><a href={zip_url}>ZIP</a></Menu.Item>
|
||||
<Menu.Item key={'1'}><a href={tar_url}>TAR.GZ</a></Menu.Item>
|
||||
</Menu>
|
||||
)
|
||||
|
||||
function getList() {
|
||||
const url = `/${owner}/${projectsId}/branches_slice.json`;
|
||||
Axios.get(url).then(result=>{
|
||||
if(result){
|
||||
setList(result.data);
|
||||
}
|
||||
setIsSpin(false);
|
||||
}).catch(error=>{setIsSpin(false);})
|
||||
}
|
||||
|
||||
return(
|
||||
<Spin spinning={isSpin}>
|
||||
<div style={{paddingTop:"10px",minHeight:"400px"}}>
|
||||
{
|
||||
list && list.length>0 && list.map((item,key)=>{
|
||||
return(
|
||||
<React.Fragment>
|
||||
<p className="branchSort">{item.branch_type === "default" ? "默认分支" : item.branch_type==="protected"?"保护分支":"其它分支"}</p>
|
||||
{
|
||||
item.list && item.list.length>0 &&
|
||||
<ul className="treeUl">
|
||||
{
|
||||
item.list.map((i,k)=>{
|
||||
let last_commit = i.last_commit;
|
||||
return(
|
||||
<li>
|
||||
<div className="treeinfo">
|
||||
<Link to={`/${owner}/${projectsId}/tree/${turnbar(i.name)}`} className="task-hide">{i.name}</Link>
|
||||
<div>
|
||||
{
|
||||
last_commit && last_commit.committer && last_commit.committer.id?
|
||||
<Link to={`/${ last_commit.committer.login}`}>
|
||||
<img style={{borderRadius:"50%"}} src={getImageUrl(`/${ last_commit.committer.image_url}`)} alt=""/>
|
||||
<span className="mr3 color-grey-3" style={{fontWeight:"500"}}>{last_commit && last_commit.committer && last_commit.committer.name}</span>
|
||||
</Link>
|
||||
:
|
||||
<React.Fragment>
|
||||
<img style={{borderRadius:"50%"}} src={getImageUrl(`/${ last_commit.committer.image_url}`)} alt=""/>
|
||||
<span className="mr3 color-grey-3" style={{fontWeight:"500"}}>{last_commit && last_commit.committer && last_commit.committer.name}</span>
|
||||
</React.Fragment>
|
||||
}
|
||||
<span className="color-grey-3">更新于{last_commit && last_commit.time_from_now}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="treecopy">
|
||||
<div>
|
||||
<span>
|
||||
<img src={Tree} alt="sha" width={"16px"}/>
|
||||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(last_commit && last_commit.sha)}`}>{truncateCommitId(last_commit && last_commit.sha)}</Link>
|
||||
<input type="text" id={`value${key}${k}`} value={`${truncateCommitId(last_commit && last_commit.sha)}`}/>
|
||||
</span>
|
||||
<CopyTool beforeText="复制commit id" afterText="复制成功" inputId={`value${key}${k}`}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="treeabout">
|
||||
{
|
||||
(isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) &&
|
||||
<Link to={`/${owner}/${projectsId}/pulls/new/${i.name}`} className="btn-83">+ 合并请求</Link>
|
||||
}
|
||||
<Dropdown overlay={menu(i.zip_url,i.tar_url)} trigger={['click']} placement="bottomRight">
|
||||
<a className="btn-83 ml15">下载<i className="iconfont icon-sanjiaoxing-down font-14"></i></a>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</React.Fragment>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
export default Index;
|
|
@ -0,0 +1,96 @@
|
|||
.branchSort{
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
font-size: 15px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
padding-left: 10px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 6px!important;
|
||||
}
|
||||
.treeUl{
|
||||
background: #FAFCFF;
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(42, 97, 255, 0.23);
|
||||
li{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 20px;
|
||||
border-bottom: 1px solid rgba(42, 97, 255, 0.23);
|
||||
&:last-child{
|
||||
border-bottom: none;
|
||||
}
|
||||
.treeinfo{
|
||||
max-width: 399px;
|
||||
flex:1;
|
||||
flex-direction: column;
|
||||
a:hover{
|
||||
span{
|
||||
color: #466AFF!important;
|
||||
}
|
||||
}
|
||||
img{
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
.treeabout{
|
||||
flex:1;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
.treecopy{
|
||||
flex:1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
&>div{
|
||||
height: 32px;
|
||||
background: #FAFBFC;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #D0D0D0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&>span{
|
||||
padding:0px 15px;
|
||||
border-right: 1px solid rgba(153, 153, 153, 0.4);
|
||||
height: 100%;
|
||||
img{
|
||||
margin-right: 4px;
|
||||
}
|
||||
a{
|
||||
color: #466AFF;
|
||||
&:hover{
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
&>i{
|
||||
margin:0px 12px;
|
||||
color: #333!important;
|
||||
}
|
||||
input{
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
opacity: 0;
|
||||
top: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.new-conmmit{
|
||||
width: 30px;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
display: block;
|
||||
background: #FF6832;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.icon-a-yuanquan2x{
|
||||
color: #466AFF;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { Button } from 'antd';
|
||||
import React from 'react';
|
||||
import './version.scss';
|
||||
|
||||
function Empty({operation,addFunc}) {
|
||||
return(
|
||||
<div className="emptyPanel color-grey-3">
|
||||
<i className="iconfont icon-banbenicon font-50 color-grey-3" style={{height:"50px",lineHeight:"50px",marginBottom:"13px"}}></i>
|
||||
<span className="weight font-26 mb15">这里暂未发布过任何版本</span>
|
||||
<span className="weight400" style={{textAlign:"center",lineHeight:"20px"}}>发行版功能基于仓库中的历史标记<br/>建议使用类似 V1.0 的版本标记作为发布点</span>
|
||||
<div className="operation">
|
||||
{
|
||||
operation ?
|
||||
<Button type={"primary"} onClick={addFunc} className="btnblue" style={{width:"118px",height:"36px"}}>发布新版本</Button>
|
||||
:
|
||||
<span className="color-grey-3 weight font-16">该项目暂时没有发布版本</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Empty;
|
|
@ -0,0 +1,41 @@
|
|||
import React from 'react';
|
||||
import { Switch , Route } from 'react-router';
|
||||
import Loadable from 'react-loadable';
|
||||
import Loading from '../../../Loading';
|
||||
import SubMenu from '../sub/SubMenu';
|
||||
import "./version.scss";
|
||||
|
||||
const CoderRootVersion = Loadable({
|
||||
loader: () => import('./version'),
|
||||
loading: Loading,
|
||||
})
|
||||
const CoderRootVersionNew = Loadable({
|
||||
loader: () => import('./New'),
|
||||
loading: Loading,
|
||||
})
|
||||
function Index(props) {
|
||||
const { projectsId , owner } = props.match.params;
|
||||
return(
|
||||
<div>
|
||||
<SubMenu tab={"releases"} projectsId={projectsId} owner={owner}/>
|
||||
<Switch>
|
||||
<Route path="/:owner/:projectsId/releases/:versionId/update"
|
||||
render={
|
||||
(p) => (<CoderRootVersionNew {...props} {...p} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/:owner/:projectsId/releases/new"
|
||||
render={
|
||||
(p) => (<CoderRootVersionNew {...props} {...p} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/:owner/:projectsId/releases"
|
||||
render={
|
||||
(p) => (<CoderRootVersion {...props} {...p} />)
|
||||
}
|
||||
></Route>
|
||||
</Switch>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Index;
|
|
@ -0,0 +1,266 @@
|
|||
import React, { useState, useEffect, forwardRef } from "react";
|
||||
import styled from "styled-components";
|
||||
import { AutoComplete , Input, Checkbox, Button, Form } from "antd";
|
||||
import SelectBranch from '../../Branch/Select';
|
||||
|
||||
import Editor from "../../../modules/tpm/challengesnew/tpm-md-editor";
|
||||
import Upload from "../../Upload/Index";
|
||||
import Attachments from "../../Upload/attachment";
|
||||
import axios from "axios";
|
||||
import "./version.scss";
|
||||
import { trim } from "lodash";
|
||||
|
||||
const { Option } = AutoComplete;
|
||||
|
||||
const Span = styled.span`
|
||||
margin: 0px 15px;
|
||||
color: #bbb;
|
||||
line-height: 35px;
|
||||
font-size:16px;
|
||||
font-weight:400;
|
||||
color:#666;
|
||||
`;
|
||||
export default Form.create()(
|
||||
forwardRef(
|
||||
(
|
||||
{ form, projectDetail , match, showNotification, history },
|
||||
ref
|
||||
) => {
|
||||
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||
const [tagList, setTagList] = useState(undefined);
|
||||
const [desc, setDesc] = useState(null);
|
||||
const [branch, setBranch ] = useState(null);
|
||||
const [fileList, setFileList] = useState(undefined);
|
||||
const [attachment, setAttachment] = useState(undefined);
|
||||
const [options , setOptions] = useState(undefined);
|
||||
const stable = history && history.location && history.location.state.stable;
|
||||
const { projectsId, versionId , owner } = match.params;
|
||||
|
||||
useEffect(()=>{
|
||||
if(projectDetail && projectDetail.default_branch){
|
||||
setBranch(projectDetail.default_branch);
|
||||
}
|
||||
},[projectDetail])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (versionId) {
|
||||
const url = `/${owner}/${projectsId}/releases/${versionId}/edit.json`;
|
||||
axios.get(url).then(result => {
|
||||
if (result) {
|
||||
setFieldsValue(result.data);
|
||||
setDesc(result.data.body);
|
||||
setAttachment(result.data.attachments);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [versionId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (projectsId) {
|
||||
const url = `/${owner}/${projectsId}/tags.json`;
|
||||
axios
|
||||
.get(url,{params:{
|
||||
limit:1000
|
||||
}})
|
||||
.then(result => {
|
||||
if (result) {
|
||||
setTagList(result.data);
|
||||
setOptions(renderTagList(result.data));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
}, [projectsId]);
|
||||
|
||||
function renderTagList(list) {
|
||||
if (list) {
|
||||
let array = list.map((item, key) => {
|
||||
return (
|
||||
<Option key={key} value={item.name}>
|
||||
{item.name}
|
||||
</Option>
|
||||
);
|
||||
});
|
||||
return array || undefined;
|
||||
}
|
||||
}
|
||||
function submit() {
|
||||
validateFields((err, value) => {
|
||||
if(err)return;
|
||||
if (versionId) {
|
||||
let url = `/${owner}/${projectsId}/releases/${versionId}.json`;
|
||||
axios
|
||||
.put(url, {
|
||||
...value,
|
||||
body: desc,
|
||||
attachment_ids: fileList,
|
||||
target_commitish:branch
|
||||
})
|
||||
.then(result => {
|
||||
if (result) {
|
||||
showNotification("版本修改成功!");
|
||||
history.push(`/${owner}/${projectsId}/releases`);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
let url = `/${owner}/${projectsId}/releases.json`;
|
||||
axios.post(url, {
|
||||
...value,
|
||||
body: desc,
|
||||
attachment_ids: fileList
|
||||
})
|
||||
.then(result => {
|
||||
if (result) {
|
||||
showNotification("版本发布成功!");
|
||||
history.push(`/${owner}/${projectsId}/releases`);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
// 输入标签名
|
||||
function changeAuto(value){
|
||||
let l = tagList.filter(item=>item.name.indexOf(value) > -1);
|
||||
setOptions(renderTagList(l));
|
||||
}
|
||||
|
||||
function changeBranch(params) {
|
||||
setBranch(params);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="df pt15">
|
||||
<Form className="versionForm">
|
||||
<div className="itemInline">
|
||||
<Form.Item>
|
||||
{getFieldDecorator("tag_name",
|
||||
{ rules:[
|
||||
{ required: true, message: "请输入获取或选择一个标签" },
|
||||
{ validator: (rule,val,callback) =>{
|
||||
if(val.length>30 || val.indexOf(' ')>0 || val.match(/^\s+$/) || trim(val).length!=val.length){
|
||||
callback('无效的标签名称,请参考右侧建议命名标签并确认长度在1~30个字符之间');
|
||||
}else{
|
||||
callback();
|
||||
}
|
||||
}}],
|
||||
validateFirst: true
|
||||
})(
|
||||
<AutoComplete
|
||||
placeholder="标记一个版本"
|
||||
onChange={changeAuto}
|
||||
style={{ width: "200px" }}
|
||||
>
|
||||
{options}
|
||||
</AutoComplete>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Span>@</Span>
|
||||
<SelectBranch
|
||||
repo_id={projectDetail && projectDetail.repo_id}
|
||||
projectsId={projectsId}
|
||||
branch={branch}
|
||||
changeBranch={changeBranch}
|
||||
owner={owner}
|
||||
history={history}
|
||||
tagflag={false}
|
||||
branchList={projectDetail && projectDetail.branches && projectDetail.branches.list}
|
||||
></SelectBranch>
|
||||
<p className="font-12 color-grey-6 weight400">选择一个已经存在的标签,或者在发布时新建一个标签</p>
|
||||
</div>
|
||||
<Form.Item className="pt20">
|
||||
{getFieldDecorator("name",
|
||||
{ rules:[
|
||||
{ required: true, message: "请输入发行版的标题" },
|
||||
{ validator: (rule,val,callback) =>{
|
||||
if(val.length>50){
|
||||
callback('标题长度在1~50个字符之间');
|
||||
}else{
|
||||
callback();
|
||||
}
|
||||
}}],
|
||||
validateFirst: true
|
||||
})(
|
||||
<Input placeholder="发行版的标题" />
|
||||
)}
|
||||
</Form.Item>
|
||||
<Editor
|
||||
placeholder={"描述此发行版"}
|
||||
height={200}
|
||||
mdID={`version-comments-description`}
|
||||
initValue={desc}
|
||||
onChange={setDesc}
|
||||
noStorage={true}
|
||||
/>
|
||||
|
||||
<div className="mt5 dragBox">
|
||||
<Upload
|
||||
className="versionStyle"
|
||||
isComplete={true}
|
||||
load={setFileList}
|
||||
icon={
|
||||
<i className="iconfont icon-shangchuanicon dragIcon" />
|
||||
}
|
||||
size={100}
|
||||
showNotification={showNotification}
|
||||
/>
|
||||
{versionId && attachment && attachment.length > 0 ? (
|
||||
<Attachments
|
||||
attachments={attachment}
|
||||
showNotification={showNotification}
|
||||
canDelete={true}
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</div>
|
||||
<Form.Item className="prerelease">
|
||||
{getFieldDecorator("prerelease",
|
||||
{ rules:[],
|
||||
validateFirst: true
|
||||
})(
|
||||
<Checkbox defaultChecked={!stable}>这是一个预览版本</Checkbox>
|
||||
)}
|
||||
</Form.Item>
|
||||
<p className="pt20" style={{borderTop:"1px solid #eee"}}>
|
||||
<Button onClick={submit} type="primary" className="mr30 btnblue">
|
||||
{versionId ? "保存" : "创建"}发行版
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() =>history.push(`/${owner}/${projectsId}/releases`)} className="btngrey"
|
||||
>取消</Button>
|
||||
</p>
|
||||
</Form>
|
||||
<div className="versionTips">
|
||||
<div className="infosTip">
|
||||
<p className="font-16 mb14 weight">标签命名建议</p>
|
||||
<p className="mb15">
|
||||
通常的做法是在版本名称前加上字母 v 前缀, v1.0 或者 v2.3.4。
|
||||
</p>
|
||||
<p>
|
||||
如果标签不适合在生产环境下使用,请在版本名称后添加预发行版本。例如:v0.2-alpha
|
||||
或者 v5.9-beta.3。
|
||||
</p>
|
||||
</div>
|
||||
<div className="infosTip">
|
||||
<p className="font-16 mb14 weight">语义化版本</p>
|
||||
<p>
|
||||
如果你是第一次发布版本,我们强烈建议你阅读<a href='https://semver.org/lang/zh-CN' target='_blank' className="color-blue">语义化版本</a>。
|
||||
</p>
|
||||
</div>
|
||||
<div className="infosTip">
|
||||
<p className="font-16 mb14 weight">附件大小说明</p>
|
||||
<p>
|
||||
单个附件不能超过 100M(GVP 项目200M),每个仓库总附件不可超过
|
||||
1G(推荐项目不可超过 5G;GVP 项目不可超过
|
||||
20G)。附件总容量统计包括仓库附件和发行版附件。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
|
@ -0,0 +1,150 @@
|
|||
import React, { useEffect , useState } from "react";
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Spin , Button } from 'antd';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import {truncateCommitId} from '../../common/util';
|
||||
import Empty from './Empty';
|
||||
import './version.scss';
|
||||
import axios from 'axios';
|
||||
import Tree from '../img/tree-black.png';
|
||||
import RenderHtml from '../../../components/render-html';
|
||||
import User from "../../Component/User";
|
||||
|
||||
function version(props) {
|
||||
const [ data , setData ] = useState(undefined);
|
||||
const [ releases , setReleases ] = useState(undefined);
|
||||
const [ isSpin , setIsSpin ] = useState(true);
|
||||
const { projectsId ,owner } = props.match.params;
|
||||
const { isManager, isDeveloper, location , user } = props;
|
||||
const type = props.projectDetail && props.projectDetail.type;
|
||||
const turnFromNew = location && location.query && location.query.turnFromNew;
|
||||
const current_user_login = user && user.login;
|
||||
useEffect(()=>{
|
||||
getIssueList();
|
||||
},[])
|
||||
// 获取列表数据
|
||||
function getIssueList(){
|
||||
const url = `/${owner}/${projectsId}/releases.json`;
|
||||
axios.get(url).then((result) => {
|
||||
if (result) {
|
||||
setData(result.data);
|
||||
const { releases = [] } = result.data;
|
||||
//默认第一个展开(body参数)
|
||||
releases.length && (releases[0].bodyshow = true);
|
||||
setReleases(result.data.releases);
|
||||
setIsSpin(false);
|
||||
}
|
||||
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
// 显示版本描述
|
||||
function showBody(key,flag){
|
||||
var lists = releases.concat();
|
||||
lists[key].bodyshow = !flag ? true : false;
|
||||
lists.splice();
|
||||
setReleases(lists);
|
||||
}
|
||||
//删除
|
||||
function deleteRelease(releaseId) {
|
||||
if(releaseId){
|
||||
axios.delete(`/${owner}/${projectsId}/releases/${releaseId}.json`).then((result)=>{
|
||||
if(result){
|
||||
getIssueList();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
function release(item,key){
|
||||
return (
|
||||
<div className="versionInfo" key={key}>
|
||||
<span className="versionInfo_left">
|
||||
<span className={`${item.draft === "稳定" ?"versionTag green":"versionTag orange"}`}>{item.draft}</span>
|
||||
<span className="color-grey-3 mt15 font-12">
|
||||
<i className="iconfont icon-biaoqianicon mr3 font-14"></i>
|
||||
<Link className="hover" to={`/${owner}/${projectsId}/tree/${item.tag_name}`} >{item.tag_name}</Link>
|
||||
</span>
|
||||
<span className="color-grey-3 font-12">
|
||||
<img src={Tree} width="16px" color="#333333" className="mr3"/>
|
||||
<Link className="hover" to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`}>{truncateCommitId(item.sha)}</Link>
|
||||
</span>
|
||||
</span>
|
||||
<div className="versionInfo_right">
|
||||
<div className="versionName">
|
||||
<Link 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 && <i className ="iconfont icon-shanchuicon1 font-16 ml15" onClick={()=>{deleteRelease(item.version_id)}}></i>}
|
||||
</span>
|
||||
</div>
|
||||
<span className="color-grey-3 mb15 version-user">
|
||||
<i className={`${item.bodyshow ? "iconfont icon-sanjiaoxing-down color-grey-8 mr3 font-14":"iconfont icon-triangle color-grey-8 mr3 font-14"}`} onClick={()=>showBody(key,item.bodyshow)}></i>
|
||||
<User
|
||||
id={item.id}
|
||||
url={(item.image_url && getImageUrl(`/${item.image_url}`)) || "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"}
|
||||
name={item.user_name}
|
||||
login={item.user_login}
|
||||
/>
|
||||
<span className="ml5">发布于{item.created_at}</span>
|
||||
</span>
|
||||
{
|
||||
item.bodyshow &&
|
||||
<div className="body-show">
|
||||
<RenderHtml className="break_word_comments imageLayerParent" value={item.body || ''} url={props.history.location}/>
|
||||
</div>
|
||||
}
|
||||
<RenderHtml />
|
||||
<p className="versionFile">
|
||||
{/* 发行版附件下载 */}
|
||||
{item.attachments && item.attachments.map((item)=>{
|
||||
return(<a href={item.url}><i className="iconfont icon-wenjian7 font-14 mr10 color-grey-3"></i>下载 {item.title}</a>)
|
||||
})}
|
||||
{/* 发行版下载包 */}
|
||||
<a href={item.tarball_url}><i className="iconfont icon-wenjian7 font-14 mr10 color-grey-3"></i>下载 {item.tag_name}.TAR.gz</a>
|
||||
<a href={item.zipball_url}><i className="iconfont icon-wenjian7 font-14 mr10 color-grey-3"></i>下载 {item.tag_name}.ZIP</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
function renderList(releases){
|
||||
if (releases && releases.length > 0) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{
|
||||
data && data.user_admin_permission && type !== 2 &&
|
||||
<div className="addReleaseBtn">
|
||||
<Button type={"primary"} onClick={addFunc} className="btnblue" style={{height:"36px"}}>发布新版本</Button>
|
||||
</div>
|
||||
}
|
||||
<div>
|
||||
{!turnFromNew ? releases.map((item, key) => release(item,key)) : release(releases[0],0)}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)
|
||||
} else if (releases && releases.length === 0) {
|
||||
return (
|
||||
<Empty
|
||||
operation={data && data.user_admin_permission && type !== 2}
|
||||
addFunc={addFunc}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function addFunc(){
|
||||
props.history.push({pathname:`/${owner}/${projectsId}/releases/new`,state:{stable:true}});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="releaseIndex">
|
||||
<div className="releasesVersion">
|
||||
<Spin spinning={isSpin}>
|
||||
{renderList(releases)}
|
||||
</Spin>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default version;
|
|
@ -0,0 +1,357 @@
|
|||
.topWrapper {
|
||||
padding: 20px 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
align-items: center;
|
||||
}
|
||||
.topWrapper_btn_new {
|
||||
background: #fff;
|
||||
color: #5091FF!important;
|
||||
padding:0px 12px;
|
||||
text-align: center;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
border:1px solid #5091FF;
|
||||
}
|
||||
.versionInfo{
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.versionInfo_left{
|
||||
display: flex;
|
||||
width: 182px;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
padding-right: 15px;
|
||||
&>.color-grey-3{
|
||||
max-width: 10rem;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
.versionInfo_right{
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
border-left: 1px solid #eee;
|
||||
position: relative;
|
||||
padding: 0px 30px 60px 24px;
|
||||
&::before{
|
||||
position: absolute;
|
||||
left: -4px;
|
||||
top:0px;
|
||||
content: '';
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: #466AFF;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.sendAuthorImg{
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.body-show{
|
||||
padding: 5px 10px 10px 10px;
|
||||
}
|
||||
& .version-user>a>span{
|
||||
display: inline-block;
|
||||
& img{
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.versionTag{
|
||||
display: inline;
|
||||
padding:0px 9px;
|
||||
color: #fff;
|
||||
position: relative;
|
||||
margin-top: -8px;
|
||||
height: 22px;
|
||||
line-height: 20px;
|
||||
border-radius: 4px;
|
||||
&::before{
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 0;
|
||||
height: 0px;
|
||||
border-left: 4px solid #cccccc;
|
||||
border-top: 4px solid transparent;
|
||||
border-bottom: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
z-index: 9;
|
||||
top: 6px;
|
||||
right: -9px;
|
||||
}
|
||||
&:after{
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
top:6px;
|
||||
right: -7px;
|
||||
position: absolute;
|
||||
border-left:4px solid #fff;
|
||||
border-top:4px solid transparent;
|
||||
border-bottom:4px solid transparent;
|
||||
border-right:4px solid transparent;
|
||||
content:'';
|
||||
z-index:10;
|
||||
}
|
||||
}
|
||||
.versionFile{
|
||||
margin-top: 5px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #eee;
|
||||
// width: 100%;
|
||||
a{
|
||||
display: block;
|
||||
color: #333;
|
||||
font-weight: 400;
|
||||
height: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
.versionTag.yellow{
|
||||
border: 1px solid #FBBC06;
|
||||
color: #FBBC06;
|
||||
&::before{
|
||||
border-left-color: #FBBC06;
|
||||
}
|
||||
}
|
||||
.versionTag.green{
|
||||
border: 1px solid #2DB44D;
|
||||
color: #2DB44D;
|
||||
&::before{
|
||||
border-left-color: #2DB44D;
|
||||
}
|
||||
}
|
||||
.versionTag.orange{
|
||||
border: 1px solid #FF6E23;
|
||||
color: #FF6E23;
|
||||
&::before{
|
||||
border-left-color: #FF6E23;
|
||||
}
|
||||
}
|
||||
.addReleaseBtn{
|
||||
text-align: right;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.versionName{
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
|
||||
.versionmilepostleft{
|
||||
padding: 15px;
|
||||
margin-right: 50px;
|
||||
width: 80%;
|
||||
}
|
||||
.topWrapper_btn_close {
|
||||
background: #504b4b;
|
||||
color: #FFFFFF!important;
|
||||
padding:0px 12px;
|
||||
text-align: center;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.topWrapper_btn_delete {
|
||||
background: #da1010;
|
||||
color: #FFFFFF!important;
|
||||
padding:0px 12px;
|
||||
text-align: center;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.versionrighe{
|
||||
flex: 2;
|
||||
}
|
||||
.versionleft{
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
}
|
||||
|
||||
/* .version_line{
|
||||
display: flex;
|
||||
height: 30px;
|
||||
margin: auto;
|
||||
border-left:1px solid #eee;
|
||||
} */
|
||||
.version_line_one{
|
||||
display: flex;
|
||||
height: 45px;
|
||||
margin: auto;
|
||||
border-left:1px solid #eee;
|
||||
}
|
||||
|
||||
.version_line_tpw{
|
||||
display: flex;
|
||||
height: 80px;
|
||||
margin: auto;
|
||||
border-left:1px solid #eee;
|
||||
}
|
||||
|
||||
.versiondiv{
|
||||
display: flex;
|
||||
}
|
||||
.verwinth{
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
/*开启中 关闭中*/
|
||||
.opendversionetail{
|
||||
display: inline-block;
|
||||
background: #21ba45;
|
||||
color: #ffffff!important;
|
||||
padding:0px 5px;
|
||||
text-align: center;
|
||||
height: 25px;
|
||||
/*width: 110px;*/
|
||||
border-radius: 4px;
|
||||
line-height: 25px;
|
||||
}
|
||||
.closedversionetail{
|
||||
display: inline-block;
|
||||
background: #e60b0b;
|
||||
color: #ffffff!important;
|
||||
padding:0px 5px;
|
||||
text-align: center;
|
||||
height: 25px;
|
||||
/*width: 110px;*/
|
||||
border-radius: 4px;
|
||||
line-height: 25px;
|
||||
}
|
||||
.versionrectangle {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 100%;
|
||||
margin-top: 15px;
|
||||
margin-left: -4px;
|
||||
margin-bottom: 10px;
|
||||
background: rgb(83, 81, 81);
|
||||
}
|
||||
.ver-middle{
|
||||
vertical-align: middle;
|
||||
}
|
||||
/* new */
|
||||
.versionForm{
|
||||
flex:1;
|
||||
padding-right: 40px;
|
||||
box-sizing: border-box;
|
||||
.ant-select-auto-complete.ant-select .ant-input:hover,.ant-input:hover {
|
||||
border-color: rgba(153, 153, 153, 0.8);
|
||||
}
|
||||
}
|
||||
.versionTips{
|
||||
width:268px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.infosTip{
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
color: #333;
|
||||
padding-bottom: 26px;
|
||||
margin-bottom: 26px;
|
||||
font-weight: 400;
|
||||
text-align: justify;
|
||||
&:last-child{
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
.dragBox{
|
||||
background: rgba(153, 153, 153, 0.04);
|
||||
border-radius: 4px;
|
||||
border: 1px dashed #d9d9d9;
|
||||
padding:20px;
|
||||
.versionStyle{
|
||||
border: none!important;
|
||||
padding-bottom:20px;
|
||||
.dragIcon{
|
||||
font-size: 40px!important;
|
||||
color: #666!important;
|
||||
line-height: 40px;
|
||||
height: 40px;
|
||||
margin-bottom: 14px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.ant-upload-list-item:hover .ant-upload-list-item-info {
|
||||
background-color: rgba(239, 244, 255, 1);
|
||||
}
|
||||
.ant-upload-list-item-info{
|
||||
padding:0px 20px 0px 8px;
|
||||
&>span{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.set-ant-row .ant-row{
|
||||
display: flex;
|
||||
height: 20px;
|
||||
align-items: center;
|
||||
}
|
||||
.itemInline{
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
position: relative;
|
||||
&>p{
|
||||
position: absolute;
|
||||
bottom: -5px;
|
||||
}
|
||||
}
|
||||
.itemInline .ant-row{
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.prerelease{
|
||||
padding-top: 20px;
|
||||
.ant-form-item-control{
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
.releaseIndex{
|
||||
margin: 30px auto;
|
||||
width: 1200px;
|
||||
}
|
||||
.emptyPanel{
|
||||
width: 100%;
|
||||
background: #FAFCFF;
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(42, 97, 255, 0.23);
|
||||
min-height: 418px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.operation{
|
||||
width: 400px;
|
||||
border-top: 1px solid #eee;
|
||||
padding-top: 34px;
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
}
|
||||
.ant-form-item-control{
|
||||
line-height: initial;
|
||||
}
|
|
@ -1,17 +1,20 @@
|
|||
import React ,{useEffect,useState } from 'react';
|
||||
import React ,{useEffect,useRef,useState } from 'react';
|
||||
import { truncateCommitId } from '../common/util';
|
||||
import { AlignCenter , FlexAJ } from '../Component/layout';
|
||||
import { Button } from 'antd';
|
||||
import { Button, Tooltip,Progress, Popover, Anchor } from 'antd';
|
||||
import './merge.css';
|
||||
import './Index.scss';
|
||||
|
||||
function Files({data,history,owner,projectsId}){
|
||||
function Files({ data,history,owner,projectsId , parentsSha }){
|
||||
const [ files , setFiles ] = useState(data && data.files);
|
||||
|
||||
const [ copyfileTipTitle, setCopyfileTipTitle] = useState("复制文件路径");
|
||||
const [ isOpen, setIsOpen] = useState(false);
|
||||
|
||||
useEffect(()=>{
|
||||
if(data){
|
||||
setFiles(data.files);
|
||||
}
|
||||
},[data])
|
||||
},[data]);
|
||||
|
||||
function showDown(flag,index,isBin){
|
||||
if(!isBin){
|
||||
|
@ -22,35 +25,83 @@ function Files({data,history,owner,projectsId}){
|
|||
}
|
||||
}
|
||||
|
||||
function copyFileName(fileName){
|
||||
var copyCont = document.createElement('input');
|
||||
copyCont.defaultValue = fileName;
|
||||
document.body.appendChild(copyCont);
|
||||
copyCont.select(); // 选择对象
|
||||
document.execCommand("Copy"); // 执行浏览器复制命令
|
||||
copyCont.className = 'copyCont';
|
||||
copyCont.style.display='none';
|
||||
setCopyfileTipTitle("复制成功");
|
||||
}
|
||||
|
||||
const folderOpen = (
|
||||
<div className="folders">
|
||||
<div className="folderList">
|
||||
{files && files.map((item, key) => {
|
||||
return (
|
||||
<a href={`#value${key}`}>
|
||||
<FlexAJ className="filesInfo" key={key} onClick={() => {item.flag && showDown(item.flag, key, item.isBin);setIsOpen(false);}}>
|
||||
<AlignCenter>
|
||||
<i className="iconfont icon-wenjianicon mr4"></i>
|
||||
<span className="cursor-pointer" data-clipboard-text={item.name}>{item.name}</span>
|
||||
</AlignCenter>
|
||||
<div className="see-file">
|
||||
<Tooltip placement="top" title={`${item.addition+item.deletion}处更改${item.addition + item.deletion > 0 && ":"}${item.addition>0?item.addition+"处添加":""}${item.addition>0 && item.deletion>0 ?"和":""}${item.deletion>0?item.deletion+"处删除":""}`}>
|
||||
<Progress showInfo = {false} strokeColor = "#2DB44D" size="small" percent={item.addition/(item.addition+item.deletion)*100} />
|
||||
{item.addition >0 && <span className="color-green ml10">+{item.addition}</span>}
|
||||
{item.deletion >0 && <span className="color-red ml10">-{item.deletion}</span>}
|
||||
</Tooltip>
|
||||
</div>
|
||||
</FlexAJ>
|
||||
</a>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
return(
|
||||
<div>
|
||||
<AlignCenter className="color-grey-9 pb10" style={{borderBottom:"1px solid #eee"}}>
|
||||
<i className="iconfont icon-sanjiaoxing-down mr5"></i>
|
||||
<span>
|
||||
共有<span className="color-grey-3"> {data && data.files_count} 个文件被更改</span>,包括
|
||||
<AlignCenter className="color-grey-9" style={{position:'relative'}}>
|
||||
<div onClick={()=>{setIsOpen(!isOpen)}}>
|
||||
<i className={`iconfont mr5 ${isOpen? "font-18 icon-sanjiaoxing-down":"font-16 icon-triangle"}`}></i>
|
||||
<span className="color-grey-6 update-file-count">
|
||||
共有<span className="color-grey-3"> {data && data.files_count} 个文件 </span>被更改,包括
|
||||
{ data && data.total_addition ? <span className="color-green"> {data && data.total_addition} 次插入</span>:"" }
|
||||
{ data && data.total_addition && data.total_deletion ? " 和 ":""}
|
||||
{ data && data.total_deletion ? <span className="color-red"> {data && data.total_deletion} 次删除</span>:""}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
{isOpen && folderOpen}
|
||||
</AlignCenter>
|
||||
{
|
||||
files && files.length>0 &&
|
||||
<div>
|
||||
<div className="fileList">
|
||||
{
|
||||
files.map((item,key)=>{
|
||||
return(
|
||||
<div className="files" key={key}>
|
||||
<FlexAJ className="filesInfo" style={{cursor:item.isBin ? "default":"pointer"}} onClick={()=>showDown(item.flag,key,item.isBin)}>
|
||||
<a id= {`value${key}`} className="anchorPoint"></a>
|
||||
<FlexAJ className="filesInfo">
|
||||
<AlignCenter>
|
||||
{!item.isBin ? <i className={!item.flag?"iconfont icon-xiajiantou font-16 mr15 color-grey-9":"iconfont icon-youjiantou font-16 mr15 color-grey-9"}></i>:""}
|
||||
<i className="iconfont icon-wenjia font-16 mr8 color-grey-9"></i>
|
||||
<span>{item.name}</span>
|
||||
{!item.isBin ? <i className={!item.flag?"iconfont icon-sanjiaoxing-down color-grey-9 mt4":"iconfont icon-triangle font-15 color-grey-9"} onClick={()=>showDown(item.flag,key,item.isBin)}></i>:""}
|
||||
<span className="cursor-pointer" data-clipboard-text={item.name} onClick={()=>showDown(item.flag,key,item.isBin)}>{item.name}</span>
|
||||
<Tooltip
|
||||
title={copyfileTipTitle}
|
||||
onVisibleChange={()=>setCopyfileTipTitle("复制文件路径")}
|
||||
>
|
||||
<i className="iconfont icon-fuzhiicon ml6" onClick={()=>copyFileName(item.name)}></i>
|
||||
</Tooltip>
|
||||
</AlignCenter>
|
||||
<span>
|
||||
<Button className="mr20" onClick={()=>{history.push(`/${owner}/${projectsId}/tree/${truncateCommitId(item.sha)}/${item.name}`)}}>查看文件</Button>
|
||||
<span className="color-green">+{item.addition}</span>
|
||||
<span className="color-red ml20">-{item.deletion}</span>
|
||||
</span>
|
||||
<div className="see-file">
|
||||
<Tooltip placement="top" title={`${item.addition + item.deletion}处更改${item.addition + item.deletion > 0 && ":"} ${item.addition > 0 ? item.addition + "处添加" : ""}${item.addition > 0 && item.deletion > 0 ? "和" : ""}${item.deletion > 0 ? item.deletion + "处删除" : ""}`}>
|
||||
<Progress showInfo = {false} strokeColor = "#2DB44D" size="small" percent={item.addition/(item.addition+item.deletion)*100} />
|
||||
<span className="ml10">{item.addition+item.deletion}处</span>
|
||||
</Tooltip>
|
||||
<span className="see-file-btn" onClick={()=>{history.push(`/${owner}/${projectsId}${item.isDeleted ? `/commits/${truncateCommitId(parentsSha)}`:`/tree/${truncateCommitId(item.sha)}/${item.name}`}`)}}>查看文件</span>
|
||||
</div>
|
||||
</FlexAJ>
|
||||
{
|
||||
item.sections && item.sections.length >= 1 && !item.flag &&
|
||||
|
|
|
@ -18,4 +18,86 @@
|
|||
.pr_tags_closed{
|
||||
border:1px solid #FA6400;
|
||||
color: #FA6400;
|
||||
}
|
||||
.update-file-count{
|
||||
cursor: pointer;
|
||||
& .color-grey-3{
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.fileList{
|
||||
.sc-bxivhb{
|
||||
width: 55rem;
|
||||
overflow: hidden;
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
}
|
||||
.see-file{
|
||||
width: 14rem;
|
||||
.ml10{
|
||||
display: inline-block;
|
||||
width: 4.5rem;
|
||||
cursor: default;
|
||||
}
|
||||
span{
|
||||
width: 7%;
|
||||
}
|
||||
}
|
||||
.anchorPoint{
|
||||
position: relative;
|
||||
top: -5rem;
|
||||
display: block;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
.filesInfo{
|
||||
background: #FAFCFF;
|
||||
border-color:rgba(42, 97, 255, 0.23);
|
||||
.ant-progress-line {
|
||||
width: 5rem;
|
||||
}
|
||||
.ant-progress-inner{
|
||||
background-color: #D14A4A;
|
||||
}
|
||||
}
|
||||
.folders,.ant-anchor{
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
.folders{
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
left: 0px;
|
||||
top: 37px;
|
||||
color: #333333;
|
||||
width: 75rem;
|
||||
box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5);
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(153, 153, 153, 0.32);
|
||||
.ant-anchor-link-active > .ant-anchor-link-title {
|
||||
color: #466AFF;
|
||||
}
|
||||
.ant-anchor-link {
|
||||
padding: 0px;
|
||||
}
|
||||
.folderList{
|
||||
max-height: 275px;
|
||||
overflow:auto;
|
||||
.files{
|
||||
border: 0px;
|
||||
}
|
||||
.filesInfo {
|
||||
padding: 10px 18px 10px 15px;
|
||||
height: 55px;
|
||||
background: #FFF;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
&:hover{
|
||||
background: #F3F4F6;
|
||||
}
|
||||
.color-green,.color-red{
|
||||
width: 3%;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -152,13 +152,23 @@ form .ant-cascader-picker, form .ant-select {
|
|||
margin-top: 15px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.see-file-btn{
|
||||
color: #466AFF;
|
||||
cursor: pointer;
|
||||
}
|
||||
.filesInfo{
|
||||
padding:10px 15px;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
.filesInfo .cursor-pointer{
|
||||
cursor: pointer;
|
||||
}
|
||||
.filesContent{
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
.icon-fuzhiicon:hover{
|
||||
color: #466AFF;
|
||||
}
|
||||
.linesContent{
|
||||
display: flex;
|
||||
min-height: 30px;
|
||||
|
|
|
@ -65,16 +65,18 @@ class Index extends Component {
|
|||
<FileLanguage language={language} select_language={this.select_language}></FileLanguage>
|
||||
</div>
|
||||
</div>
|
||||
<Meditor
|
||||
{...this.props}
|
||||
{...this.state}
|
||||
filepath={`${file_path}`}
|
||||
language = {language}
|
||||
content={undefined}
|
||||
readOnly={false}
|
||||
editorType="new"
|
||||
descName={filename && `Add ${filename}`}
|
||||
></Meditor>
|
||||
<div className="editorBorder">
|
||||
<Meditor
|
||||
{...this.props}
|
||||
{...this.state}
|
||||
filepath={`${file_path}`}
|
||||
language = {language}
|
||||
content={undefined}
|
||||
readOnly={false}
|
||||
editorType="new"
|
||||
descName={filename && `Add ${filename}`}
|
||||
></Meditor>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
|
|
|
@ -8,7 +8,13 @@
|
|||
border: 1px solid #d9d9d9!important;
|
||||
border-right: none!important;
|
||||
}
|
||||
|
||||
.editorBorder .editorBorderBox{
|
||||
border:1px solid #eee;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.editorBorder .editorBorderSubmitBox{
|
||||
padding:20px 0px!important;
|
||||
}
|
||||
.userScrew{
|
||||
margin:20px 0px;
|
||||
border:1px solid #f4f4f4;
|
||||
|
@ -39,7 +45,7 @@
|
|||
z-index: 1;
|
||||
}
|
||||
.ant-input-group .ant-input:focus{
|
||||
border-right: 1px solid #d9d9d9!important;
|
||||
border-right: 1px solid rgba(70, 106, 255, 1)!important;
|
||||
}
|
||||
.ant-btn-primary.grey{
|
||||
border:1px solid #BBBBBB;
|
||||
|
|
|
@ -10,6 +10,7 @@ class m_editor extends Component {
|
|||
super(props);
|
||||
this.state = {
|
||||
editorValue: this.props.content,
|
||||
prevHeight:0
|
||||
};
|
||||
}
|
||||
componentDidUpdate=(prevProps)=>{
|
||||
|
@ -41,42 +42,81 @@ class m_editor extends Component {
|
|||
folding: true,
|
||||
foldingStrategy: "indentation", // 代码可分小段折叠
|
||||
automaticLayout: true, // 自适应布局
|
||||
// overviewRulerBorder: false, // 不要滚动条的边框
|
||||
// scrollBeyondLastLine: false, // 取消代码后面一大段空白
|
||||
overviewRulerBorder: false, // 不要滚动条的边框
|
||||
scrollBeyondLastLine: false, // 取消代码后面一大段空白
|
||||
minimap: {
|
||||
// 不要小地图
|
||||
enabled: false,
|
||||
},
|
||||
};
|
||||
|
||||
const handleEditorMount = (editor, monaco) => {
|
||||
editor.onDidChangeModelDecorations(() => {
|
||||
requestAnimationFrame(updateEditorHeight); // folding
|
||||
});
|
||||
|
||||
const updateEditorHeight = () => {
|
||||
const editorElement = editor.getDomNode();
|
||||
|
||||
if (!editorElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const padding = 40;
|
||||
|
||||
const lineHeight = editor.getOption(
|
||||
monaco.editor.EditorOption.lineHeight
|
||||
);
|
||||
|
||||
const lineCount = editor.getModel().getLineCount() || 1;
|
||||
let height =
|
||||
editor.getTopForLineNumber(lineCount + 1) +
|
||||
lineHeight +
|
||||
padding ;
|
||||
|
||||
if(height<400){height = 400;}
|
||||
|
||||
if (this.state.prevHeight !== height) {
|
||||
this.setState({
|
||||
prevHeight:height
|
||||
})
|
||||
// setPrevHeight(height);
|
||||
editorElement.style.height = `${height}px`;
|
||||
editor.layout();
|
||||
}
|
||||
};
|
||||
|
||||
updateEditorHeight(); // typing
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div>
|
||||
<div className="branchTable" style={{border:"1px solid #eee"}}>
|
||||
<Editor
|
||||
height="400px"
|
||||
language={language ? language : "plaintext"}
|
||||
theme={"vs-grey"}
|
||||
placeholder="请输入内容"
|
||||
value={editorValue}
|
||||
options={editor_options}
|
||||
onChange={this.changeEditor}
|
||||
editorWillMount={this.editorWillMount}
|
||||
/>
|
||||
</div>
|
||||
{!readOnly && (
|
||||
<div style={{marginTop:"20px",padding:"20px"}}>
|
||||
<UserSubmitComponent
|
||||
{...this.props}
|
||||
{...this.state}
|
||||
filepath={`${this.props.filepath}`}
|
||||
content={editorValue}
|
||||
editor_type={editorType}
|
||||
currentBranch={currentBranch}
|
||||
descName={descName}
|
||||
></UserSubmitComponent>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="editorBorderBox">
|
||||
<Editor
|
||||
language={language ? language : "plaintext"}
|
||||
theme={"vs-grey"}
|
||||
placeholder="请输入内容"
|
||||
value={editorValue}
|
||||
options={editor_options}
|
||||
onChange={this.changeEditor}
|
||||
editorWillMount={this.editorWillMount}
|
||||
editorDidMount={handleEditorMount}
|
||||
/>
|
||||
</div>
|
||||
{!readOnly && (
|
||||
<div className="editorBorderSubmitBox" style={{marginTop:"20px",padding:"20px"}}>
|
||||
<UserSubmitComponent
|
||||
{...this.props}
|
||||
{...this.state}
|
||||
filepath={`${this.props.filepath}`}
|
||||
content={editorValue}
|
||||
editor_type={editorType}
|
||||
currentBranch={currentBranch}
|
||||
descName={descName}
|
||||
></UserSubmitComponent>
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ const menu = [
|
|||
{name:"合并请求",index:"pulls"},
|
||||
{name:"Wiki",index:"wiki"},
|
||||
{name:"工作流(beta版)",index:"devops"},
|
||||
{name:"资源库",index:"resources"},
|
||||
// {name:"资源库",index:"resources"},
|
||||
{name:"里程碑",index:"versions"},
|
||||
{name:"动态",index:"activity"},
|
||||
]
|
||||
|
|
|
@ -87,7 +87,7 @@ export default Form.create()(
|
|||
}
|
||||
],
|
||||
<Input
|
||||
addonBefore={`https://`+ port ? `${hostname}:${port}/organize`:`${hostname}/organize`}
|
||||
addonBefore={port ? `${hostname}:${port}/`:`https://${hostname}/`}
|
||||
placeholder="组织账号" maxLength={100}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -122,7 +122,7 @@ export default Form.create()(
|
|||
validator:checkname
|
||||
}
|
||||
],
|
||||
<Input placeholder="请输入组织账号" maxLength={100} disabled/>,true
|
||||
<Input placeholder="请输入组织账号" disabled/>,true
|
||||
)}
|
||||
{helper(
|
||||
"组织名称:",
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React, { Component } from "react";
|
||||
import { Upload, Icon , Button } from 'antd';
|
||||
import { getUploadActionUrl, appendFileSizeToUploadFileAll } from 'educoder';
|
||||
import { AlignCenter } from '../Component/layout';
|
||||
|
||||
import axios from 'axios';
|
||||
const { Dragger } = Upload;
|
||||
|
@ -64,7 +63,6 @@ class Index extends Component {
|
|||
changeIsComplete && changeIsComplete(true);
|
||||
if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
|
||||
let fileList = info.fileList;
|
||||
|
||||
this.setState({ fileList: appendFileSizeToUploadFileAll(fileList) });
|
||||
this.fileIdList(fileList);
|
||||
}
|
||||
|
@ -111,7 +109,7 @@ class Index extends Component {
|
|||
:
|
||||
<Dragger {...upload} className={className}>
|
||||
{icon || <Icon type="inbox" />}
|
||||
<p className="ant-upload-text font-14">拖动文件或<span className="color-blue">点击此处上传</span></p>
|
||||
<p className="ant-upload-text font-16 color-grey-3">拖动文件或点击此处上传</p>
|
||||
</Dragger>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
|
||||
1.请求URL: https://code.ihub.org.cn/api/v1/mirrors/create.json
|
||||
|
||||
2.请求方式: POST
|
||||
|
||||
3.参数:
|
||||
|
||||
{
|
||||
"image_url": "xxx.git", #必填,且后缀必为.git,
|
||||
"language": "Ruby", #必填,如数据库不存在,则会创建新的记录
|
||||
}
|
||||
|
||||
|
||||
4. 返回值: {
|
||||
"status": 1,
|
||||
"message": "同步成功,项目ID===1806"
|
||||
}
|
||||
|
||||
5. 返回值说明: 仅有当有返回值,且返回值的status 的值为1, 才是创建成功,其余均为创建失败
|
||||
|
||||
|
|
@ -1,278 +0,0 @@
|
|||
import React, { useState, useEffect, useCallback, forwardRef } from "react";
|
||||
import styled from "styled-components";
|
||||
import { AutoComplete, Select, Input, Checkbox, Button, Form } from "antd";
|
||||
|
||||
import Editor from "../../modules/tpm/challengesnew/tpm-md-editor";
|
||||
import Upload from "../Upload/Index";
|
||||
import Attachments from "../Upload/attachment";
|
||||
import axios from "axios";
|
||||
import "./version.css";
|
||||
import UploadImg from "../Images/upload.png";
|
||||
import { getBranch } from '../GetData/getData';
|
||||
|
||||
const { Option } = AutoComplete;
|
||||
|
||||
export default Form.create()(
|
||||
forwardRef(
|
||||
(
|
||||
{ form, projectDetail , match, showNotification, history },
|
||||
ref
|
||||
) => {
|
||||
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||
const [tagList, setTagList] = useState(undefined);
|
||||
const [branchList, setBranchList] = useState(undefined);
|
||||
const [desc, setDesc] = useState(null);
|
||||
const [fileList, setFileList] = useState(undefined);
|
||||
const [attachment, setAttachment] = useState(undefined);
|
||||
const [options , setOptions] = useState(undefined);
|
||||
|
||||
|
||||
const repo_id = projectDetail && projectDetail.repo_id;
|
||||
const { projectsId, versionId , owner } = match.params;
|
||||
useEffect(()=>{
|
||||
getBranchs(projectsId,owner);
|
||||
},[projectsId])
|
||||
|
||||
async function getBranchs(id,owner){
|
||||
let result = await getBranch(id,owner);
|
||||
setBranchList(result);
|
||||
}
|
||||
|
||||
const Span = styled.span`
|
||||
margin: 0px 15px;
|
||||
color: #bbb;
|
||||
line-height: 35px;
|
||||
`;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (versionId) {
|
||||
const url = `/${owner}/${projectsId}/releases/${versionId}/edit.json`;
|
||||
axios.get(url).then(result => {
|
||||
if (result) {
|
||||
setFieldsValue(result.data);
|
||||
setDesc(result.data.body);
|
||||
setAttachment(result.data.attachments);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [versionId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (projectsId) {
|
||||
const url = `/${owner}/${projectsId}/tags.json`;
|
||||
axios
|
||||
.get(url,{params:{
|
||||
limit:1000
|
||||
}})
|
||||
.then(result => {
|
||||
if (result) {
|
||||
setTagList(result.data);
|
||||
setOptions(renderTagList(result.data));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
}, [projectsId]);
|
||||
|
||||
function renderTagList(list) {
|
||||
if (list) {
|
||||
let array = list.map((item, key) => {
|
||||
return (
|
||||
<Option key={key} value={item.name}>
|
||||
{item.name}
|
||||
</Option>
|
||||
);
|
||||
});
|
||||
return array || undefined;
|
||||
}
|
||||
}
|
||||
function submit() {
|
||||
validateFields((err, value) => {
|
||||
if(err)return;
|
||||
if (versionId) {
|
||||
let url = `/${owner}/${projectsId}/releases/${versionId}.json`;
|
||||
axios
|
||||
.put(url, {
|
||||
...value,
|
||||
body: desc,
|
||||
attachment_ids: fileList
|
||||
})
|
||||
.then(result => {
|
||||
if (result) {
|
||||
showNotification("版本修改成功!");
|
||||
history.push(`/${owner}/${projectsId}/releases`);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
let url = `/${owner}/${projectsId}/releases.json`;
|
||||
axios.post(url, {
|
||||
...value,
|
||||
body: desc,
|
||||
attachment_ids: fileList
|
||||
})
|
||||
.then(result => {
|
||||
if (result) {
|
||||
showNotification("版本发布成功!");
|
||||
history.push(`/${owner}/${projectsId}/releases`);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget, isRequired = true) => (
|
||||
<React.Fragment>
|
||||
<span required={isRequired}>{label}</span>
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
</Form.Item>
|
||||
</React.Fragment>
|
||||
),
|
||||
[]
|
||||
);
|
||||
// 输入标签名
|
||||
function changeAuto(value){
|
||||
let l = tagList.filter(item=>item.name.indexOf(value) > -1);
|
||||
setOptions(renderTagList(l));
|
||||
}
|
||||
return (
|
||||
<div className="main df">
|
||||
<Form className="versionForm">
|
||||
<div>
|
||||
<p className="font-16 color-grey-3 mb15">{versionId?"编辑":"创建"}发行版</p>
|
||||
<div>
|
||||
<div className="itemInline">
|
||||
{helper(
|
||||
"",
|
||||
"tag_name",
|
||||
[{ required: true, message: "请输入获取或选择一个标签" }],
|
||||
<AutoComplete
|
||||
placeholder="标记一个版本"
|
||||
onChange={changeAuto}
|
||||
style={{ width: "200px" }}
|
||||
>
|
||||
{options}
|
||||
</AutoComplete>
|
||||
)}
|
||||
<Span>@</Span>
|
||||
{helper(
|
||||
"",
|
||||
"target_commitish",
|
||||
[{ required: true, message: "请选择一个分支" }],
|
||||
<Select
|
||||
placeholder="请选择一个分支"
|
||||
style={{ width: "200px" }}
|
||||
showArrow={false}
|
||||
>
|
||||
{renderTagList(branchList)}
|
||||
</Select>
|
||||
)}
|
||||
</div>
|
||||
<p className="font-13 color-grey-8">
|
||||
选择一个已经存在的标签,或者在发布时新建一个标签
|
||||
</p>
|
||||
</div>
|
||||
<div className="pt20">
|
||||
{helper(
|
||||
"",
|
||||
"name",
|
||||
[{ required: true, message: "请输入发行版的标题" }],
|
||||
<Input placeholder="发行版的标题" />
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<Editor
|
||||
placeholder={"描述此发行版"}
|
||||
height={200}
|
||||
mdID={`version-comments-description`}
|
||||
initValue={desc}
|
||||
onChange={setDesc}
|
||||
/>
|
||||
</div>
|
||||
<div className="set-ant-row">
|
||||
{helper(
|
||||
"",
|
||||
"prerelease",
|
||||
[],
|
||||
<Checkbox>这是一个预览版本</Checkbox>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<Upload
|
||||
className="versionStyle"
|
||||
isComplete={true}
|
||||
load={setFileList}
|
||||
icon={
|
||||
<img
|
||||
src={UploadImg}
|
||||
width="58"
|
||||
alt=""
|
||||
style={{ marginBottom: 15 }}
|
||||
/>
|
||||
}
|
||||
size={100}
|
||||
showNotification={showNotification}
|
||||
/>
|
||||
{versionId && attachment && attachment.length > 0 ? (
|
||||
<Attachments
|
||||
attachments={attachment}
|
||||
showNotification={showNotification}
|
||||
canDelete={true}
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</div>
|
||||
<p className="pt20">
|
||||
<Button onClick={submit} type="primary" className="mr30">
|
||||
{versionId ? "保存" : "创建"}发行版
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() =>
|
||||
history.push(`/${owner}/${projectsId}/releases`)
|
||||
}
|
||||
style={{
|
||||
backgroundColor: "rgba(187,187,187,1)",
|
||||
color: "#fff"
|
||||
}}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
</p>
|
||||
</div>
|
||||
</Form>
|
||||
<div className="versionTips">
|
||||
<div className="infosTip">
|
||||
<p className="font-16 mb15">标签命名建议</p>
|
||||
<p className="mb15">
|
||||
通常的做法是在版本名称前加上字母 v 前缀, v1.0 或者 v2.3.4。
|
||||
</p>
|
||||
<p>
|
||||
如果标签不适合在生产环境下使用,请在版本名称后添加预发行版本。例如:v0.2-alpha
|
||||
或者 v5.9-beta.3。
|
||||
</p>
|
||||
</div>
|
||||
<div className="infosTip">
|
||||
<p className="font-16 mb15">语义化版本</p>
|
||||
<p className="mb15">
|
||||
如果你是第一次发布版本,我们强烈建议你阅读语义化版本。
|
||||
</p>
|
||||
</div>
|
||||
<div className="infosTip">
|
||||
<p className="font-16 mb15">附件大小说明</p>
|
||||
<p className="mb15">
|
||||
单个附件不能超过 100M(GVP 项目200M),每个仓库总附件不可超过
|
||||
1G(推荐项目不可超过 5G;GVP 项目不可超过
|
||||
20G)。附件总容量统计包括仓库附件和发行版附件。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
|
@ -1,205 +0,0 @@
|
|||
.topWrapper {
|
||||
padding: 20px 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
align-items: center;
|
||||
}
|
||||
.topWrapper_btn_new {
|
||||
background: #fff;
|
||||
color: #5091FF!important;
|
||||
padding:0px 12px;
|
||||
text-align: center;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
border:1px solid #5091FF;
|
||||
}
|
||||
.versionInfo{
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.versionInfo_left{
|
||||
display: flex;
|
||||
width: 30%;
|
||||
padding-top: 20px;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
padding-right: 15px;
|
||||
}
|
||||
.versionInfo_right{
|
||||
flex: 1;
|
||||
padding: 20px 0px 20px 15px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
.versionTag{
|
||||
display: inline;
|
||||
border-radius: 2px;
|
||||
padding:2px 12px;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
}
|
||||
.versionTag.yellow{
|
||||
background-color: #FBBC06;
|
||||
}
|
||||
.versionTag.green{
|
||||
background-color: #20BA45;
|
||||
}
|
||||
.versionTag.orange{
|
||||
background-color: #F2711D;
|
||||
}
|
||||
.versionName{
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
position: relative;
|
||||
}
|
||||
.versionName::before{
|
||||
position: absolute;
|
||||
left: -19px;
|
||||
top:8px;
|
||||
content: '';
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: #5091FF;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
|
||||
.versionmilepostleft{
|
||||
padding: 15px;
|
||||
margin-right: 50px;
|
||||
width: 80%;
|
||||
}
|
||||
.topWrapper_btn_close {
|
||||
background: #504b4b;
|
||||
color: #FFFFFF!important;
|
||||
padding:0px 12px;
|
||||
text-align: center;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.topWrapper_btn_delete {
|
||||
background: #da1010;
|
||||
color: #FFFFFF!important;
|
||||
padding:0px 12px;
|
||||
text-align: center;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.versionrighe{
|
||||
flex: 2;
|
||||
}
|
||||
.versionleft{
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
}
|
||||
|
||||
/* .version_line{
|
||||
display: flex;
|
||||
height: 30px;
|
||||
margin: auto;
|
||||
border-left:1px solid #eee;
|
||||
} */
|
||||
.version_line_one{
|
||||
display: flex;
|
||||
height: 45px;
|
||||
margin: auto;
|
||||
border-left:1px solid #eee;
|
||||
}
|
||||
|
||||
.version_line_tpw{
|
||||
display: flex;
|
||||
height: 80px;
|
||||
margin: auto;
|
||||
border-left:1px solid #eee;
|
||||
}
|
||||
|
||||
.versiondiv{
|
||||
display: flex;
|
||||
}
|
||||
.verwinth{
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
/*开启中 关闭中*/
|
||||
.opendversionetail{
|
||||
display: inline-block;
|
||||
background: #21ba45;
|
||||
color: #ffffff!important;
|
||||
padding:0px 5px;
|
||||
text-align: center;
|
||||
height: 25px;
|
||||
/*width: 110px;*/
|
||||
border-radius: 4px;
|
||||
line-height: 25px;
|
||||
}
|
||||
.closedversionetail{
|
||||
display: inline-block;
|
||||
background: #e60b0b;
|
||||
color: #ffffff!important;
|
||||
padding:0px 5px;
|
||||
text-align: center;
|
||||
height: 25px;
|
||||
/*width: 110px;*/
|
||||
border-radius: 4px;
|
||||
line-height: 25px;
|
||||
}
|
||||
.versionrectangle {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 100%;
|
||||
margin-top: 15px;
|
||||
margin-left: -4px;
|
||||
margin-bottom: 10px;
|
||||
background: rgb(83, 81, 81);
|
||||
}
|
||||
.ver-middle{
|
||||
vertical-align: middle;
|
||||
}
|
||||
/* new */
|
||||
.versionForm{
|
||||
flex:1;
|
||||
padding-right: 30px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.versionTips{
|
||||
width:30%;
|
||||
padding-left: 15px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.infosTip{
|
||||
padding:20px;
|
||||
background-color: #F1F8FF;
|
||||
margin-bottom: 22px;
|
||||
color: #333;
|
||||
}
|
||||
.versionStyle{
|
||||
height: 200px!important;
|
||||
border: 1px dashed rgba(80,145,255,1)!important;
|
||||
}
|
||||
.set-ant-row .ant-row{
|
||||
display: flex;
|
||||
height: 20px;
|
||||
align-items: center;
|
||||
}
|
||||
.itemInline{
|
||||
display: flex;
|
||||
align-item: center;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.itemInline .ant-row{
|
||||
margin-bottom: 0px;
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
import React, { Component } from "react";
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Spin } from 'antd';
|
||||
import NoneData from '../Nodata';
|
||||
import './version.css';
|
||||
import axios from 'axios';
|
||||
import RenderHtml from '../../components/render-html';
|
||||
|
||||
/**
|
||||
* issue_chosen:下拉的筛选列表,
|
||||
* data:列表接口返回的所有数据,
|
||||
* issues:列表数组,
|
||||
* isSpin:加载中,
|
||||
*/
|
||||
class version extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
issue_chosen: undefined,
|
||||
data: undefined,
|
||||
releases:undefined,
|
||||
issues: undefined,
|
||||
isSpin: true,
|
||||
search: undefined,
|
||||
search_count: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
this.getIssueList();
|
||||
}
|
||||
// 获取列表数据
|
||||
getIssueList = () => {
|
||||
const { projectsId, owner } = this.props.match.params;
|
||||
const url = `/${owner}/${projectsId}/releases.json`;
|
||||
axios.get(url).then((result) => {
|
||||
if (result) {
|
||||
this.setState({
|
||||
data: result.data,
|
||||
releases:result.data.releases,
|
||||
issues: result.data.issues,
|
||||
isSpin: false
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
// 显示版本描述
|
||||
showBody=(key,flag)=>{
|
||||
let { releases } = this.state;
|
||||
releases[key].bodyshow = !flag;
|
||||
this.setState({
|
||||
releases
|
||||
})
|
||||
}
|
||||
|
||||
renderList = (releases) => {
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
const { isManager , isDeveloper } = this.props;
|
||||
const type = this.props.projectDetail && this.props.projectDetail.type;
|
||||
|
||||
if (releases && releases.length > 0) {
|
||||
return (
|
||||
releases.map((item, key) => {
|
||||
return (
|
||||
<div className="versionInfo" key={key}>
|
||||
<span className="versionInfo_left">
|
||||
<span className={`${item.draft === "稳定" ?"versionTag green":"versionTag yellow"}`}>{item.draft}</span>
|
||||
<span className="mt10">{item.created_at}</span>
|
||||
<span className="color-grey-8">
|
||||
<i className="iconfont icon-biaoqian3 mr3 font-14"></i>
|
||||
{item.tag_name}
|
||||
</span>
|
||||
</span>
|
||||
<div className="versionInfo_right">
|
||||
<span className="versionName">
|
||||
<span className="task-hide">{item.name}</span>
|
||||
{
|
||||
(isManager || isDeveloper) && type !==2 &&
|
||||
<Link to={`/${owner}/${projectsId}/releases/${item.version_id}/update`} className="color-blue ml3 font-12">(编辑)</Link>
|
||||
}
|
||||
</span>
|
||||
<span className="color-grey-3">
|
||||
<i className={`${item.bodyshow ? "iconfont icon-sanjiaoxing-down color-grey-8 mr3 font-14":"iconfont icon-triangle color-grey-8 mr3 font-14"}`} onClick={()=>this.showBody(key,item.bodyshow)}></i>
|
||||
{item.user_name}:<span className="color-grey-8">发布了这个版本,并在发布后提交给{item.target_commitish}</span>
|
||||
</span>
|
||||
{
|
||||
item.bodyshow && <RenderHtml className="break_word_comments imageLayerParent" value={item.body} url={this.props.history.location}/>
|
||||
}
|
||||
<RenderHtml />
|
||||
<p className="mt10 pl3">
|
||||
<a href={item.tarball_url} style={{color:"#4CC1DA"}} className="mr30"><i className="iconfont icon-TAR font-18 mr5"></i>TAR</a>
|
||||
<a href={item.zipball_url} style={{color:"#28BD6C"}}><i className="iconfont icon-ZIP font-18 mr5"></i>ZIP</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)
|
||||
} else if (releases && releases.length === 0) {
|
||||
return ( <NoneData _html="暂时还没有相关数据!" /> )
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { projectsId ,owner } = this.props.match.params;
|
||||
const { data , releases , isSpin } = this.state;
|
||||
const type = this.props.projectDetail && this.props.projectDetail.type;
|
||||
return (
|
||||
<div className="main" style={{padding:"0px"}}>
|
||||
<div className="topWrapper" style={{padding:"15px 20px"}}>
|
||||
<span className="font-18 color-grey-3">版本发布</span>
|
||||
{
|
||||
data && data.user_permission && type !== 2 ?
|
||||
<Link to={`/${owner}/${projectsId}/releases/new`} className="topWrapper_btn_new">+ 发布新版</Link>
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
<div className="releasesVersion">
|
||||
<Spin spinning={isSpin}><div>{this.renderList(releases)}</div></Spin>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
export default version;
|
|
@ -6,3 +6,11 @@ export function truncateCommitId(str) {
|
|||
return str
|
||||
}
|
||||
}
|
||||
|
||||
// 秒数转2021-9-29 01:01
|
||||
export function timeFormat(SecondsStr){
|
||||
const time = new Date(SecondsStr*1000);
|
||||
const hour = time.getHours()<10?"0".concat(time.getHours()):time.getHours();
|
||||
const minutes = time.getMinutes()<10?"0".concat(time.getMinutes()):time.getMinutes();
|
||||
return time.getFullYear()+"-"+(time.getMonth()+1)+"-"+time.getDate()+" "+hour+":"+minutes;
|
||||
}
|
|
@ -88,14 +88,23 @@ ul,ol,dl{
|
|||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
&>span, & a:link, a:visited{
|
||||
color: #333;
|
||||
}
|
||||
&>span{
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
.commitDesc{
|
||||
flex:1;
|
||||
margin-left:20px;
|
||||
font-size:16px;
|
||||
color:#333;
|
||||
line-height:26px;
|
||||
line-height:20px;
|
||||
word-break: break-all;
|
||||
width: 49rem;
|
||||
overflow: hidden;
|
||||
white-space: normal;
|
||||
&:hover{
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.normalBox{
|
||||
|
@ -143,7 +152,7 @@ form.ant-form{
|
|||
}
|
||||
form{
|
||||
.ant-row.ant-form-item{
|
||||
margin-bottom: 15px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 1000px){
|
||||
|
@ -285,4 +294,50 @@ form{
|
|||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.btn-83{
|
||||
width: 83px;
|
||||
height: 32px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
background: #FAFBFC;
|
||||
border: 1px solid #D0D0D0;
|
||||
display: inline-block;
|
||||
border-radius: 5px;
|
||||
font-weight: 500;
|
||||
color: #333333!important;
|
||||
margin-right: 15px;
|
||||
&:hover{
|
||||
background: #F3F4F6;
|
||||
color: #333333!important;
|
||||
}
|
||||
&:active{
|
||||
background: #D0D0D0;
|
||||
color: #333333!important;
|
||||
}
|
||||
}
|
||||
.shadow:hover{
|
||||
background: #eeeff1;
|
||||
border-bottom-left-radius: 4px;
|
||||
border-top-left-radius: 4px;
|
||||
}
|
||||
a.hover:hover{
|
||||
text-decoration: underline;
|
||||
}
|
||||
button.ant-btn-primary.btnblue{
|
||||
background-color:rgba(70, 106, 255, 1);
|
||||
border-color:rgba(70, 106, 255, 1);
|
||||
&:hover{
|
||||
background-color:rgba(70, 106, 255, 0.85);
|
||||
border-color:rgba(70, 106, 255, 0.85);
|
||||
}
|
||||
}
|
||||
button.btngrey{
|
||||
background-color:#FFFFFF;
|
||||
border-color:#D0D0D0;
|
||||
color: #666666;
|
||||
&:hover,&:focus{
|
||||
border-color:rgba(153, 153, 153, 0.5);
|
||||
color: #666666;
|
||||
}
|
||||
}
|
|
@ -30,11 +30,11 @@
|
|||
|
||||
.ant-upload-list-item-info .anticon-loading,
|
||||
.ant-upload-list-item-info .anticon-paper-clip {
|
||||
color: #29bd8b !important;
|
||||
color: rgba(102, 102, 102, 1) !important;
|
||||
}
|
||||
|
||||
.anticon anticon-paper-clip {
|
||||
color: #29bd8b !important;
|
||||
color: rgba(102, 102, 102, 1) !important;
|
||||
}
|
||||
|
||||
.MuiModal-root-15 {
|
||||
|
|
|
@ -53,8 +53,6 @@ class CompetitionContentspdfpeopledata extends Component {
|
|||
let url = `/users/accounts/${id}.json`;
|
||||
axios.get(url).then((result) => {
|
||||
if (result.data) {
|
||||
console.log("GetuseridApi");
|
||||
console.log(result.data);
|
||||
this.setState({
|
||||
userdata:result.data
|
||||
})
|
||||
|
|
|
@ -938,7 +938,7 @@ body #root {
|
|||
}
|
||||
|
||||
.ant-input:focus {
|
||||
border: 1px solid #d9d9d9 !important;
|
||||
border: 1px solid rgba(70, 106, 255, 1) !important;
|
||||
}
|
||||
|
||||
/* 公用的文字按钮:蓝、白、灰 */
|
||||
|
@ -1423,7 +1423,7 @@ samp {
|
|||
}
|
||||
|
||||
.newcourses .ant-select-selection--single:hover {
|
||||
border: 1px solid #d9d9d9 !important;
|
||||
border: 1px solid rgba(70, 106, 255, 1) !important;
|
||||
}
|
||||
|
||||
.pd20 {
|
||||
|
@ -1528,9 +1528,6 @@ samp {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.exerciselist .ant-input {
|
||||
border: 1px solid #d9d9d9 !important;
|
||||
}
|
||||
|
||||
.exercisetime .ant-form-explain {
|
||||
margin-left: 107px;
|
||||
|
@ -1689,18 +1686,12 @@ samp {
|
|||
height: 40px;
|
||||
}
|
||||
|
||||
.ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled) {
|
||||
border: 1px solid #d9d9d9 !important;
|
||||
}
|
||||
|
||||
.ant-input-affix-wrapper .ant-input-prefix,
|
||||
.ant-input-affix-wrapper .ant-input-suffix {
|
||||
background: #fafafa !important;
|
||||
}
|
||||
|
||||
.ant-input:hover {
|
||||
border: 1px solid #d9d9d9 !important;
|
||||
}
|
||||
|
||||
.ant-input:focus {
|
||||
box-shadow: none !important;
|
||||
|
|
|
@ -11,9 +11,6 @@
|
|||
.ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled){
|
||||
border:1px solid #d9d9d9!important;
|
||||
}
|
||||
.ant-input:hover{
|
||||
border:1px solid #d9d9d9!important;
|
||||
}
|
||||
.ant-input:focus{
|
||||
box-shadow:none!important;
|
||||
background-color: #fff!important;
|
||||
|
|
|
@ -163,7 +163,6 @@ body>.-task-title {
|
|||
outline: 0;
|
||||
-webkit-box-shadow: 0 0 0 2px transparent;
|
||||
box-shadow: 0 0 0 2px transparent;
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.HeaderSearch .ant-input-search .ant-input::-webkit-input-placeholder {
|
||||
|
|
Loading…
Reference in New Issue