Merge pull request '代码库二级页面改版(部分)' (#71) from caishi/forgeplus-react:feature_repo_second_page into feature_repo_second_page

This commit is contained in:
jasder 2021-09-22 09:35:04 +08:00
commit 465ae57b07
85 changed files with 2846 additions and 2747 deletions

File diff suppressed because it is too large Load Diff

14
package-lock.json generated
View File

@ -4885,7 +4885,7 @@
},
"dom-closest": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/dom-closest/-/dom-closest-0.2.0.tgz",
"resolved": "https://registry.npm.taobao.org/dom-closest/download/dom-closest-0.2.0.tgz",
"integrity": "sha1-69n5HRvyLo1vR3h2u80+yQIWwM8=",
"requires": {
"dom-matches": ">=1.0.1"
@ -4929,7 +4929,7 @@
},
"dom-matches": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-matches/-/dom-matches-2.0.0.tgz",
"resolved": "https://registry.npm.taobao.org/dom-matches/download/dom-matches-2.0.0.tgz",
"integrity": "sha1-0nKLQWqHUzmA6wibhI0lPPI6dYw="
},
"dom-scroll-into-view": {
@ -5187,7 +5187,7 @@
},
"enquire.js": {
"version": "2.1.6",
"resolved": "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz",
"resolved": "https://registry.npm.taobao.org/enquire.js/download/enquire.js-2.1.6.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fenquire.js%2Fdownload%2Fenquire.js-2.1.6.tgz",
"integrity": "sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ="
},
"entities": {
@ -5706,7 +5706,7 @@
},
"eventlistener": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/eventlistener/-/eventlistener-0.0.1.tgz",
"resolved": "https://registry.npm.taobao.org/eventlistener/download/eventlistener-0.0.1.tgz",
"integrity": "sha1-7Suqu4UiJ68rz4iRUscsY8pTLrg="
},
"events": {
@ -8040,7 +8040,7 @@
},
"hammerjs": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
"resolved": "https://registry.npm.taobao.org/hammerjs/download/hammerjs-2.0.8.tgz",
"integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE="
},
"handle-thing": {
@ -8881,7 +8881,7 @@
},
"immutable": {
"version": "3.7.6",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz",
"resolved": "https://registry.npm.taobao.org/immutable/download/immutable-3.7.6.tgz",
"integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks="
},
"import-fresh": {
@ -10486,7 +10486,7 @@
},
"lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"resolved": "https://registry.npm.taobao.org/lodash.throttle/download/lodash.throttle-4.1.1.tgz",
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
},
"lodash.uniq": {

View File

@ -193,6 +193,7 @@
"babel-core": "^6.26.0",
"babel-plugin-import": "^1.13.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",

View File

@ -114,14 +114,6 @@ a:visited {
color: #898989;
}
a:hover {
color: #FF7500;
}
a:hover.fa {
color: #FF7500;
}
input,
textarea,
select {

View File

@ -97,10 +97,6 @@ a:visited {
color: #05101a;
}
a:hover {
color: #459be5;
}
ol,
ul,
li {

View File

@ -1,3 +1,4 @@
@charset "utf-8";
/* 头部 */
.header {
width: 100%;
@ -1271,7 +1272,7 @@ html body {
font-size: 14px;
line-height: 2.0;
background: #fafafa;
font-family: "微软雅黑", "宋体";
font-family: "Microsoft YaHei", "SimSun";
color: #05101a;
height: 100%;
position: relative;
@ -1307,6 +1308,7 @@ td,
span {
margin: 0;
padding: 0;
margin-bottom: 0px!important;
}
table,
@ -1363,10 +1365,6 @@ a:visited {
color: #05101a;
}
a:hover {
color: #459be5;
}
ol,
ul,
li {
@ -1473,7 +1471,7 @@ a.edu-txt-w80,
/*隐藏*/
.none {
display: none
display: none!important;
}
.block {
@ -1522,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;
}
@ -1542,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;
@ -1563,6 +1572,9 @@ a.edu-txt-w80,
font-size: 36px !important;
}
.font-40 {
font-size: 40px !important;
}
.font-50 {
font-size: 50px !important;
}
@ -2436,7 +2448,11 @@ a.hoverLine:hover{
.color-grey-9 {
color: #999999 !important;
color: #333333 !important;
}
a:hover{
color: #466AFF !important;
}
.color-grey-98 {
@ -2458,7 +2474,7 @@ a.hoverLine:hover{
.color-grey-B3 {
color: #B3B3B3 !important;
}
`
.color-grey-B4 {
color: #B4B4B4 !important;
}
@ -2471,33 +2487,23 @@ a.hoverLine:hover{
a.color-grey-name:hover,
a.color-dark:hover,
a.color-grey-6:hover,
a.color-grey-3:hover {
color: #4cacff !important;
}
a.color-grey-9:hover,
a.color-grey-8:hover,
a.color-grey-c:hover {
color: #111C24 !important;
a.color-grey-3:hover,a.color-ooo:hover {
color: #2A61FF !important;
}
/*蓝色*/
.color-blue {
color: #4CACFF !important;
color: #2A61FF !important;
}
.color-blue-file {
color: #4598FA!important;
}
/* 绿色 */
.color-green-file{
color: #28BD6C;
}
/*主*/
.color-blue_4C {
color: #4CACFF !important;
}
a.color-blue:hover,
a.color-blue_4C:hover {
color: #459BE6 !important;
}
/*橙色*/
.color-orange {

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 2340181 */
src: url('iconfont.woff2?t=1630632852475') format('woff2'),
url('iconfont.woff?t=1630632852475') format('woff'),
url('iconfont.ttf?t=1630632852475') format('truetype');
src: url('iconfont.woff2?t=1631692103587') format('woff2'),
url('iconfont.woff?t=1631692103587') format('woff'),
url('iconfont.ttf?t=1631692103587') format('truetype');
}
.iconfont {
@ -13,6 +13,54 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-icon:before {
content: "\e8ce";
}
.icon-tar:before {
content: "\e8cf";
}
.icon-a-fuzhi2:before {
content: "\e8d0";
}
.icon-fujian1:before {
content: "\e8d1";
}
.icon-a-bianji1:before {
content: "\e8d2";
}
.icon-banbenicon:before {
content: "\e8d3";
}
.icon-shanchuicon2:before {
content: "\e8d4";
}
.icon-a-lajitong_icon3x:before {
content: "\e8d5";
}
.icon-xialaanniu2:before {
content: "\e8d6";
}
.icon-xiazai-icon:before {
content: "\e8d7";
}
.icon-master_icon1:before {
content: "\e8d8";
}
.icon-shangchuanicon:before {
content: "\e8d9";
}
.icon-gerenziliao1:before {
content: "\e8c7";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,90 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "24368060",
"name": "icon",
"font_class": "icon",
"unicode": "e8ce",
"unicode_decimal": 59598
},
{
"icon_id": "24368061",
"name": "tar",
"font_class": "tar",
"unicode": "e8cf",
"unicode_decimal": 59599
},
{
"icon_id": "24289113",
"name": "复制 (2)",
"font_class": "a-fuzhi2",
"unicode": "e8d0",
"unicode_decimal": 59600
},
{
"icon_id": "24289114",
"name": "附件",
"font_class": "fujian1",
"unicode": "e8d1",
"unicode_decimal": 59601
},
{
"icon_id": "24289115",
"name": "编 辑",
"font_class": "a-bianji1",
"unicode": "e8d2",
"unicode_decimal": 59602
},
{
"icon_id": "24289116",
"name": "版本icon",
"font_class": "banbenicon",
"unicode": "e8d3",
"unicode_decimal": 59603
},
{
"icon_id": "24289117",
"name": "删除icon",
"font_class": "shanchuicon2",
"unicode": "e8d4",
"unicode_decimal": 59604
},
{
"icon_id": "24289118",
"name": "垃圾桶_icon@3x",
"font_class": "a-lajitong_icon3x",
"unicode": "e8d5",
"unicode_decimal": 59605
},
{
"icon_id": "24289119",
"name": "下拉按钮",
"font_class": "xialaanniu2",
"unicode": "e8d6",
"unicode_decimal": 59606
},
{
"icon_id": "24289120",
"name": "下载-icon",
"font_class": "xiazai-icon",
"unicode": "e8d7",
"unicode_decimal": 59607
},
{
"icon_id": "24289121",
"name": "master_icon",
"font_class": "master_icon1",
"unicode": "e8d8",
"unicode_decimal": 59608
},
{
"icon_id": "24289122",
"name": "上传icon",
"font_class": "shangchuanicon",
"unicode": "e8d9",
"unicode_decimal": 59609
},
{
"icon_id": "24059956",
"name": "个人资料",

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -218,7 +218,7 @@ a:hover {
}
.color-blue {
color: #4CACFF;
color: #2A61FF;
}
.color-huang {

View File

@ -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

View File

@ -18,6 +18,23 @@ export function getImageUrl(path) {
return `${path}`;
}
export function numFormat(num, digits){
let d = digits || 1;
var si = [
{ value: 1, symbol: "" },
{ value: 1E3, symbol: "k" },
{ value: 1E4, symbol: "W" }
];
var rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
var i;
for (i = si.length - 1; i > 0; i--) {
if (num >= si[i].value) {
break;
}
}
return (num / si[i].value).toFixed(d).replace(rx, "$1") + si[i].symbol;
}
export function getImage(path) {
// https://www.educoder.net
// https://testbdweb.trustie.net

View File

@ -3,7 +3,7 @@
// export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil';
export {
getUploadLogoActionUrl as getUploadLogoActionUrl,
getUploadLogoActionUrl as getUploadLogoActionUrl,numFormat as numFormat,
getImageUrl as getImageUrl,getImage as getImage, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode, getupload_git_file as getupload_git_file, getcdnImageUrl as getcdnImageUrl

View File

@ -7,7 +7,7 @@ function CloneAddress({http_url , ssh_url , zip_url , tar_url}) {
const [ key , setKey ] = useState("HTTP");
return (
<div className="downMenu">
<div style={{padding:"10px 20px 20px 20px",borderBottom:"1px solid #eee"}}>
<div style={{borderBottom:"1px solid #eee"}}>
<Menu className="urlMenu" selectedKeys={[key]} mode={"horizontal"}>
<Menu.Item key="HTTP" onClick={(e)=>{setKey(e.key)}}>HTTP</Menu.Item>
<Menu.Item key="SSH" onClick={(e)=>{setKey(e.key)}}>SSH</Menu.Item>

View File

@ -1,116 +1,36 @@
import React , { useState , useEffect } from 'react';
import { Popover , Input , Spin } from 'antd';
import { Popover , Dropdown , Input , Spin } from 'antd';
import './branch.scss';
import { getBranch , getTag } from '../GetData/getData';
import SelectOverlay from './SelectOverlay';
export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true })=>{
const [ showValue , setShowValue ] = useState(branch);
const [ inputValue , setInputValue] = useState(undefined);
const [ nav , setNav ] = useState(0);
const [ isSpin , setIsSpin ] = useState(true);
const [ flag , setFlag ] = useState(false);
const [ data , setData ] = useState(undefined);
const [ datas , setDatas ] = useState(undefined);
useEffect(()=>{
setShowValue(branch);
},[branch])
useEffect(()=>{
document.body.addEventListener('click', e => {
let name = e.target.className;
let turn = name === "ant-input OptionsInput" || name === "navli active"|| name === "navli" || name === "padding10 bor-bottom-greyE";
if(turn){
return;
}else{
setFlag(false);
}
})
})
useEffect(()=>{
if(branchList){
setData(branchList);
setDatas(branchList);
setIsSpin(false);
}
},[branchList])
async function getBranchs(id,owner){
let result = await getBranch(id,owner);
setData(result);
setDatas(result);
setIsSpin(false);
}
async function getTags(id,owner){
let result = await getTag(id,owner);
setData(result);
setDatas(result);
setIsSpin(false);
}
function changeInputValue(e){
setInputValue(e.target.value);
let filter = e.target.value ? data && data.length>0 && data.filter(item=>item.name.indexOf(e.target.value)>-1) : data;
setDatas(filter);
}
function changeNav(nav){
setNav(nav);
setIsSpin(true);
if(nav === 0){
getBranchs(projectsId,owner);
}else{
getTags(projectsId,owner);
}
}
function chooseitem(value){
// setShowValue(value);
changeBranch(value);
}
const menu = (
<div>
<div className="padding10 bor-bottom-greyE">
<Input
placeholder="请输入分支或标签名称搜索"
autocomplete="off" className="OptionsInput" value={inputValue}
onChange={changeInputValue} style={{width:"220px"}}
/>
<ul className="navUl">
<li className={nav === 0?"navli active":"navli"} onClick={()=>changeNav(0)}><i className="iconfont icon-fenzhi1 font-14 mr3"></i>分支列表</li>
{ tagflag && <li className={nav === 1?"navli active":"navli"} onClick={()=>changeNav(1)}><i className="iconfont icon-biaoqian3 font-14 mr3"></i>标签列表</li> }
</ul>
</div>
<Spin spinning={isSpin}>
<ul className="OptionsUl" id="ul-btn">
{
datas && datas.length>0 ?
datas.map((item,key)=>{
return(
<li key={key} onClick={()=>chooseitem(item.name)}><a className="task-hide ulALink">{item.name}</a></li>
)
}):
<p className="listTips">暂无{inputValue}{nav === 0 ?"分支":"标签"}~</p>
}
</ul>
</Spin>
</div>
<SelectOverlay
changeBranch={changeBranch}
tagflag={tagflag}
projectsId={projectsId}
owner={owner}
branchList={branchList}
/>
);
return(
<Popover placement='bottomLeft' visible={flag} content={menu} onClick={()=>setFlag(!flag)} overlayClassName="branch-tagBox-list">
<Dropdown placement='bottomLeft' overlay={menu} overlayClassName="branch-tagBox-list" trigger={['click']} >
<div className="branch-tagBox">
{/* {nav === 0 ?"分支":"标签"} */}
<span className="color-grey-9 mr3 ml8"><i className="iconfont icon-fenzhi2 font-18"></i></span>
<a className="ant-dropdown-link">
<span className="ant-dropdown-link task-hide" style={{fontWeight:"500",minWidth:"45px"}}>
{showValue}
</a>
<i className="showtag iconfont icon-xiajiantou font-14 color-grey-9 mr8" />
</span>
<i className="showtag iconfont icon-sanjiaoxing-down font-15 color-grey-9 mr5 ml5 mt1" />
</div>
</Popover>
</Dropdown>
)
})

View File

@ -0,0 +1,84 @@
import React , { useState , useEffect } from 'react';
import { Input , Spin , Menu } from 'antd';
import { getBranch , getTag } from '../GetData/getData';
function SelectOverlay({ changeBranch , tagflag , branchList , projectsId , owner }) {
const [ inputValue , setInputValue] = useState(undefined);
const [ nav , setNav ] = useState(0);
const [ isSpin , setIsSpin ] = useState(true);
const [ data , setData ] = useState(undefined);
const [ datas , setDatas ] = useState(undefined);
const [ keys ,setKeys] = useState("branch");
useEffect(()=>{
if(branchList){
setData(branchList);
setDatas(branchList);
setIsSpin(false);
}
},[branchList])
async function getBranchs(id,owner){
let result = await getBranch(id,owner);
setData(result);
setDatas(result);
setIsSpin(false);
}
async function getTags(id,owner){
let result = await getTag(id,owner);
setData(result);
setDatas(result);
setIsSpin(false);
}
function chooseitem(value){
changeBranch(value);
}
function changeInputValue(e){
setInputValue(e.target.value);
let filter = e.target.value ? data && data.length>0 && data.filter(item=>item.name.indexOf(e.target.value)>-1) : data;
setDatas(filter);
}
function changeNav(e){
setKeys(e.key);
setIsSpin(true);
if(e.key === "branch"){
getBranchs(projectsId,owner);
}else{
getTags(projectsId,owner);
}
}
return(
<div className="overlayBranch">
<div className="padding15" style={{paddingBottom:"0px"}}>
<Input
prefix={<i className="iconfont icon-sousuo_icon1 font-14"></i>}
placeholder={`请输入分支${tagflag ? "或标签" :""}名称搜索`}
autocomplete="off" className="OptionsInput"
value={inputValue}
onChange={changeInputValue}
/>
</div>
<Menu mode="horizontal" className="navUl" selectedKeys={[keys]} onClick={changeNav}>
<Menu.Item key={"branch"}>分支</Menu.Item>
{ tagflag && <Menu.Item key={"tag"}>标签</Menu.Item> }
</Menu>
<Spin spinning={isSpin}>
<ul className="OptionsUl" id="ul-btn">
{
datas && datas.length>0 ?
datas.map((item,key)=>{
return(
<li key={key} onClick={()=>chooseitem(item.name)}><a className="task-hide ulALink">{item.name}</a></li>
)
}):
<p className="listTips">暂无{inputValue}{nav === 0 ?"分支":"标签"}~</p>
}
</ul>
</Spin>
</div>
)
}
export default SelectOverlay;

View File

@ -27,10 +27,11 @@
overflow-y: auto;
}
.OptionsUl li{
height: 35px;
line-height: 35px;
height: 30px;
line-height: 30px;
cursor: pointer;
padding:0px 10px;
padding:0px 20px;
margin:5px 0px;
}
.OptionsUl li:hover{
background-color: #F0F0F0;
@ -45,38 +46,49 @@
width: 100%;
}
.branch-tagBox{
border:1px solid #eee;
border:1px solid #D0D0D0;
border-radius: 3px;
height: 40px;
height: 32px;
display: flex;
align-items: center;
cursor: pointer;
min-width: 140px;
min-width: 104px;
}
.branch-tagBox-list .ant-popover-arrow{
display: none;
.branch-tagBox:hover{
background-color: #F3F4F6;
}
.branch-tagBox-list.ant-popover.ant-popover-placement-bottom{
padding-top:0px;
.branch-tagBox-list{
background: #FFFFFF;
box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5);
border-radius: 4px;
.ant-popover-arrow{
display: none;
}
&.ant-popover.ant-popover-placement-bottom{
padding-top:0px;
}
.branch-tagBox .ant-dropdown-link{
display: block;
flex:1;
max-width: 105px;
}
.ant-popover-inner-content{
padding:0px;
}
}
.branch-tagBox .ant-dropdown-link{
display: block;
flex:1;
}
.branch-tagBox-list .ant-popover-inner-content{
padding:0px;
}
.navUl{
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 5px;
}
.navUl li{
cursor: pointer;
}
.navUl li.active{
color:#5091FF;
.overlayBranch{
width: 325px;
.navUl{
margin-top: 8px;
height: 30px;
line-height: 30px;
li{
height: 30px;
line-height: 30px;
padding:0px 5px;
margin-left: 20px!important;
}
}
}
.listTips{
padding:20px 0px;
@ -86,6 +98,7 @@
.urlMenu{
line-height: 30px;
margin-bottom: 10px;
padding:15px 20px 0px 20px;
border-bottom: none;
li.ant-menu-item{
height: 30px;

View File

@ -113,7 +113,14 @@ li.ant-menu-item{
z-index: 10000;
}
.laterest{
color: #05690d;
background-color: #EF3131;
color: #fff;
font-size: 12px;
margin-left: 10px;
padding:0px 5px;
border-radius: 2px;
height: 18px;
line-height: 18px;
}
@media screen and (max-width: 1800px){
@ -155,41 +162,112 @@ li.ant-menu-item{
margin:0px 20px!important;
}
}
.hoverA{
display:flex;
align-items: center;
max-width: 78px;
&:hover a{
color:#2A61FF !important ;
}
}
.menuPanels{
width: 240px;
height: 180px;
width: 295px;
.leftline{
position: relative;
color: #666;
height: 16px;
margin-left: 14px;
font-size: 12px;
&::before{
position: absolute;
left: -7px;
top:3px;
height: 12px;
width: 1px;
background-color: #999;
content: "";
}
}
.ant-btn{
height: 36px;
line-height: 34px;
width: 83px;
text-align: center;
padding:0px ;
font-weight: 500;
font-size: 14px;
&.currentBtn{
cursor: default;
color: #333;
&:hover{
color: #333;
border-color: #d0d0d0;
}
}
}
.ant-btn-default{
color: #333;
border-color: #d0d0d0;
&:hover{
background: #F3F4F6;
}
}
.ant-btn{
width: 102px;
height: 32px;
line-height: 30px;
}
.ant-btn-primary{
color: #fff;
background-color: #466AFF;
border:none;
&:hover{
background-color: rgba(70,106,255,0.85);
}
}
.focusPanelHeadInfo{
padding:14px 16px;
border-bottom: 1px solid #eee;
}
.ant-popover-content,.ant-popover-inner{
height: 100%;
width: 100%;
}
.ant-popover-inner-content{
padding:0px;
}
}
.halfs{
margin-top: 24px;
padding:24px 0px 0px 0px;
border-top: 1px solid #e8e8e8;
.attrPerson{
padding-bottom: 24px;
}
}
.aboutSubTitle{
display: flex;
align-items: center;
}
.menuMaininfos{
padding:10px 16px 14px;
border-bottom: 1px solid #eee;
}
.menuinfos{
padding:15px 0px;
padding:10px 20px 16px;
&>a{
display: flex;
flex-direction: column;
align-items: center;
border-right: 1px solid #eee;
flex: 1;
& >span:first-child{
font-size: 18px;
font-weight: 400;
font-size: 16px;
font-weight: 500;
color: #333;
line-height: 22px;
}
& >span:last-child{
color: #666;
}
&:last-child{
border-right: none;
font-weight: 400;
line-height: 20px;
margin-top: 6px;
}
}
}

View File

@ -1,13 +1,13 @@
import React, { useEffect, useState } from 'react';
import { AlignCenter , FlexAJ } from '../Component/layout';
import { Link } from 'react-router-dom';
import { Popover , Spin } from 'antd';
import { Popover , Spin , Button } from 'antd';
import { getImageUrl } from 'educoder';
import './Component.scss';
import { getUser } from '../GetData/getData';
import axios from 'axios';
function Contributors({contributors,owner,projectsId}){
function Contributors({contributors,owner,projectsId,currentLogin}){
const [ menuList ,setMenuList ]= useState([]);
const [ list , setList ]= useState(undefined);
const [ total , setTotal ]= useState(0);
@ -46,46 +46,60 @@ function Contributors({contributors,owner,projectsId}){
}
}
function renderOrganize(list) {
let str = "";
list.map(i=>{
str = str+i.name + "、";
})
return str && str.substr(0,str.length - 1);
}
function setMenusFunc(data){
if(data){
let ele = (
<Spin spinning={isSpin}>
<FlexAJ>
<FlexAJ className="menuMaininfos">
<AlignCenter>
<Link to={`/${data.login}`}><img src={getImageUrl(`/${data.image_url}`)} alt="" className="radius" width="38px" height="38px"/></Link>
<Link to={`/${data.login}`} className="ml10">{data.name}</Link>
</AlignCenter>
{
data.is_watch ? <a className="color-grey-9" onClick={()=>FocusFunc(false,data.login)}>取消关注</a>:<a className="color-blue" onClick={()=>FocusFunc(true,data.login)}>关注</a>
}
</FlexAJ>
<AlignCenter className="menuinfos">
<a href={data.projects_url}>
<span>{data.projects_count}</span>
<span>项目数</span>
</a>
<a href={data.followers_url}>
<span>{data.followers_count}</span>
<span>粉丝数</span>
</a>
<a href={data.following_url}>
<span>{data.following_count}</span>
<span>关注数</span>
</a>
</AlignCenter>
{
data.organizations && data.organizations.length > 0 ?
<AlignCenter className="font-12 pt4 pb4">
<span>所属组织</span>
<div className="task-hide flex1">
{renderArray(data.organizations)}
<div className="ml10">
<Link to={`/${data.login}`}>{data.name}</Link>
{ data.location && <span className="leftline">{data.location}</span> }
{
data.organizations && data.organizations.length>0&&
<p className="task-hide" style={{maxWidth:"215px"}}>
所属组织{renderOrganize(data.organizations)}
</p>
}
</div>
</AlignCenter>
:""
}
{
data.location && <AlignCenter className="font-12 pt4 pb4"><span>所在地址:</span><span className="ml5">{data.location}</span></AlignCenter>
}
</FlexAJ>
<AlignCenter className="menuinfos">
<Link to={`/${data.login}/projects`}>
<span>{data.projects_count}</span>
<span>项目数</span>
</Link>
<Link to={`/${data.login}/followers`}>
<span>{data.followers_count}</span>
<span>粉丝数</span>
</Link>
<Link to={`/${data.login}/following`}>
<span>{data.following_count}</span>
<span>关注数</span>
</Link>
</AlignCenter>
<div className={"pb20"} style={{display:"flex",justifyContent:'center'}}>
{
currentLogin && (currentLogin === data.login)
?
<Button className="currentBtn">当前用户</Button>
:
data.is_watch ?
<Button type={"default"} onClick={()=>FocusFunc(false,data.login)}>已关注</Button>
:
<Button type={"primary"} onClick={()=>FocusFunc(true,data.login)}>关注TA</Button>
}
</div>
</Spin>
)
setMenu(ele);
@ -135,10 +149,10 @@ function Contributors({contributors,owner,projectsId}){
return(
<div className="halfs">
<FlexAJ>
<AlignCenter><span className="font-16 color-grey-6">贡献者</span>{ contributors && contributors.total_count > 0 && <span className="infoCount">{contributors.total_count}</span>}</AlignCenter>
<Link className="font-12 color-grey-9" to={`/${owner}/${projectsId}/contribute`}>全部</Link>
</FlexAJ>
<Link to={`/${owner}/${projectsId}/contribute`} className="font-16 color-ooo hoverA">
<span>贡献者</span>
{ contributors && contributors.total_count > 0 && <span className="infoCount">{contributors.total_count}</span>}
</Link>
<div className="attrPerson" onMouseLeave={()=>setVisibleFunc(false)}>
{
total > 0 ?

View File

@ -2,7 +2,7 @@ import React, { useState, useCallback, memo } from 'react';
import { Tooltip } from 'antd';
CopyTool.defaultProps = {
beforeText: '复制', //
beforeText: '复制链接', //
afterText: '复制成功', //
className: '', //svgclass
inputId: 'copyText', //ID
@ -26,6 +26,7 @@ function CopyTool({ beforeText, afterText, className , inputId , timeOut }) {
if (document.execCommand('copy')) {
document.execCommand('copy');
}
document.getSelection().removeAllRanges();
setTitle(afterText);
if(timeOut){

View File

@ -25,7 +25,7 @@ function LanguagePower({languages}){
}
return(
<div>
<p className="font-16 color-grey-6">开发语言</p>
<p className="font-16 color-ooo aboutSubTitle">开发语言</p>
<div className="progress">
{
array && array.map((item,key)=>{

View File

@ -1,38 +1,34 @@
import React from 'react';
import { AlignCenter , AlignTop , FlexAJ } from '../Component/layout';
import { AlignTop } from '../Component/layout';
import { Link } from 'react-router-dom';
function Releases({owner,projectsId,releaseVersions , baseOperate , projectType}){
return(
<div>
<FlexAJ>
<AlignCenter><span className="font-16 color-grey-6">发行版</span>
{ releaseVersions && releaseVersions.total_count > 0 && <span className="infoCount">{releaseVersions.total_count}</span>}
</AlignCenter>
{ (releaseVersions && releaseVersions.total_count > 0) || projectType ===2 ?
<Link className="font-12 color-grey-9" to={`/${owner}/${projectsId}/releases`}>全部</Link>
:
baseOperate && <Link className="font-12 color-blue" to={`/${owner}/${projectsId}/releases/new`}>新建</Link>
}
</FlexAJ>
<Link to={`/${owner}/${projectsId}/releases`} className="font-16 color-ooo hoverA">
<span>发行版</span>
{ releaseVersions && releaseVersions.total_count > 0 && <span className="infoCount">{releaseVersions.total_count}</span>}
</Link>
{
releaseVersions && releaseVersions.total_count>0 ?
releaseVersions.list.map((item,key)=>{
return(
key === 0 &&<AlignTop className="mt10">
<i className="iconfont icon-biaoqian3 color-grey-6 font-18 mr10"></i>
<div>
<p className="font-16 color-grey-6">
<Link to={`/${owner}/${projectsId}/releases`}>{item.name}</Link>
<span className="font-12 laterest ml5">最新</span>
</p>
<p className="color-grey-9 font-13">{item.created_at}</p>
<p className="color-grey-3 font-12">{item.created_at}</p>
</div>
</AlignTop>
)
})
:""
:
<div className="mt8">
您暂未发布任何版本{baseOperate && projectType !==2 && <Link className="color-blue ml20" to={`/projects/${owner}/${projectsId}/releases/new`}>创建新版本</Link>}
</div>
}
</div>

View File

@ -2,9 +2,9 @@ import React from 'react';
import {Popover} from 'antd';
import './Component.scss';
export default (({menu , children})=>{
export default (({menu , children, overlayClassName})=>{
return(
<Popover content={menu} trigger={['click']} placement='bottom'>
<Popover content={menu} trigger={['click']} placement='bottom' overlayClassName={overlayClassName}>
{children}
</Popover>
)

View File

@ -46,14 +46,11 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
Axios.post(url,{
...values
}).then(result=>{
if(result){
if(result.data.status === 0){
onSuccess(result.data && result.data.owner);
}else{
onSuccess();
}
if(result && result.data.id){
onSuccess(result.data && result.data.owner);
}else{
onSuccess();
}
}).catch(error=>{})
}
})

View File

@ -1,8 +1,9 @@
import React , { useEffect , useState } from 'react';
import { WhiteBack , Box , LongWidth , ShortWidth , Gap , AlignCenter , FlexAJ } from '../Component/layout';
import { Dropdown , Menu , Divider , Spin, Button } from 'antd';
import { Dropdown , Menu , Divider , Spin, Button , Typography } from 'antd';
import { getImageUrl } from "educoder";
import { Link } from 'react-router-dom';
import { truncateCommitId } from "../common/util";
import CloneAddress from '../Branch/CloneAddress';
import SelectBranch from '../Branch/Select';
@ -24,7 +25,7 @@ import CheckProfile from '../Component/ProfileModal/Profile';
/**
* projectDetail.type:0是托管项目1是镜像项目2是同步镜像项目(为2时不支持在线创建在线上传在线修改在线删除创建合并请求等功能)
*/
const { Paragraph } = Typography;
function turnbar(str){
if(str && str.length>0 && str.indexOf("/")>-1){
return str.replaceAll('/','%2F');
@ -148,7 +149,6 @@ function CoderDepot(props){
setReadme(result.data.readme);
setEditReadme(false);
setHide(true);
console.log("dddd:",result.data.entries);
}
setTimeout(function(){setIsSpin(false);},500);
}).catch(error=>{setIsSpin(false);})
@ -209,7 +209,7 @@ function CoderDepot(props){
let b = branchName || defaultBranch;
let checkvalue = turnbar(b);
return (
<Menu>
<Menu className="fileMenu">
<Menu.Item>
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件</CheckProfile>
</Menu.Item>
@ -303,6 +303,7 @@ function CoderDepot(props){
const { current_user } = props;
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));
return(
<WhiteBack>
<UpdateDescModal desc={desc} website={website} lesson_url={lesson_url} visible={openModal} onCancel={()=>setOpenModal(false)} onOk={okUpdate}/>
@ -321,7 +322,7 @@ function CoderDepot(props){
list = {mainFlag ? dirInfo : undefined}
/>
<div className="drawerBtn" onClick={()=>setVisible(true)}>
<i className="iconfont icon-youjiantou font-16"></i>
<i className="iconfont icon-zuohuaicon font-14"></i>
<span>目录</span>
</div>
</React.Fragment>
@ -334,7 +335,7 @@ function CoderDepot(props){
<div className="panelmenu">
<FlexAJ>
<AlignCenter>
<div className="mr20">
<div className="mr30">
{
props && props.platform ?
<SelectBranch
@ -351,40 +352,47 @@ function CoderDepot(props){
}
</div>
<AlignCenter className="mr20">
<Link to={`/${owner}/${projectsId}/branches`} className="color-grey-9">
<i className="iconfont icon-fenzhi2 font-18 color-grey-9 mr3"></i>
<span className="color-grey-6 mr3">{projectDetail && projectDetail.branches && projectDetail.branches.total_count}</span>分支
<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="color-grey-9">
<i className="iconfont icon-biaoqian3 font-16 color-grey-9 mr3"></i>
<span className="color-grey-6 mr3">{projectDetail && projectDetail.tags && projectDetail.tags.total_count}</span>标签
<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>
</AlignCenter>
<AlignCenter>
<AlignCenter className="depotBtn">
{
baseOperate && ((projectDetail.type !== 2 && pullsFlag) || issuesFlag )&&
<div className="mr20 addOptionBtn">
<div className="addOptionBtn">
{
projectDetail.type !== 2 && pullsFlag &&
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/pulls/new`)} >+ 合并请求</CheckProfile>
}
{
issuesFlag &&
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/issues/new`)} >+ 任务</CheckProfile>
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/issues/new`)} >+ 易修</CheckProfile>
}
</div>
}
{ fileOperate &&
<Dropdown overlay={fileMenu()} className="mr20" trigger={['click']}>
<Button type="default">文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-9"></i></Button>
<Dropdown
overlay={fileMenu()}
className="mr10"
trigger={['click']}
getPopupContainer={document.parentNode}
>
<a>文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-6 mr-5"></i></a>
</Dropdown>
}
<Dropdown overlay={downloadMenu} placement="bottomRight" trigger={['click']}>
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white"></i></Button>
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white mr-3"></i></Button>
</Dropdown>
</AlignCenter>
</FlexAJ>
@ -395,15 +403,18 @@ 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 className={hideBtn && hide ? "ellipsistxt hidetxt" :"ellipsistxt"}>
<pre id="ptxt">{lastCommit && lastCommit.message}</pre>
<div onClick={()=>props.history.push(`/${owner}/${projectsId}/commits/${truncateCommitId(lastCommit.sha)}`)} className={hideBtn && hide ? "ellipsistxt hidetxt" :"ellipsistxt"}>
<pre id="ptxt">{lastCommit.message}</pre>
</div>
{ hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> }
<span className="ml12 color-grey-9 mt3">{lastCommit && lastCommit.time_from_now}</span>
{ commitCount ? <Link to={`/${owner}/${projectsId}/commits/branch/${turnbar(branchName || defaultBranch)}`} className="ml12 color-grey-9">
<i className="iconfont icon-tijiao mr3 font-17 color-grey-9"></i>{commitCount}次提交
</Link>:"" }
<span className="ml20 color-grey-6 font-12 mt3">{lastCommit.time_from_now}</span>
{
commitCount ?
<Link to={`/${owner}/${projectsId}/commits/branch/${turnbar(branchName || defaultBranch)}`} className="ml20 color-grey-3"style={{height:"28px",lineHeight:"28px"}}>
<i className="iconfont icon-tijiaoicon mr3 font-16"></i><span style={{fontWeight:"500"}}>{commitCount}次提交</span>
</Link>:""
}
</div>
}
<ul className="listtablebody">
@ -458,48 +469,48 @@ function CoderDepot(props){
<ShortWidth>
<Gap style={{paddingLeft:"30px"}}>
<div className="panelmenu">
<FlexAJ className="font-18 color-grey-6 mb20" style={{lineHeight:"28px"}}>简介
<FlexAJ className="font-18 color-ooo mb20" style={{lineHeight:"28px"}}>关于
{
projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner" || projectDetail.permission==="Manager") &&
<i onClick={()=>setOpenModal(true)} className="iconfont icon-anquanshezhi color-grey-9 font-15"></i>
<i onClick={()=>setOpenModal(true)} className="iconfont icon-a-shezhi color-grey-9 font-15"></i>
}
</FlexAJ>
{desc && <p className="font-14 color-grey-9 mb15 task-hide-2" style={{lineHeight:"22px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}}>{desc}</p>}
{desc && <p className="font-14 color-grey-3 mb15 task-hide-2" style={{lineHeight:"24px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}}>{desc}</p>}
{
website &&
<p className="color-grey-6 df">
<i className="iconfont icon-lianjie2 font-15 mr10 color-grey-9"></i>
<a href={website} className="color-grey-6" target="_blank" style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px",textDecoration:"underline"}}>{website}</a>
</p>
<div className="color-grey-6 df pinfos mb5">
<i className="iconfont icon-lianjie2 font-15 mr10"></i>
<a href={website} target="_blank" style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px",textDecoration:"underline"}}>{website}</a>
</div>
}
<p>
<i className="iconfont icon-wenjian4 font-15 mr10 color-grey-9"></i>
<a href="#readme" className="color-grey-6">README.md</a>
</p>
<p className="color-grey-6">
<i className="iconfont icon-dataBase font-15 mr10 color-grey-6"></i>
<div className="pinfos mb5">
<i className="iconfont icon-zishuwenjian_icon font-15 mr10"></i>
<a href="#readme">README.md</a>
</div>
<div className="color-grey-6 mb5">
<i className="iconfont icon-neicunicon font-15 mr10"></i>
<span>{projectDetail && projectDetail.size}</span>
</p>
</div>
{
projectDetail && projectDetail.license_name &&
<p className="color-grey-6">
<i className="iconfont icon-tianping font-16 mr10 color-grey-3"></i>
<span>{projectDetail.license_name}</span>
</p>
<div className="pinfos">
<i className="iconfont icon-xieyiicon font-16 mr10"></i>
<Link to={`/${owner}/${projectsId}/tree/${branchName || defaultBranch}/LICENSE`} className="color-grey-6">{projectDetail.license_name}</Link>
</div>
}
</div>
{
inviteCode &&
<div>
<Divider />
<Invite code={inviteCode} className={"detailsCode"}/>
<Invite code={inviteCode}/>
</div>
}
{
lesson_url &&
<div>
<Divider />
<p className="font-16 color-grey-6">实践课程</p>
<p className="font-16 color-ooo">实践课程</p>
<a href={lesson_url} target="_blank" className="color-grey-6" style={{textDecoration:"underline",wordBreak:"break-all"}}>{lesson_url}</a>
</div>
}
@ -520,11 +531,11 @@ function CoderDepot(props){
}
{/* 贡献者 */}
{
projectDetail && projectDetail.contributors && projectDetail.contributors.length >0 &&
<Contributors contributors={projectDetail && projectDetail.contributors} owner={owner} projectsId={projectsId} />
projectDetail && projectDetail.contributors && projectDetail.contributors.total_count >0 &&
<Contributors contributors={projectDetail.contributors} owner={owner} projectsId={projectsId} />
}
{/* 语言 */}
{ projectDetail && projectDetail.languages && projectDetail.languages.length >0 &&
{ projectDetail && projectDetail.languages &&
<React.Fragment>
<Divider />
<LanguagePower languages={projectDetail.languages}/>

View File

@ -4,8 +4,8 @@ import { truncateCommitId } from '../common/util';
const typeIco = {
"submodule":"icon-file-submodule font-17",
"file":'icon-wenjia font-15',
"dir":"icon-wenjianjia1 font-15"
"file":'icon-wenjian6 font-15 color-blue-file',
"dir":"icon-wenjianjia4 font-15 color-blue_4C"
}
function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
@ -13,7 +13,7 @@ function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
<li>
<span>
<a onClick={()=>goToSubRoot(item.path,item.type,item.name)} className={item.type === "submodule" && "submoduleStyle"}>
<i className={`iconfont ${typeIco[`${item.type}`]} color-green-file mr5`}></i>{item.name}
<i className={`iconfont ${typeIco[`${item.type}`]} mr8`}></i>{item.name}
</a>
</span>
<span title="init project">
@ -21,7 +21,7 @@ function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
{item.commit && item.commit.message}
</Link>
</span>
<span>{item.commit && item.commit.time_from_now}</span>
<span title={item.commit && item.commit.created_at}>{item.commit && item.commit.time_from_now}</span>
</li>
)
}

View File

@ -1,8 +1,9 @@
import React, { useEffect, useState } from 'react';
import RenderHtml from '../../components/render-html';
import { AlignCenter } from '../Component/layout';
import { Dropdown , Menu , Spin } from 'antd';
import { Link } from 'react-router-dom';
import { Dropdown , Anchor , Spin } from 'antd';
import ReadmeCatelogue from './sub/ReadmeCatelogue';
const $ = window.$;
function CoderDepotReadme({ operate , history , readme , ChangeFile }){
@ -23,49 +24,45 @@ function CoderDepotReadme({ operate , history , readme , ChangeFile }){
const anchor = el.id;
const level = el.tagName.replace("H", "");
const href = `#${anchor}`;
return { href:`${path}${href}`,text:el.textContent , level:level }
return { href:`${href}`,text:el.textContent , level:level }
});
setMenuList(items);
},[content])
function menu(){
if(menuList && menuList.length > 0){
let hash = history.location.hash;
return(
<Menu className="menuslist">
{
menuList.map((item,key)=>{
return(
<Menu.Item key={item.id} className={decodeURI(hash).indexOf(item.text)>-1 ?"active":""}><Link to={`${item.href}`} style={{paddingLeft:`${item.level *10}px`}} title={item.text}>{item.text}</Link></Menu.Item>
)
})
}
</Menu>
<ReadmeCatelogue menuList={menuList} hash={history.location.hash}/>
)
}else{
return <Spin />
}
}
return(
<div className="commonBox" id="readme">
<div className="commonBox-title boxTitle">
<AlignCenter>
<Dropdown overlay={menu()}>
<span className="catelogue">
<i className="iconfont icon-zhangjie1 font-14 mr5"></i>
<span>目录</span>
</span>
</Dropdown>
<span className="commonBox-title-read">README.md</span>
</AlignCenter>
{
operate ?
<a className="ml20 pull-right" onClick={() =>ChangeFile(readme && readme.path, false)}>
<i className="iconfont icon-bianji6 font-16 color-blue"></i>
</a>
:""
}
</div>
<div className="commonBox readBox" id="readme">
<Anchor offsetTop={70} targetOffset={160}>
<div className="commonBox-title boxTitle">
<AlignCenter>
<Dropdown overlay={menu()} trigger={['hover']} overlayClassName="menuslist">
<span className="catelogue">
<i className="iconfont icon-muluicon font-12 mr5"></i>
<span>目录</span>
</span>
</Dropdown>
<span className="commonBox-title-read"><a href="#readme ">README.md</a></span>
</AlignCenter>
{
operate ?
<a className="ml20 pull-right" onClick={() =>ChangeFile(readme && readme.path, false)}>
<i className="iconfont icon-a-bianji font-17 color-grey-6"></i>
</a>
:""
}
</div>
</Anchor>
{
content &&
<div className="commonBox-info">

View File

@ -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.css';
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>
)
})

View File

@ -1,6 +1,6 @@
import React, { Component } from "react";
import { Popconfirm , Select } from "antd";
import "./list.css";
import "./list.scss";
import axios from "axios";
import Meditor from "../Newfile/m_editor";
import RenderHtml from "../../components/render-html";

View File

@ -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} />)

View File

@ -1,70 +0,0 @@
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { Spin } from 'antd';
import { truncateCommitId } from '../common/util';
import Nodata from '../Nodata';
import { Link } from 'react-router-dom'
export default (( props, { projectDetail }) => {
const [isSpin, setSpin] = useState(true);
const [data, setData] = useState(undefined);
const { projectsId , owner } = props.match.params;
useEffect(() => {
if (projectsId) {
const url = `/${owner}/${projectsId}/tags.json`;
axios.get(url).then((result) => {
if (result) {
setSpin(false);
setData(result.data);
}
}).catch(error => {
console.log(error);
})
}
}, [owner, projectsId]);
return (
<div className="main" style={{padding:"0px",border:"none"}}>
<Spin spinning={isSpin}>
<div style={{minHeight:"400px"}}>
{
data && data.length > 0 &&
<div className="div_table">
<ul className="ul_thead">
<li>
<span className="flex1">标签名</span>
<span>提交信息</span>
<span className="ul_tbody_forth">下载</span>
</li>
</ul>
<ul className="ul_tbody">
{
data.map((item, key) => {
return (
<li>
<span className="flex1">
<i className="iconfont icon-biaoqian3 font-16 mr5 color-grey-8"></i>
<span className="font-16">{item.name}</span>
</span>
<span className="ul_tbody_third">
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.id}`)}`} className="commitKey" style={{ "marginLeft": 0 }}>{truncateCommitId(`${item.id}`)}</Link>
</span>
<span className="ul_tbody_forth">
<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>
</span>
</li>
)
})
}
</ul>
</div>
}
{ data && data.length === 0 && <Nodata _html={`暂无标签!`}/> }
</div>
</Spin>
</div>
)
})

View File

@ -1,10 +1,13 @@
import React, { Component } from 'react';
import { Spin, Tooltip, Button } from 'antd';
import { Spin, Tooltip } from 'antd';
import { Link, Route, Switch } from 'react-router-dom';
import { Content, AlignTop } from '../Component/layout';
import DetailBanner from './sub/DetailBanner';
import '../css/index.scss'
import './list.css';
import './list.scss';
import { ImageLayerOfCommentHOC } from "../../modules/page/layers/ImageLayerOfCommentHOC";
import Loadable from 'react-loadable';
import Loading from '../../Loading';
@ -142,7 +145,7 @@ const WikiEdit = Loadable({
function checkPathname(projectsId, owner, pathname) {
let name = "";
if (pathname && pathname !== `/${owner}/${projectsId}`) {
let url = pathname.split(`/${owner}/${projectsId}`)[1] || '';
let url = pathname.split(`/${owner}/${projectsId}`)[1] || "";
if (url.indexOf("/about") > -1) {
name = "about"
} else if (url.indexOf("/issues") > -1 || url.indexOf("Milepost") > 0) {
@ -471,7 +474,7 @@ class Detail extends Component {
<div>
<div className="detailHeader-wrapper">
<div className="normal">
<AlignTop style={{ padding: "20px 0px 10px", justifyContent: "space-between" }}>
<AlignTop style={{ padding: "18px 0px 10px", justifyContent: "space-between" }}>
<div>
<AlignTop>
<div className="projectallName">
@ -491,7 +494,7 @@ class Detail extends Component {
}
{
projectDetail && projectDetail.type && projectDetail.type !== 0 ?
<span className="color-grey-9">镜像自 <a className="color-grey-6" target="_blank" href={projectDetail.mirror_url}>{projectDetail.mirror_url}</a></span>
<span className="color-grey-9">导入于 <a className="color-grey-6" target="_blank" href={projectDetail.mirror_url}>{projectDetail.mirror_url}</a></span>
: ""
}
</div>
@ -504,7 +507,7 @@ class Detail extends Component {
((current_user && current_user.admin) || isManager) && (projectDetail && projectDetail.type && projectDetail.type === 2) ?
<a className="synchronism ml30" onClick={this.synchronismMirror}>同步镜像</a> : ""
}
<Button className="detail_tag_btn">
<span className="detail_tag_btn">
<a className="detail_tag_btn_name" style={{ cursor: platform ? "pointer" : "default" }} onClick={() => this.focusFunc(watched)}>
<i className={watched ? "iconfont icon-shixing color-orange font-16 mr3" : "iconfont icon-kongxing color-grey-9 font-16 mr3"}></i>
<span>{watched ? '取消关注' : '关注'}</span>
@ -512,15 +515,15 @@ class Detail extends Component {
{
watchers_count > 0 ?
platform ?
<Link className="detail_tag_btn_count" style={{ color: `${watched ? "#2878FF" : "#666"}` }} to={platform ? { pathname: `/${owner}/${projectsId}/following`, state } : ""}>
<Link className="detail_tag_btn_count" style={{ color: `#666` }} to={platform ? { pathname: `/${owner}/${projectsId}/following`, state } : ""}>
{watchers_count}
</Link>
:
<span className="detail_tag_btn_count">{watchers_count}</span>
: ""
}
</Button>
<Button className="detail_tag_btn">
</span>
<span className="detail_tag_btn">
<a className="detail_tag_btn_name" style={{ cursor: platform ? "pointer" : "default" }} onClick={() => this.pariseFunc(praised)}>
<i className={praised ? "iconfont icon-weibiaoti105 color-orange font-14 mr3" : "iconfont icon-guanzhu color-grey-9 font-14 mr3"}></i>
<span>{praised ? '取消点赞' : '点赞'}</span>
@ -528,17 +531,17 @@ class Detail extends Component {
{
praises_count > 0 ?
platform ?
<Link className="detail_tag_btn_count" style={{ color: `${praised ? "#2878FF" : "#666"}` }} to={{ pathname: `/${owner}/${projectsId}/stargazers`, state }}>
<Link className="detail_tag_btn_count" style={{ color: `#666` }} to={{ pathname: `/${owner}/${projectsId}/stargazers`, state }}>
{praises_count}
</Link> :
<span className="detail_tag_btn_count">{praises_count}</span>
: ""
}
</Button>
<Button className="detail_tag_btn" loading={forkSpin}>
</span>
<span className="detail_tag_btn" loading={forkSpin}>
<Tooltip title="复刻是fork的中文名即复制代码仓库" placement="bottom">
<a className="detail_tag_btn_name" style={{ cursor: platform ? "pointer" : "default" }} onClick={this.forkFunc}>
<i className="iconfont icon-fork color-grey-9 mr3"></i>
<i className="iconfont icon-fork color-grey-9 mr3 font-16"></i><span></span>
</a>
</Tooltip>
{
@ -551,7 +554,7 @@ class Detail extends Component {
<span className="detail_tag_btn_count">{forked_count}</span>
: ""
}
</Button>
</span>
</span>
}
</div>
@ -780,4 +783,7 @@ class Detail extends Component {
}
}
export default Detail;
export default ImageLayerOfCommentHOC({
imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget",
parentSelector: ".newContainer",
})(Detail);

View File

@ -5,7 +5,7 @@ import { getImageUrl } from 'educoder';
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
import '../css/index.scss'
import './list.css';
import './list.scss';
import './Index.scss';
import ListItem from './IndexItem'
import axios from 'axios';
@ -255,14 +255,14 @@ class Index extends Component {
newItem = ()=>{
return(
<Menu>
<Menu.Item key="created_mirror">
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/mirror/new')}}>新建镜像项目</CheckProfile>
</Menu.Item>
<Menu.Item key="created_deposit">
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/deposit/new')}}>新建托管项目</CheckProfile>
</Menu.Item>
</Menu>
<ul>
<li>
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/deposit/new')}}>新建项目</CheckProfile>
</li>
<li>
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/mirror/new')}}>导入项目</CheckProfile>
</li>
</ul>
)
}
@ -392,7 +392,13 @@ class Index extends Component {
<div>
{
current_user && current_user.login &&
<Popover content={this.newItem()} trigger={["click"]} placement='bottom' className="mr50">
<Popover
overlayClassName="newPopUl"
content={this.newItem()}
trigger={["click"]}
placement='bottom'
className="mr50"
>
<a className="ant-dropdown-link">
<span className="color-blue font-16"><img src={img_new} alt="" width="13px" /> 新建</span>
</a>

View File

@ -13,6 +13,21 @@
}
}
}
.iconBtn{
i{
color: #666;
}
span{
margin-left: 4px;
color: #333!important;
&:last-child{
font-weight: 500;
}
}
&:hover span,&:hover i{
color: #466AFF!important;
}
}
/* recommandProjects */
.recommandProjects.slick-slider{
width: 1230px;
@ -108,46 +123,77 @@
margin: 0 auto;
.panelmenu{
padding-top:30px;
.depotBtn{
.mr-5{
margin-right: -5px;
}
.ant-btn{
height: 32px;
line-height: 32px;
width: 83px;
text-align: center;
padding:0px ;
font-weight: 500;
font-size: 14px;
}
.ant-btn-default{
color: #333;
border-color: #d0d0d0;
&:hover{
background: #F3F4F6;
}
}
.ant-btn-primary{
color: #fff;
background-color: #466AFF;
border: none;
&:hover{
background-color: rgba(70,106,255,0.85);
}
}
}
}
.addOptionBtn{
height: 32px;
line-height: 30px;
.depotBtn,.addOptionBtn{
display: flex;
border:1px solid #d9d9d9;
border-radius: 2px;
a{
padding:0px 13px;
color: rgba(0, 0, 0, 0.65);
cursor: pointer;
}
& > a:first-child{
border-right: 1px solid #d9d9d9;
}
& > a:last-child{
border-right: none;
color: #333!important;
font-weight: 500!important;
border-radius: 5px;
width: 83px;
height: 32px;
line-height: 30px;
background: #fff;
border: 1px solid #D0D0D0;
margin-right: 10px;
text-align: center;
&:hover,&:active{
background: #F3F4F6;
}
}
}
.infoCount{
display: inline-block;
padding:0px 5px;
height: 16px;
line-height: 16px;
background-color: #eee;
color:#999;
width: 24px;
text-align: center;
height: 24px;
line-height: 24px;
background-color:rgba(153, 153, 153, 0.13);;
color:#666;
border-radius: 12px;
margin-left: 10px;
margin-left: 6px;
font-size: 12px;
}
.attrPerson{
padding-top: 15px;
padding-top: 12px;
display: flex;
flex-wrap: wrap;
padding-bottom: 2px;
a{
margin: 10px 10px 0px 0px;
margin: 0px 17px 0px 0px;
img{
border-radius: 50%;
width: 35px;
height: 35px;
width: 40px;
height: 40px;
}
&:nth-child(6){
margin-right: 0px;
@ -156,15 +202,15 @@
}
.progress{
display: flex;
border-radius: 10px;
height: 7px;
border-radius: 2px;
height: 11px;
margin-top: 12px;
span{
&:first-child{
border-radius: 10px 0px 0px 10px;
border-radius: 2px 0px 0px 2px;
}
&:last-child{
border-radius: 0px 10px 10px 0px;
border-radius: 0px 2px 2px 0px;
}
}
}
@ -184,10 +230,11 @@
padding-left: 15px;
position: relative;
min-width: 33.5%;
font-size: 12px;
font-weight: 400;
color: #666;
span{
color: #666;
&:last-child{
color: #999;
margin-left: 5px;
}
}
@ -195,18 +242,18 @@
}
.listtable{
margin-top: 20px;
border:1px solid #d9d9d9;
border-radius: 4px;
.listtablehead{
display: flex;
justify-content: space-between;
align-items: flex-start;
border-bottom: 1px solid #d9d9d9;
padding:7px 20px;
padding:12px 20px 11px;
border-radius: 4px 4px 0px 0px;
background-color: #FAFBFC;
border: 1px solid rgba(42, 97, 255, 0.23);
background-color: #FAFCFF;
.ellipsistxt{
margin-top: 6px;
cursor: pointer;
#ptxt{
margin-bottom: 0px;
word-break: break-all;
@ -227,32 +274,37 @@
overflow: hidden;
position: relative;
padding-right:8px;
&::after{
position: absolute;
right: 0px;
bottom: 0px;
content:"...";
}
// &::after{
// position: absolute;
// right: 0px;
// bottom: 0px;
// content:"...";
// }
}
}
.ellipsis{
margin-left: 8px;
cursor: pointer;
border-radius: 2px;
background-color: #c1c1c1;
height: 16px;
background: rgba(153, 153, 153, 0.2);
border-radius: 2px;
padding:0px 4px;
height: 14px;
line-height: 14px;
margin-top: 9px;
i{
font-size: 15px!important;
color: #fff;
color: #333;
height: 14px;
line-height: 14px;
}
}
}
.listtablebody{
border-radius:0px 0px 4px 4px ;
border: 1px solid #D0D0D0;
border-top: none;
li.listtablepath{
a{color: #40a9ff;}
p{
@ -260,12 +312,15 @@
}
}
& > li{
height: 42px;
height: 38px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #d9d9d9;
padding:0px 20px 0px 24px;
&:hover{
background-color: #F3F4F6;
}
& > span:first-child{
width: 30%;
overflow: hidden;
@ -292,8 +347,10 @@
.drawerBtn{
position: fixed;
left: -13px;
border:1px solid rgb(207,205,223);
width: 34px;
width: 33px;
background: #FFFFFF;
box-shadow: 0px 0px 8px 3px rgba(0, 0, 0, 0.09);
border: 1px solid #666666;
border-radius: 0px 12px 12px 0px;
height: 70px;
top:50%;
@ -301,63 +358,63 @@
cursor: pointer;
display: flex;
flex-direction: column;
align-items: flex-end;
align-items: center;
justify-content: center;
padding-left: 7px;
&:hover{
box-shadow: 1px 0px 7px rgba(0,0,0,0.1);
box-shadow: 0px 0px 8px 3px rgba(0, 0, 0, 0.09);
}
span{
writing-mode: vertical-lr;
color: #202429;
color: #333;
width: 25px;
font-size: 14px;
}
i{
color: #24292e;
height: 18px;
line-height: 18px;
width: 18px;
color: #333;
height: 14px;
line-height: 14px;
width: 14px;
margin-left: 2px;
margin-bottom: 3px;
}
}
.downMenu{
width: 330px;
box-shadow: 0px 0px 9px rgba(134, 134, 134,0.4);
width: 329px;
background-color: #fff;
.ant-menu-vertical .ant-menu-item:hover{
background-color: #e6f7ff;
box-shadow: 0px 1px 8px 1px rgba(212, 212, 212, 0.5);
padding-bottom: 14px;
.ant-menu-item{
height: 50px;
line-height: 50px;
}
}
.fileMenu{
width: 83px;
li{
padding:6px 0px!important;
text-align: center;
width: 100%;
}
}
.menuslist{
max-height: 200px;
overflow-y: auto;
padding:10px 15px;
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;
}
}
.ant-dropdown-menu-item.active{
background-color: #e6f7ff;
}
}
.catelogue{
border:1px solid rgb(211, 211, 211);
cursor: pointer;
background: #FAFBFC;
border-radius: 4px;
border: 1px solid #D0D0D0;
font-size: 15px;
font-weight: normal;
border-radius: 5px;
margin-right: 10px;
margin-right: 12px;
padding:0px 10px;
height: 30px;
line-height: 30px;
color: #666!important;
display: flex;
align-items: center;
&:hover{
background-color: #F3F4F6;
}
span{
margin-top: 1px;
}
@ -370,4 +427,28 @@
&:hover{
color: #05101a;
}
}
.pinfos{
i,a{color: #666;}
&:hover i,&:hover a{
color: #2A61FF!important;
}
}
.graph{
flex:1;
margin:0px 12px;
.ant-typography{
white-space: pre-wrap;
margin-bottom: 0px;
}
}
.ant-anchor-wrapper{
padding-left: 2px;
.ant-anchor-ink::before{
background-color: #fff;
}
}
.coderSubPage{
width: 1200px;
margin:0px auto;
}

View File

@ -5,7 +5,7 @@ import { AlignCenter } from '../Component/layout';
import { Link } from 'react-router-dom';
import '../css/index.scss';
import Nodata from '../Nodata';
import './list.css';
import './list.scss';
import img_parise from '../Images/parise.png';
class IndexItem extends Component {
@ -41,22 +41,22 @@ class IndexItem extends Component {
{ !item.is_public && <span className="privateTag">私有</span> }
{
item.forked_from_project_id ?
<span className="ml5">
<Tooltip title="该项目是一个fork仓库" className="ml5">
<i className="iconfont icon-fork font-18 color-orange" />
</span>
</Tooltip>
: ""
}
{
item.type && item.type === 2 ?
<Tooltip title="该项目是一个镜像" className="ml5">
<Tooltip title="该项目是一个同步镜像仓库" className="ml5">
<i className="iconfont icon-banbenku font-18 color-green" />
</Tooltip>:""
}
{
item.type && item.type === 1 ?
<span className="ml5">
<Tooltip title="该项目是一个导入于其他网站的仓库" className="ml5">
<i className="iconfont icon-jingxiang font-18 color-green" />
</span>:""
</Tooltip>:""
}
</AlignCenter>
<span className="p-r-tags">

BIN
src/forge/Main/img/tree.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 B

View File

@ -218,74 +218,92 @@
}
/* -----------详情------------ */
.detailHeader-wrapper{
background-color:#FAFBFC;
/* background: url(../Images/forgeBanner.jpg) no-repeat center; */
/* background-size:cover; */
background-color:#FBFCFF;
border-bottom:1px solid #e2e2e2;
}
.headerMenu-wrapper{
font-size: 16px;
display: flex;
flex-direction: row;
}
.headerMenu-wrapper li{
position: relative;
text-align: center;
height: 40px;
line-height: 28px;
margin-right: 40px;
}
.headerMenu-wrapper li a{
color: #666;
}
.headerMenu-wrapper li a > img{
margin-right: 8px;
}
.headerMenu-wrapper li a > span.num{
height: 28px;
line-height: 29px;
margin-left: 8px;
font-size: 12px;
color: #2878FF;
float: right;
}
.headerMenu-wrapper li.active::after{
position: absolute;
bottom:0px;
height:2px;
background-color: #5091FF;
content:'';
left: 0px;
width:100%;
cursor: pointer;
li{
text-align: center;
padding:0px;
margin-right: 40px;
display: flex;
& > a{
position: relative;
font-size: 14px;
height: 36px;
line-height: 24px;
display: block;
color: #000!important;
&> span.num{
line-height: 24px;
margin-left: 5px;
font-size: 12px;
float: right;
color: #666!important;
background-color: rgba(153, 153, 153, 0.13);;
border-radius: 50%;
width: 24px;
height: 24px;
}
}
&.active a::after,&:hover a::after{
position: absolute;
bottom:0px;
height:2px;
background-color:rgba(153, 153, 153, 0.2);
content:'';
left: 0px;
width:100%;
}
&.active span{
font-weight: 500;
}
&.active a::after{
background-color: #466AFF;
}
}
}
.detail_tag_btn{
height:26px;
line-height: 26px;
height:32px;
line-height: 32px;
border-radius:5px;
border:1px solid #f1f1f1;
border:1px solid #D0D0D0;
display: flex;
align-items: center;
margin-left: 30px;
margin-left: 10px;
padding:0px;
background-color: transparent;
background-color:#FAFBFC;
box-shadow: none;
.detail_tag_btn_name{
padding:0px 10px;
text-align: center;
height: 30px;
line-height: 30px;
border-radius:5px 0px 0px 5px;
&:hover
{
background-color: #F3F4F6;
}
span{
color: #333!important;
}
}
.detail_tag_btn_count{
width: 42px;
text-align: center;
background: #fff;
border-radius: 0px 4px 4px 0px;
height:100%;
border-left: 1px solid #D0D0D0;
}
}
.ant-tooltip {
max-width: fit-content!important;
}
.detail_tag_btn_name{
padding:0px 10px;
color: #666!important;
}
.detail_tag_btn_name img{
margin-right: 10px;
}
.detail_tag_btn_count{
padding:0px 10px;
background: #fff;
border-radius: 0px 4px 4px 0px;
font-size: 12px;
height:100%;
}
.files-md{
padding:20px;
}
@ -336,6 +354,7 @@
.gitAddressClone{
margin:14px 20px!important;
display: flex;
height: 40px;
align-items: center;
@ -499,7 +518,7 @@
}
.addFile a{
display: block;
background-color: rgb(76, 172, 255,0.8);
background-color: rgba(76, 172, 255,0.8);
color: #fff;
cursor: pointer;
height: 32px;
@ -514,7 +533,7 @@
border-left: 1px solid rgba(247, 247, 247, 0.3);
}
.addFile a:active{
background-color: rgb(76, 172, 255,1);
background-color: rgba(76, 172, 255,1);
}
@ -553,7 +572,7 @@
}
.commonBox{
border:1px solid #ddd;
margin-top: 30px;
margin-top: 18px;
border-radius: 4px;
}
.commonBox .commonBox-title{
@ -567,14 +586,28 @@
border-bottom: 1px solid #d9d9d9;
border-radius: 4px 4px 0px 0px;
}
.readBox{
border:none;
&.commonBox .commonBox-info{
border:1px solid #D0D0D0;
border-top: none;
border-radius: 0px 0px 4px 4px;
padding:20px 38px;
}
}
.commonBox .commonBox-title.boxTitle{
display: flex;
justify-content: space-between;
height: 55px;
line-height: 55px;
background: #FAFCFF;
border-radius: 4px 4px 0px 0px;
border: 1px solid rgba(42, 97, 255, 0.23);
}
.synchronism{
display: block;
height: 26px;
line-height: 26px;
height: 34px;
line-height: 34px;
padding:0px 15px;
color: #fff!important;
background-color: #28BD6C;
@ -583,10 +616,19 @@
.files_info{
cursor: pointer;
}
.commonBox .commonBox-info{
padding:20px 15px;
.commonBox {
.commonBox-info{
padding:20px 15px;
}
}
.commonBox-title-read{
vertical-align: middle;
color: #000;
font-size: 14px;
&:hover {
color: #466AFF;
}
}
.commonBox-title-read{vertical-align: middle;color: #666;}
@media screen and (max-width: 370px){
.p-r-tags,.p-r-btn{
@ -627,9 +669,7 @@
.item:last-child{
border-bottom:none;
}
.gitAddressClone{
margin: 0 !important;
}
.item_title small{
font-weight: 400;
margin-left: 10px;
@ -732,4 +772,13 @@ a.color-grey-ccc:hover{
text-align: center;
display: flex;
justify-content: center;
}
.depotNum{
color: #666!important;
span:last-child{
color: #333;
}
&:hover span:last-child{
color: #2A61FF;
}
}

View File

@ -1,6 +1,7 @@
import React, { useEffect, useState } from 'react';
import { Skeleton , Tooltip} from 'antd';
import { Link } from 'react-router-dom';
import { numFormat } from 'educoder';
function DetailBanner({ history,list , owner , projectsId , isManager , url , pathname , state , urlFlag , projectDetail , platform ,open_devops }){
const [ menuName , setMenuName ] = useState(undefined);
@ -17,7 +18,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
}
},[list]);
return(
<div className="f-wrap-between mt15">
<div className="f-wrap-between mt25">
{
menuName && projectDetail ?
<ul className="headerMenu-wrapper">
@ -29,39 +30,39 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
item.menu_name === "home" &&
<li className={pathname==="about" ? "active" : ""}>
<Link to={{ pathname: `/${owner}/${projectsId}/about`, state }}>
<i className={(pathname==="" || urlFlag) ? "iconfont icon-zhuye1 color-grey-3 mr5 font-14":"iconfont icon-zhuye1 color-grey-6 font-14 mr5"}></i>
<i className={"iconfont icon-zhuye-fill color-grey-3 mr5 font-14"}></i>
<span>主页</span>
</Link>
</Link>
</li>
}
{
item.menu_name === "code" &&
<li className={(pathname==="" || urlFlag) ? "active" : ""}>
<Link to={{ pathname: `/${owner}/${projectsId}`, state }}>
<i className={(pathname==="" || urlFlag) ? "iconfont icon-daimaku color-grey-3 mr5 font-14":"iconfont icon-daimaku color-grey-6 font-14 mr5"}></i>
<i className={"iconfont icon-daimakuicon1 color-grey-3 mr5 font-14"}></i>
<span>代码库</span>
</Link>
</Link>
</li>
}
{
item.menu_name === "issues" &&
<li className={pathname==="issues" ? "active" : ""}>
<Tooltip title="易修是Issue的中文名即问题列表" placement="bottom">
<Link to={{ pathname: `/${owner}/${projectsId}/issues`, state }}>
<i className={pathname==="issues" ? "iconfont icon-renwu color-grey-3 mr5 font-14":"iconfont icon-renwu color-grey-6 font-14 mr5"}></i>
<span>易修</span>
{projectDetail && projectDetail.issues_count ? <span className="num">{projectDetail.issues_count}</span> : ""}
<Tooltip title="易修是Issue的中文名即问题列表" placement="bottom">
<i className={"iconfont icon-yixiuicon1 color-grey-3 mr5 font-14"}></i>
<span>易修</span>
</Tooltip>
{projectDetail && projectDetail.issues_count ? <span className="num">{numFormat(projectDetail.issues_count)}</span> : ""}
</Link>
</Tooltip>
</li>
}
{
item.menu_name === "pulls" && projectDetail && parseInt(projectDetail.type) !== 2 && platform ?
<li className={pathname==="pulls" ? "active" : ""}>
<Link to={{ pathname: `/${owner}/${projectsId}/pulls`, state }}>
<i className={pathname==="pulls" ? "iconfont icon-hebingqingqiu1 color-grey-3 mr5 font-14":"iconfont icon-hebingqingqiu1 color-grey-6 font-14 mr5"}></i>
<i className={"iconfont icon-hebingqingqiu1 color-grey-3 mr5 font-14"}></i>
<span>合并请求</span>
{projectDetail && projectDetail.pull_requests_count ? <span className="num">{projectDetail.pull_requests_count}</span> : ""}
{projectDetail && projectDetail.pull_requests_count ? <span className="num">{numFormat(projectDetail.pull_requests_count)}</span> : ""}
</Link>
</li>:""
}
@ -69,7 +70,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
item.menu_name === "wiki" &&
<li className={pathname === "wiki" ? "active" : ""}>
<Link to={{ pathname: `/${owner}/${projectsId}/wiki`, state }}>
<i className={pathname==="wiki" ? "iconfont icon-wiki_icon color-grey-3 mr5 font-14":"iconfont icon-wiki_icon color-grey-6 font-14 mr5"}></i>
<i className={"iconfont icon-a-wikiicon1 color-grey-3 mr5 font-14"}></i>
<span>Wiki</span>
</Link>
</li>
@ -79,29 +80,29 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
<li className={pathname==="devops" ? "active" : ""}>
{/* <Link to={{ pathname: `/${owner}/${projectsId}/devops${open_devops ? `/dispose`:""}`, state }}> */}
<Link to={{ pathname: `/${owner}/${projectsId}/devops`, state:{...state,open_devops} }}>
<i className="iconfont icon-gongzuoliu font-13 mr8"></i>工作流(beta版)
<i className="iconfont icon-gongzuoliuicon font-13 mr5 color-grey-3"></i>工作流(beta版)
{projectDetail && projectDetail.ops_count ? <span>{projectDetail.ops_count}</span> : ""}
</Link>
</li>
:""
}
{
// item.menu_name === "resources" &&
// <li className={pathname==="source" ? "active" : ""}>
// <Link to={{ pathname: `/${owner}/${projectsId}/source`, state }}>
// <i className={pathname==="source" ? "iconfont icon-ziyuanpaihanghetuijian color-grey-3 mr5 font-14":"iconfont icon-ziyuanpaihanghetuijian color-grey-6 font-14 mr5"}></i>
// <span></span>
// {projectDetail && projectDetail.source_count ? <span className="num">{projectDetail.source_count}</span> :""}
// </Link>
// </li>
item.menu_name === "resources" &&
<li className={pathname==="source" ? "active" : ""}>
<Link to={{ pathname: `/${owner}/${projectsId}/source`, state }}>
<i className={pathname==="source" ? "iconfont icon-ziyuanpaihanghetuijian color-grey-3 mr5 font-14":"iconfont icon-ziyuanpaihanghetuijian color-grey-6 font-14 mr5"}></i>
<span>资源库</span>
{projectDetail && projectDetail.source_count ? <span className="num">{projectDetail.source_count}</span> :""}
</Link>
</li>
}
{
item.menu_name === "versions" &&
<li className={pathname==="milestones" ? "active" : ""}>
<Link to={{ pathname: `/${owner}/${projectsId}/milestones`, state }}>
<i className={pathname==="milestones" ? "iconfont icon-lichengbei color-grey-3 mr5 font-14":"iconfont icon-lichengbei color-grey-6 font-14 mr5"}></i>
<span>里程碑</span>
{projectDetail && projectDetail.versions_count ? <span className="num">{projectDetail.versions_count}</span> :""}
<i className={pathname==="milestones" ? "iconfont icon-lichengbeiicon color-grey-3 mr5 font-14":"iconfont icon-lichengbeiicon color-grey-6 font-14 mr5"}></i>
<span>里程碑</span>
{projectDetail && projectDetail.versions_count ? <span className="num">{numFormat(projectDetail.versions_count)}</span> :""}
</Link>
</li>
}
@ -109,7 +110,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
item.menu_name === "activity" &&
<li className={pathname==="activity" ? "active" : ""}>
<Link to={{ pathname: `/${owner}/${projectsId}/activity`, state }}>
<i className={pathname==="activity" ? "iconfont icon-tongzhi color-grey-3 mr5 font-14":"iconfont icon-tongzhi color-grey-6 font-14 mr5"}></i>
<i className={pathname==="activity" ? "iconfont icon-dongtaiicon color-grey-3 mr5 font-14":"iconfont icon-dongtaiicon color-grey-6 font-14 mr5"}></i>
<span>动态</span>
</Link>
</li>
@ -118,7 +119,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
item.menu_name === "settings" &&
<li className={pathname === "settings" ? "active" : ""}>
<Link to={`/${owner}/${projectsId}/settings`}>
<i className={url && url.indexOf("/settings") > 0 ? "iconfont icon-cangku color-grey-3 mr5 font-14":"iconfont icon-cangku color-grey-6 font-14 mr5"}></i>
<i className={url && url.indexOf("/settings") > 0 ? "iconfont icon-cangkushezhiicon color-grey-3 mr5 font-14":"iconfont icon-cangkushezhiicon color-grey-6 font-14 mr5"}></i>
<span>仓库设置</span>
</Link>
</li>

View File

@ -6,7 +6,7 @@ function Invite({code,className}) {
return(
<div className={className}>
<span className="font-16 color-grey-6">邀请码</span>
<span className="font-16 color-ooo">邀请码</span>
<div>
<input value={code} id="devitecode" style={{width:"62px",border:"none",cursor:"default"}} readOnly/>
<CopyTool timeOut={true} beforeText={<p className="edu-txt-center">可以通过邀请码邀请成员加入项目<br/>点击复制邀请码</p>} className="ml8 font-16" inputId="devitecode"/>

View File

@ -0,0 +1,57 @@
import React , { useState , useEffect } from 'react';
import { Anchor , Input } from 'antd';
import './sub.scss';
import { Base64 } from 'js-base64';
const { Link } = Anchor;
function ReadmeCatelogue({ menuList , hash }) {
const [ goHref , setGoHref ] = useState("");
const [ value , setValue ] = useState("");
const [ menu , setMenu] = useState(menuList);
function onChange(link){
setGoHref(link);
};
function changeValue(e) {
setValue(e.target.value);
if(e.target.value){
let m = menuList.filter(i=>i.text.indexOf(e.target.value)>-1);
setMenu(m);
}else{
setMenu(menuList);
}
}
return(
<div>
<div className="searchBox">
<Input
placeholder={"请输入关键字"}
value={value}
onChange={changeValue}
prefix={<i className="iconfont icon-sousuo_icon1 font-14"></i>}/>
</div>
{
menu && menu.length>0?
<div className="anchorBox">
<Anchor affix={false} onChange={onChange}>
{
menu.map((item,key)=>{
return(
<div style={{paddingLeft:`${item.level *10}px`}} className={goHref===item.href?"items active":"items"}>
<Link href={`#${item.text}`} title={item.text} />
</div>
)
})
}
</Anchor>
</div>
:""
}
</div>
)
}
export default ReadmeCatelogue;

View File

@ -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;

View File

@ -53,7 +53,7 @@ function UpdateDescModal({form , visible , onCancel , onOk,desc,website,lesson_u
{getFieldDecorator("lesson_url",{
rules:[]
})(
<Input placeholder="实践课程链接"/>
<Input placeholder="实践课程链接" />
)}
</Form.Item>
</Form>

View File

@ -24,7 +24,68 @@
}
}
.detailsCode{
.menuslist{
z-index: 100;
width: 297px;
background: #FFFFFF;
box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5);
border-radius: 4px;
.searchBox{
padding:15px;
border-bottom: 1px solid #eee;
}
.ant-anchor-wrapper{
margin-left: 0px;
padding:5px 15px;
max-height: 255px!important;
.items{
border-radius: 4px;
margin-bottom: 5px;
cursor: pointer;
.ant-anchor-link-title{
color: #333333!important;
}
&:hover{
background-color: #F3F4F6;
}
&.active{
background-color: #2A61FF;
.ant-anchor-link-title{
color: #fff!important;
}
}
}
.ant-anchor-link{
padding:0px;
height: 30px;
line-height: 30px;
}
.ant-anchor-ink::before{
background-color: #fff;
}
}
}
.subMenu{
display: flex;
justify-content: space-between;
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;
}
}
}

View File

@ -0,0 +1,103 @@
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'
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",
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>创建于{item.commit && item.commit.time}</span>
</span>
)
}
},
{
title:"提交ID",
dataIndex:"id",
key:3,
ellipsis:true,
render:(txt,item)=>{
return (
<Tooltip placement="top" title={`最后提交日期:${`dddddd`}`}>
<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>
<Link to={`/${owner}/${projectsId}/pulls/new/${item.name}`} className="btn-83">
<i className="iconfont icon-xiazai-icon font-16 mr5"></i>TAR
</Link>
<Link to={`/${owner}/${projectsId}/pulls/new/${item.name}`} className="btn-83 ml15">
<i className="iconfont icon-xiazai-icon font-16 mr5"></i>ZIP
</Link>
</div>
)
}
}
]
return(
<div>
<SubMenu tab={"tags"} projectsId={projectsId} owner={owner}/>
<Table className="tagTable" dataSource={source} columns={columns} pagination={false}></Table>
</div>
)
}
export default Tags;

View File

@ -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;
}
}
}
}
}

View File

@ -0,0 +1,104 @@
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>
<img src={getImageUrl(`${last_commit && last_commit.committer && last_commit.image_url}`)} alt="" />
<span className="mr3 color-grey-3" style={{fontWeight:"500"}}>{last_commit && last_commit.committer && last_commit.committer.name}</span>
<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/${item.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;

View File

@ -0,0 +1,81 @@
.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{
text-decoration: underline;
}
img{
height: 20px;
width: 20px;
margin-right: 5px;
}
}
.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;
}
}
}
.treeabout{
flex:1;
text-align: right;
}
}
}

View File

@ -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-6" style={{height:"50px",lineHeight:"50px",marginBottom:"13px"}}></i>
<span className="weight500 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 weight500 font-16">该项目暂时没有发布版本</span>
}
</div>
</div>
)
}
export default Empty;

View File

@ -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;

View File

@ -0,0 +1,253 @@
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";
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 { 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 pt20">
<Form className="versionForm">
<div className="itemInline">
<Form.Item>
{getFieldDecorator("tag_name",
{ rules:[
{ required: true, message: "请输入获取或选择一个标签" }
],
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: "请输入发行版的标题" }
],
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>这是一个预览版本</Checkbox>
)}
</Form.Item>
<p className="pt20" style={{borderTop:"1px solid #eee"}}>
<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>
</Form>
<div className="versionTips">
<div className="infosTip">
<p className="font-16 mb15 weight500">标签命名建议</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 weight500">语义化版本</p>
<p>
如果你是第一次发布版本我们强烈建议你阅读<a className="color-blue">语义化版本</a>
</p>
</div>
<div className="infosTip">
<p className="font-16 mb15 weight500">附件大小说明</p>
<p>
单个附件不能超过 100MGVP 项目200M每个仓库总附件不可超过
1G推荐项目不可超过 5GGVP 项目不可超过
20G附件总容量统计包括仓库附件和发行版附件
</p>
</div>
</div>
</div>
);
}
)
);

View File

@ -0,0 +1,122 @@
import React, { useEffect , useState } from "react";
import { Link } from 'react-router-dom';
import { Spin , Button } from 'antd';
import { getImageUrl } from 'educoder';
import Empty from './Empty';
import './version.scss';
import axios from 'axios';
import RenderHtml from '../../../components/render-html';
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 } = props;
const type = props.projectDetail && props.projectDetail.type;
useEffect(()=>{
getIssueList();
},[])
// 获取列表数据
function getIssueList(){
const url = `/${owner}/${projectsId}/releases.json`;
axios.get(url).then((result) => {
if (result) {
setData(result.data);
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 renderList(releases){
if (releases && releases.length > 0) {
return (
<React.Fragment>
{
data && data.user_permission && type !== 2 &&
<div className="addReleaseBtn">
<Button type={"primary"} onClick={addFunc} className="btnblue" style={{height:"36px"}}>发布新版本</Button>
</div>
}
<div>
{
releases.map((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">
<i className="iconfont icon-biaoqianicon mr3 font-14"></i>
{item.tag_name}{item.draft === "预发行" ?"(standalone)":""}
</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}{item.draft === "预发行" ?"(standalone)版本":""}</Link>
{
(isManager || isDeveloper) && type !==2 &&
<Link to={`/${owner}/${projectsId}/releases/${item.version_id}/update`} className="ml15"><i className="iconfont icon-a-bianji1 font-16 color-grey-6"></i></Link>
}
</div>
<span className="color-grey-3 mb15">
<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>
<img src={getImageUrl(item.image_url)} alt="" className="sendAuthorImg"/>
<span className="weight500">{item.user_name}</span>
<span className="ml5">发布于{item.created_at}</span>
</span>
{
item.bodyshow &&
<div className="padding10">
<RenderHtml className="break_word_comments imageLayerParent" value={item.body} url={props.history.location}/>
</div>
}
<RenderHtml />
<p className="versionFile">
<a href={item.tarball_url}><i className="iconfont icon-tar font-14 mr10 color-grey-3"></i>{item.tag_name}.TAR.gz</a>
<a href={item.zipball_url}><i className="iconfont icon-icon font-14 mr10 color-grey-3"></i>{item.tag_name}.ZIP</a>
</p>
</div>
</div>
)
})
}
</div>
</React.Fragment>
)
} else if (releases && releases.length === 0) {
return (
<Empty
operation={data && data.user_permission && type !== 2}
addFunc={addFunc}
/>
)
}
}
function addFunc(){
props.history.push(`/${owner}/${projectsId}/releases/new`);
}
return (
<div className="releaseIndex">
<div className="releasesVersion">
<Spin spinning={isSpin}>
{renderList(releases)}
</Spin>
</div>
</div>
)
}
export default version;

View File

@ -0,0 +1,338 @@
.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;
}
.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: #5091FF;
border-radius: 50%;
}
.sendAuthorImg{
width: 20px;
height: 20px;
border-radius: 50%;
margin-right: 5px;
}
}
.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;
}
.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: 0px;
}
}
.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;
}

View File

@ -2,9 +2,10 @@ import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { Input , Form , Select , Checkbox , Button , Spin , AutoComplete, Modal } from 'antd';
import { Base64 } from 'js-base64';
import { AlignCenter } from '../Component/layout';
import '../css/index.scss';
import './new.css'
import './new.scss'
import axios from 'axios';
const Option = Select.Option;
@ -44,7 +45,12 @@ class Index extends Component {
project_category_name: undefined,
license_name: undefined,
ignore_name: undefined,
descNum:0
descNum:0,
categoreFlag:false,
languageFlag:false,
ignoreFlag:false,
licenseFlag:false,
}
}
componentDidMount = () => {
@ -149,7 +155,7 @@ class Index extends Component {
if (mirror_status === 2 && sessionStorage.newProjectValue) {
Modal.warning({
title: '警告',
content: '镜像项目创建失败!请按操作规范重新创建项目!',
content: '项目导入失败!请按操作规范重新导入项目!',
});
let newProjectValue = JSON.parse(sessionStorage.newProjectValue);
if (newProjectValue) {
@ -189,12 +195,16 @@ class Index extends Component {
subMitFrom = () => {
this.props.form.validateFieldsAndScroll((err, values) => {
console.log(values);
if (!err) {
this.setState({
isSpin: true
})
const { projectsType } = this.props.match.params;
const { project_language_id, project_category_id, license_id, ignore_id , owners_id , owners_name } = this.state;
const {
project_language_id, project_category_id, license_id, ignore_id , owners_id ,
ignoreFlag,licenseFlag,categoreFlag,languageFlag
} = this.state;
const decoderPass = Base64.encode(values.password);
const url = (projectsType && projectsType === "mirror") ? "/projects/migrate.json" : "/projects.json";
// 新建项目的时候,暂存数据,如果失败,返回的时候可以重新赋值
@ -202,10 +212,10 @@ class Index extends Component {
axios.post(url, {
...values,
auth_password:decoderPass,
project_language_id,
project_category_id,
license_id,
ignore_id,
project_language_id:languageFlag ? project_language_id : undefined,
project_category_id:categoreFlag ? project_category_id : undefined,
license_id:licenseFlag ? license_id : undefined,
ignore_id:ignoreFlag ? ignore_id : undefined,
user_id:owners_id
}).then((result) => {
if (result && result.data.id) {
@ -313,41 +323,28 @@ class Index extends Component {
mirrorCheck,
descNum
descNum,
ignoreFlag,
licenseFlag,
languageFlag,
categoreFlag
} = this.state;
return (
<div className="main back-white" style={{padding:"0px",border:"none"}}>
<div className="newPanel">
<div className="newPanel_title">创建{projectsType && projectsType === "mirror" ? "镜像" : "托管"}项目</div>
<div className="newPanel_title">{projectsType && projectsType === "mirror" ? "导入" : "新建"}项目</div>
<Spin spinning={isSpin}>
<Form>
<div className="newPanel_content">
<Form.Item
label="拥有者"
>
{getFieldDecorator('user_id', {
rules: [{
required: true, message: '请选择拥有者'
},{
validator:(rule, value, callback) => this.checkId(rule, value, callback, OwnerList, '拥有者')
}],
})(
<AutoComplete
placeholder="请选择拥有者"
onChange={(value, e) => this.ChangePlatform(value, e, 'owners', OwnerList)}
className="plateAutoComplete"
onBlur={(value) => this.blurCategory(value, OwnerList, "owners")}
>
{owners_list}
</AutoComplete>
)}
</Form.Item>
{
{
projectsType && projectsType === "mirror" &&
<React.Fragment>
<Form.Item
label="镜像版本库地址"
label="导入仓库URL"
style={{ marginBottom: "0px" }}
colon={false}
>
{getFieldDecorator('clone_addr', {
rules: [{
@ -362,14 +359,16 @@ class Index extends Component {
}
{
projectsType && projectsType === "mirror" &&
<React.Fragment>
<div className="pb10">
<p className="mt10 mb10 color-grey-3 pointer" onClick={this.changeMirrorCheck}>
需要授权验证<i className={mirrorCheck?"iconfont icon-xiajiantou font-13 ml10 color-grey-8":"iconfont icon-youjiantou font-13 ml10 color-grey-8"}></i>
<span className="ml20 font-12 color-red">如果源项目为公有仓库禁止填写用户名密码如果源项目为私有仓库则必须填写正确的用户名和密码!</span></p>
需要授权验证<i className={mirrorCheck ? "iconfont icon-xiajiantou font-13 ml10 color-grey-8":"iconfont icon-youjiantou font-13 ml10 color-grey-8"}></i>
<span className="ml20 font-12 color-red">如果导入项目为私有仓库则必须填写相应平台正确的用户名和密码</span>
</p>
{
mirrorCheck &&
<div className="df mb20" style={{alignItems:'center'}}>
<div className="df mb10" style={{alignItems:'center'}}>
<span className="mr10">用户名</span>
<input type="password" style={{display:"none"}} />
<Form.Item
style={{ marginBottom: "0px" }}
label=""
@ -383,153 +382,153 @@ class Index extends Component {
<span className="mr10">密码</span>
<Form.Item
style={{ marginBottom: "0px" }}
label=""
>
{getFieldDecorator('password', {
rules: [],
})(
<Input placeholder="请输入对应平台的登录密码" type="password" style={{width:"240px"}}/>
<Input.Password placeholder="请输入对应平台的登录用户名" autocomplete='new-password' style={{width:"240px"}}/>
)}
</Form.Item>
</div>
}
</React.Fragment>
</div>
}
<AlignCenter>
<Form.Item
label="拥有者"
style={{width:"260px"}}
colon={false}
className="explainPos"
>
{getFieldDecorator('user_id', {
rules: [{
required: true, message: '请选择拥有者'
},{
validator:(rule, value, callback) => this.checkId(rule, value, callback, OwnerList, '拥有者')
}],
})(
<AutoComplete
style={{width:"260px",height:"35px"}}
placeholder="请选择拥有者"
onChange={(value, e) => this.ChangePlatform(value, e, 'owners', OwnerList)}
className="plateAutoComplete"
onBlur={(value) => this.blurCategory(value, OwnerList, "owners")}
>
{owners_list}
</AutoComplete>
)}
</Form.Item>
<span className="ml10 mr10 mt10 font-18">/</span>
<Form.Item
label="项目名称"
className="flex1 explainPos"
colon={false}
>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请填写项目名称'
}],
})(
<Input placeholder="例如:团队协作方法与研究" maxLength={50}/>
)}
</Form.Item>
</AlignCenter>
<Form.Item
label="项目名称"
label={<span>项目标识 <span className="color-grey-9">(项目url标识部分)</span></span>}
colon={false}
>
{getFieldDecorator('name', {
{getFieldDecorator('repository_name', {
rules: [{
required: true, message: '请填写项目名称'
required: true, message: '请填写项目标识'
}],
})(
<Input placeholder="例如:团队协作方法与研究" maxLength={50}/>
<Input placeholder="项目标识请使用与项目相关的英文关键字" maxLength={100} />
)}
</Form.Item>
<div className="pr">
<span className="toprightNum">{descNum}/200</span>
<Form.Item
label="项目简介"
colon={false}
style={{marginBottom:"0px"}}
>
{getFieldDecorator('description', {
rules: [{
required: true, message: '请填写项目简介'
}],
rules: [],
})(
<Input.TextArea maxLength={200} placeholder="项目的介绍" autoSize={{ minRows: 2, maxRows: 6 }} onChange={this.changeDesc}/>
)}
</Form.Item>
</div>
<Form.Item
label="仓库名称"
>
{getFieldDecorator('repository_name', {
rules: [{
required: true, message: '请填写仓库名称'
}],
})(
<Input placeholder="仓库名称请使用与项目相关的英文关键字" maxLength={100} />
)}
</Form.Item>
<Form.Item
label="项目类别"
>
{getFieldDecorator('project_category', {
rules: [{
required: true, message: '请选择大类别',
}, {
validator: (rule, value, callback) => this.checkId(rule, value, callback, CategoryList, '项目类别')
}],
})(
<AutoComplete
placeholder="请选择项目类别"
onChange={(value, e) => this.ChangePlatform(value, e, 'project_category', CategoryList)}
className="plateAutoComplete"
onBlur={(value) => this.blurCategory(value, CategoryList, "project_category")}
>
{project_category_list}
</AutoComplete>
)}
</Form.Item>
<Form.Item
label="项目语言"
>
{getFieldDecorator('project_language', {
rules: [{
required: true, message: '请选择项目语言'
}, {
validator: (rule, value, callback) => this.checkId(rule, value, callback, LanguageList, '项目语言')
}],
})(
<AutoComplete
placeholder="请选择项目语言"
onChange={(value, e) => this.ChangePlatform(value, e, 'project_language', LanguageList)}
className="plateAutoComplete"
onBlur={(value) => this.blurCategory(value, LanguageList, "project_language")}
>
{project_language_list}
</AutoComplete>
)}
</Form.Item>
{
(projectsType === "deposit" || !projectsType) &&
<React.Fragment>
<Form.Item
label=".gitignore"
className="privatePart"
>
{getFieldDecorator('ignore', {
rules: [{
required: true, message: '请选择gitignore'
}, {
validator: (rule, value, callback) => this.checkId(rule, value, callback, GitignoreList, 'gitignore')
}],
})(
<AutoComplete
placeholder="请选择gitignore用来定义哪些文件不需要添加到版本管理中"
onChange={(value, e) => this.ChangePlatform(value, e, 'ignore', GitignoreList)}
className="plateAutoComplete"
onBlur={(value) => this.blurCategory(value, GitignoreList, "ignore")}
>
{ignore_list}
</AutoComplete>
{getFieldDecorator('ignoreFlag')(
<Checkbox checked={ignoreFlag} onChange={(e)=>this.setState({ignoreFlag:e.target.checked})}>.gitignore</Checkbox>
)}
</Form.Item>
{ ignoreFlag &&
<Form.Item>
{getFieldDecorator('ignore', {
rules: [{
required: ignoreFlag, message: '请选择gitignore'
}, {
validator: (rule, value, callback) => this.checkId(rule, value, callback, GitignoreList, 'gitignore')
}],
})(
<AutoComplete
placeholder="请选择gitignore用来定义哪些文件不需要添加到版本管理中"
onChange={(value, e) => this.ChangePlatform(value, e, 'ignore', GitignoreList)}
className="plateAutoComplete"
onBlur={(value) => this.blurCategory(value, GitignoreList, "ignore")}
>
{ignore_list}
</AutoComplete>
)}
</Form.Item>
}
<Form.Item
label="开源许可证"
className="privatePart"
>
{getFieldDecorator('license', {
rules: [{
required: true, message: '请选择开源许可证'
}, {
validator: (rule, value, callback) => this.checkId(rule, value, callback, LicensesList, '开源许可证')
}],
})(
<AutoComplete
placeholder="请选择开源许可证"
onChange={(value, e) => this.ChangePlatform(value, e, 'license', LicensesList)}
className="plateAutoComplete"
onBlur={(value) => this.blurCategory(value, LicensesList, "license")}
>
{license_list}
</AutoComplete>
{getFieldDecorator('licenseFlag')(
<Checkbox checked={licenseFlag} onChange={(e)=>this.setState({licenseFlag:e.target.checked})}>开源许可证</Checkbox>
)}
</Form.Item>
{ licenseFlag &&
<Form.Item>
{getFieldDecorator('license', {
rules: [{
required: licenseFlag, message: '请选择开源许可证'
}, {
validator: (rule, value, callback) => this.checkId(rule, value, callback, LicensesList, '开源许可证')
}],
})(
<AutoComplete
placeholder="请选择开源许可证"
onChange={(value, e) => this.ChangePlatform(value, e, 'license', LicensesList)}
className="plateAutoComplete"
onBlur={(value) => this.blurCategory(value, LicensesList, "license")}
>
{license_list}
</AutoComplete>
)}
</Form.Item>
}
</React.Fragment>
}
<Form.Item
label="可见性"
style={{ margin: "0px" }}
className="privatePart"
>
{getFieldDecorator('private')(
<Checkbox value="limit">将项目设为私有<span className="ml15 font-13 color-grey-9">(只有项目所有人或拥有权限的项目成员才能看到)</span></Checkbox>
<Checkbox value="limit">将项目设为私有<span className="font-13 color-grey-9">(只有项目所有人或拥有权限的项目成员才能看到)</span></Checkbox>
)}
</Form.Item >
{
projectsType && projectsType === "mirror" &&
<Form.Item
label="迁移类型:"
style={{ margin: "0px" }}
className="privatePart"
>
{getFieldDecorator('is_mirror')(
@ -537,12 +536,69 @@ class Index extends Component {
)}
</Form.Item >
}
<div>
<Form.Item
style={{ margin: "0px" }}
className="privatePart"
>
{getFieldDecorator('categoreFlag')(
<Checkbox checked={categoreFlag} onChange={(e)=>this.setState({categoreFlag:e.target.checked})}>项目类别</Checkbox>
)}
</Form.Item>
{categoreFlag &&
<Form.Item
className="privatePart"
>
{getFieldDecorator('project_category', {
rules: [{
required: categoreFlag, message: '请选择项目类别',
}, {
validator: (rule, value, callback) => this.checkId(rule, value, callback, CategoryList, '项目类别')
}],
})(
<AutoComplete
placeholder="请选择项目类别"
onChange={(value, e) => this.ChangePlatform(value, e, 'project_category', CategoryList)}
className="plateAutoComplete"
onBlur={(value) => this.blurCategory(value, CategoryList, "project_category")}
>
{project_category_list}
</AutoComplete>
)}
</Form.Item>
}
<Form.Item
className="privatePart"
>
{getFieldDecorator('languageFlag')(
<Checkbox checked={languageFlag} onChange={(e)=>this.setState({languageFlag:e.target.checked})}>项目语言</Checkbox>
)}
</Form.Item>
{languageFlag &&
<Form.Item>
{getFieldDecorator('project_language', {
rules: [{
required: languageFlag, message: '请选择项目语言'
}, {
validator: (rule, value, callback) => this.checkId(rule, value, callback, LanguageList, '项目语言')
}],
})(
<AutoComplete
placeholder="请选择项目语言"
onChange={(value, e) => this.ChangePlatform(value, e, 'project_language', LanguageList)}
className="plateAutoComplete"
onBlur={(value) => this.blurCategory(value, LanguageList, "project_language")}
>
{project_language_list}
</AutoComplete>
)}
</Form.Item>
}
<div className="mt20">
<span className="ant-form-item-required"></span>
</div>
<Form.Item className="formTip mt20">
<Button type="primary" onClick={this.subMitFrom} className="mr20">创建项目</Button>
<Link to={'/projects'} className="btn_32">取消</Link>
<Button type="primary" onClick={this.subMitFrom} className="mr20">{projectsType && projectsType === "mirror" ? "导入" : "创建"}项目</Button>
<Link to={'/explore'} className="btn_32">取消</Link>
</Form.Item>
</div>
</Form>

View File

@ -12,7 +12,13 @@
border-bottom: 1px solid #f0f0f0
}
.newPanel_content{
padding:1rem 2rem;
padding:2rem;
}
.newPanel_content form .ant-row.ant-form-item{
margin-bottom: 25px;
}
.newPanel_content .ant-form-item-label label{
font-size: 16px;
}
.newPanel_content .ant-form-item-control-wrapper{
flex: 1;
@ -25,24 +31,35 @@
height: 35px;
line-height: 35px;
}
.newContent_inline{
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items:flex-end
}
.explainPos{
.ant-form-explain{
position: absolute;
}
}
.newContent_inline > .ant-form-item:nth-child(2){
margin-left: 20px;
}
.newPanel_content .privatePart .ant-form-item-label{
margin-left: 0px;
.privatePart{
margin-bottom: 0px!important;
.ant-form-item-label{
margin-left: 0px;
}
}
.newPanel_content .ant-form-item-label{
line-height: 25px;
height: 25px;
margin-left: -0.8rem;
}
.plateAutoComplete{
.ant-input{
height: 34px!important;
}
}
@media screen and (max-width: 750px){
.newPanel_content{

View File

@ -39,7 +39,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;

View File

@ -61,7 +61,7 @@ function UndoEvent(props){
return(
<div>
<Spin spinning={isSpin}>
<div style={{minHeight:"400px"}}>
<div >
{
list && list.length > 0 ?
<ul className="notifyList">

View File

@ -119,11 +119,12 @@ class Milepost extends Component {
}
ChangePage = (page) => {
document.body.scrollIntoView();
this.setState({
page
})
this.getList(page);
const { status } = this.state;
this.getList( page , status );
}
// 排序
@ -260,7 +261,7 @@ class Milepost extends Component {
{
data && data.versions_count > limit ?
<div className="mt30 mb50 edu-txt-center">
<Pagination simple defaultCurrent={page} total={data && data.versions_count} pageSize={limit} onChange={this.ChangePage}></Pagination>
<Pagination simple current={page} total={data && data.versions_count} pageSize={limit} onChange={this.ChangePage}></Pagination>
</div> : ""
}
</div>

View File

@ -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"},
]

View File

@ -34,13 +34,6 @@ export default Form.create()(
const { getFieldDecorator, validateFields, setFieldsValue } = form;
const { OIdentifier, groupId } = match.params;
useEffect(()=>{
setFieldsValue({
authorize:"read",
includes_all_project:0
})
},[])
useEffect(() => {
if (GroupDetail) {
setOnwers(GroupDetail.authorize === "owner");

View File

@ -61,14 +61,14 @@ function List(props){
</Menu>
)
const menu_new=(
<Menu>
<Menu.Item key="updated_on">
<CheckProfile {...props} sureFunc={()=>{props.history.push(`/projects/deposit/new/${OIdentifier}`)}}>新建托管项目</CheckProfile>
</Menu.Item>
<Menu.Item key="created_on">
<CheckProfile {...props} sureFunc={()=>{props.history.push(`/projects/mirror/new/${OIdentifier}`)}}>新建镜像项目</CheckProfile>
</Menu.Item>
</Menu>
<ul>
<li>
<CheckProfile {...props} sureFunc={()=>{props.history.push(`/projects/deposit/new/${OIdentifier}`)}}>新建项目</CheckProfile>
</li>
<li>
<CheckProfile {...props} sureFunc={()=>{props.history.push(`/projects/mirror/new/${OIdentifier}`)}}>导入项目</CheckProfile>
</li>
</ul>
)
return(
@ -81,7 +81,7 @@ function List(props){
</div>
<p>
{ organizeDetail && organizeDetail.can_create_project ?
<Sort menu={menu_new}>
<Sort menu={menu_new} overlayClassName={"newPopUl"}>
<a className="addBtn mr30">+&nbsp;新建项目</a>
</Sort>
:""}

View File

@ -108,7 +108,7 @@ function RightBox({ OIdentifier , history , admin , showCompeleteDialog ,complet
<div>
{
(item.is_admin || item.is_member) ?
<Link to={`/${OIdentifier}/teams/${item.id}`}><ColorListName>{item.name}</ColorListName></Link>
<Link to={`/${OIdentifier}/teams/${item.id}`}><ColorListName>{item.nickname}</ColorListName></Link>
:
<ColorListName>{item.name}</ColorListName>
}

View File

@ -1,5 +1,5 @@
import React, { forwardRef , useCallback , useEffect, useState } from 'react';
import { Form , Input , Radio ,Checkbox , Divider , Button } from 'antd';
import { Form , Input , Radio ,Checkbox , Divider , Button , InputNumber } from 'antd';
import { WhiteBack , FlexAJ } from '../../Component/layout';
import Title from '../../Component/Title';
import styled from 'styled-components';
@ -31,7 +31,8 @@ export default Form.create()(
useEffect(()=>{
if(organizeDetail){
setFieldsValue({
...organizeDetail
...organizeDetail,
max_repo_creation:organizeDetail.max_repo_creation===-1 ? "":organizeDetail.max_repo_creation
})
setImage(organizeDetail.avatar_url);
setDescNum(organizeDetail.description ? organizeDetail.description.length : 0);
@ -39,10 +40,10 @@ export default Form.create()(
},[organizeDetail])
const helper = useCallback(
(label, name, rules, widget , isRequired , flag ) => (
(label, name, rules, widget , isRequired , flag , help ) => (
<div>
<span className={isRequired?"required":""}>{label}</span>
<Form.Item>
<Form.Item help={help}>
{getFieldDecorator(name, { rules, validateFirst: true , valuePropName:flag ? "checked":"value" })(widget)}
</Form.Item>
</div>
@ -175,7 +176,8 @@ export default Form.create()(
'最大仓库数:',
"max_repo_creation",
[],
<Input value="-1" style={{width:"350px"}}/>
<InputNumber value="-1" style={{width:"350px"}}/>,false,false,
"当输入栏为空时,默认数量无限制"
)}
<p>选择头像:</p>
<UploadImage url={getImageUrl(`/${image}`)} getImage={getImage}/>

View File

@ -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-14">拖动文件或点击此处上传</p>
</Dragger>
)
}

View File

@ -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 才是创建成功,其余均为创建失败

View File

@ -93,7 +93,13 @@ class CommonUsers extends Component {
{count === 0 ? (
<NoneData _html="暂时还没有相关数据!" />
) : (
<UserList users={users} userClass={'w-25'} successFunc={this.getUsersList} {...this.props}></UserList>
<UserList
users={users}
userClass={'w-25'}
successFunc={this.getUsersList}
notReset={true}
{...this.props}
></UserList>
)}
</div>
</Spin>

View File

@ -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">
单个附件不能超过 100MGVP 项目200M每个仓库总附件不可超过
1G推荐项目不可超过 5GGVP 项目不可超过
20G附件总容量统计包括仓库附件和发行版附件
</p>
</div>
</div>
</div>
);
}
)
);

View File

@ -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;
}

View File

@ -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;

View File

@ -0,0 +1,51 @@
.welcome-main {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
width: 1200px;
min-height: 400px;
padding: 20px;
margin: 20px auto;
background: #fafcff;
font-family: "PingFangSC-Medium";
border-radius: 4px;
border: 1px solid rgba(42, 97, 255, 0.23);
}
.welcome-main .icon-huanying_icon {
font-size: 48px !important;
font-weight: 700;
}
.welcome-main .welcome-title {
display: inline-flex;
align-items: center;
margin: 10px 0;
font-size: 26px;
color: #333333;
font-weight: 500;
}
.welcome-main .wiki-title {
display: inline-block;
max-width: 20em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.welcome-main .welcome-content {
font-size: 14px;
color: #333333;
font-weight: 400;
}
.welcome-main .wiki-line {
margin: 50px 0 40px;
width: 400px;
height: 1px;
background: #eeeeee;
}
.welcome-main .welcome-des {
font-size: 16px;
color: #333333;
font-weight: 500;
}
/*# sourceMappingURL=index.css.map */

View File

@ -1,6 +1,6 @@
import * as React from 'react';
import classNames from 'classnames';
import { Icon, Tree } from 'antd';
import { Tree } from 'antd';
import omit from 'omit.js';
import debounce from 'lodash/debounce';
import { conductExpandParent, convertTreeToEntities } from 'rc-tree/lib/util';

View File

@ -0,0 +1,56 @@
.delete-modal .ant-modal-header {
padding: 9px 24px;
background: #f8f8f8;
border-bottom: 1px solid #eee;
}
.delete-modal .ant-modal-title {
text-align: left;
}
.delete-modal .ant-modal-close {
top: 0px !important;
}
.delete-modal .ant-modal-close-x {
font-size: 24px;
}
.delete-modal .ant-modal-body {
text-align: center;
}
.delete-modal .delete-title {
display: flex;
justify-content: center;
align-items: center;
margin: 2rem 0 1rem !important;
font-size: 16px;
color: #333;
letter-spacing: 0;
line-height: 29px;
font-weight: 400;
}
.delete-modal .red-circle {
align-self: flex-start;
color: #ca0002;
font-size: 1.5rem !important;
}
.delete-modal .delete-descibe {
font-size: 14px;
color: #666;
line-height: 33px;
font-weight: 400;
}
.delete-modal .ant-modal-footer {
padding: 2rem 0;
text-align: center;
border: 0;
}
.delete-modal .ant-modal-footer .ant-btn {
width: 6rem;
}
.delete-modal .foot-submit {
margin-left: 3rem;
color: #df0002;
}
.delete-modal .foot-submit:hover {
border-color: #df0002;
}
/*# sourceMappingURL=index.css.map */

View File

@ -11,7 +11,10 @@ ul,ol,dl{
font-size: 22px;
font-weight: normal;
line-height: 30px;
max-width: 850px;
max-width: 690px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
.projectN{
word-break: break-all;
}
@ -140,7 +143,7 @@ form.ant-form{
}
form{
.ant-row.ant-form-item{
margin-bottom: 15px;
margin-bottom: 20px;
}
}
@media screen and (max-width: 1000px){
@ -270,4 +273,41 @@ form{
background-color: #DF0002!important;
border-color: #DF0002;
color: #fff;
}
.newPopUl{
li{
height: 30px;
line-height: 30px;
border-bottom: 1px solid #eee;
min-width: 78px;
text-align: center;
&:last-child{
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;
&:hover,&:active{
background: #F3F4F6;
color: #333333!important;
}
}
a.hover:hover{
text-decoration: underline;
}
button.ant-btn-primary.btnblue{
background-color:rgba(70, 106, 255, 1);
&:hover{
background-color:rgba(70, 106, 255, 0.85);
}
}

247
src/forge/users/Index.css Normal file
View File

@ -0,0 +1,247 @@
.headerbox {
padding: 20px;
border-bottom: 1px solid #E0E0E0;
display: flex;
align-items: center;
justify-content: space-between;
}
.headerbox > div {
width: 400px;
}
.headerbox > p {
display: flex;
align-items: center;
}
.headerbox > p a {
color: #5091FF;
margin-left: 30px;
font-size: 16px;
display: flex;
align-items: center;
}
.headerbox .ant-btn.ant-input-search-button {
margin-top: -1px;
margin-right: -1px;
}
.echartBox {
border: 1px solid #DEDEDE;
}
.echartBox > p {
color: #999;
padding: 15px 20px;
text-align: center;
}
.contentBox {
padding: 20px 20px 0px 20px;
}
.contentBox > div {
margin-bottom: 20px;
display: flex;
align-items: center;
padding: 20px 25px;
background-color: #fafafa;
}
.contentBox > div .imgBox {
width: 190px;
height: 90px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20px;
background-color: #fff;
}
.contentBox > div .imgBox img {
max-width: 90%;
max-height: 90%;
}
.contentBox .item-news {
display: flex;
justify-content: space-between;
font-size: 12px;
color: #888;
margin-top: 3px;
margin-bottom: 0px;
}
.contentBox .teamdesc {
word-break: break-all;
line-height: 20px;
}
.infosType {
padding: 20px 30px 0px 20px;
display: flex;
justify-content: space-between;
}
.infosType .infoStatus {
height: 30px;
background: white;
border-radius: 15px;
border: 1px solid #dddddd;
line-height: 30px;
font-size: 12px;
color: #888;
display: flex;
}
.infosType .infoStatus > span {
display: block;
padding: 0px 12px;
border-radius: 15px;
cursor: pointer;
}
.infosType .infoStatus > span.active {
background-color: #5091FF;
color: #fff;
padding: 0px 15px;
}
.infosType .infoStatus .statusDivider {
margin: 8px 0 0 0 !important;
}
.userDescription {
color: #666666;
line-height: 18px;
text-align: left;
margin: 10px 0px;
word-break: break-all;
text-align: justify;
font-size: 16px;
text-align: center;
}
.focusBox, .infoBox {
width: 100% !important;
display: inline-block;
margin-top: 30px;
padding-top: 30px;
border-top: 1px solid #f1f1f1;
}
.infoBox {
padding-bottom: 10px;
text-align: left;
line-height: 28px;
color: #666;
margin-top: 20px;
}
.infoBox > div {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.infoBox i {
color: #DEDEDE;
font-size: 15px !important;
}
.infoBox span {
margin-left: 10px;
}
.headimg {
position: relative;
display: block;
}
.headimg img {
width: 110px;
height: 110px;
border-radius: 50%;
}
.headimg span {
position: absolute;
bottom: -6px;
right: 0px;
left: 65px;
}
.headimg span i {
font-size: 25px !important;
border-radius: 50%;
color: #fff;
}
.headimg span i.icon-nan1 {
background-color: #1890FF;
}
.headimg span i.icon-nv1 {
background-color: pink;
}
ul.ant-menu.menuStyle {
padding: 0px 30px;
font-size: 16px;
}
ul.ant-menu.menuStyle li {
height: 70px;
line-height: 70px;
padding: 0px;
margin-right: 30px !important;
border-bottom: transparent !important;
}
.disposeInfo {
padding: 0px 30px;
min-height: 400px;
}
.disposeInfo .disposeItem {
display: flex;
justify-content: space-between;
padding: 30px 0px;
border-bottom: 1px solid #eee;
}
.authTag {
display: inline-block;
padding: 0px 10px;
border-radius: 12px;
font-size: 12px;
height: 22px;
line-height: 22px;
}
.authTag.red {
border: 1px solid #F73030;
color: #F73030;
}
.authTag.green {
border: 1px solid #28BD6C;
color: #28BD6C;
}
.CIList {
padding: 0px 30px;
min-height: 400px;
}
.CIList li {
display: flex;
justify-content: space-between;
padding: 28px 0px;
border-bottom: 1px solid #eee;
}
.infosRightMenu .ant-menu-item {
padding: 0px;
margin: 0px 20px !important;
font-size: 17px;
height: 32px;
line-height: 0px;
border-bottom: 2px solid transparent !important;
position: relative;
}
.infosRightMenu .ant-menu-item a > i {
font-size: 15px !important;
margin-right: 8px;
}
.infosRightMenu .ant-menu-item .menuNum {
font-size: 12px;
margin-left: 3px;
color: #FF6E21;
}
.infosRightMenu .ant-menu-item.ant-menu-item-selected::before {
position: absolute;
width: 100%;
bottom: -1px;
height: 2px;
left: 0px;
background-color: #1890ff;
content: "";
}
/*# sourceMappingURL=Index.css.map */

View File

@ -114,14 +114,14 @@ class InfosUser extends Component {
);
newItem =()=> (
<Menu>
<Menu.Item key="created_mirror">
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/mirror/new')}}>新建镜像项目</CheckProfile>
</Menu.Item>
<Menu.Item key="created_deposit">
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/deposit/new')}} >新建托管项目</CheckProfile>
</Menu.Item>
</Menu>
<ul>
<li>
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/deposit/new')}} >新建项目</CheckProfile>
</li>
<li>
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/mirror/new')}}>导入项目</CheckProfile>
</li>
</ul>
);
@ -192,6 +192,7 @@ class InfosUser extends Component {
trigger={["hover"]}
placement="bottom"
className="mr50"
overlayClassName="newPopUl"
>
<a className="ant-dropdown-link">
<span className="color-blue font-16">

View File

@ -6,7 +6,7 @@ function TeamItem({item,history}){
<div onClick={()=>{history.push(`/${item.name}`)}} style={{cursor:"pointer"}}>
<div className="imgBox"><img alt="" src={getImageUrl(`/${item.avatar_url}`)}/></div>
<div style={{flex:'1'}}>
<span className="mb5 font-18 color-grey-3 task-hide">{item.name}</span>
<span className="mb5 font-18 color-grey-3 task-hide" style={{display:"block",maxWidth:"588px"}}>{item.nickname}</span>
<div className="task-hide-2 teamdesc">
{item.description}
</div>

BIN
src/images/add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -134,6 +134,7 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
},
toolbarIconsClass: {
"line-break": "fa-minus",
"fullScreen":"iconfont icon-fangdaicon font-14"
},
toolbarCustomIcons: {
"inline-latex": "<a title='行内公式' class='latex' ><i name='inline-latex' class='fa iconfont icon-hangneigongshi font-14'></i></a>",
@ -150,6 +151,10 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
}
cm.replaceSelection(NULL_CH)
},
"fullScreen":function(cm,icon,cursor,selection){
icon.addClass("none");
console.log(cm,icon)
},
"inline-latex": function (cm, icon, cursor, selection) {
cm.replaceSelection("$$" + selection + "$$");
cm.setCursor(cursor.line, cursor.ch + 2);
@ -164,7 +169,8 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
lang: {
toolbar: {
"latex": "多行公式",
"line-break": "换行"
"line-break": "换行",
"fullScreen":"开启全屏"
}
},
onload: function () {
@ -229,7 +235,7 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
if (resizeBarEl.current) {
let el = resizeBarEl.current
let dragging = false
let startY = 0
let startY = 0
function onMouseDown(e) {
dragging = true
startY = e.pageY

View File

@ -392,9 +392,6 @@ a.white-btn.use_scope-btn:hover{
border-color: #096dd9;
}
/*.ant-btn:hover, .ant-btn:focus, .ant-btn:active, .ant-btn.active{*/
/* background-color: #4CACFF;*/
/*}*/
.newViewAfter .ant-input{
line-height: 40px !important;