diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..7a73a41bf --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4771ae99a..9ea84263c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3425,9 +3425,9 @@ "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" }, "clipboard": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz", - "integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz", + "integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==", "requires": { "good-listener": "^1.2.2", "select": "^1.1.2", @@ -7286,7 +7286,8 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "optional": true }, "aproba": { "version": "1.2.0", @@ -7703,7 +7704,8 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -7759,6 +7761,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -7802,12 +7805,14 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "optional": true }, "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "optional": true } } }, diff --git a/package.json b/package.json index ff7a86851..04142cb4d 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "case-sensitive-paths-webpack-plugin": "2.1.1", "chalk": "1.1.3", "classnames": "^2.2.5", - "clipboard": "^2.0.6", + "clipboard": "^2.0.8", "code-prettify": "^0.1.0", "codemirror": "^5.53.0", "connected-react-router": "4.4.1", @@ -125,7 +125,7 @@ "scripts": { "start": "node --max_old_space_size=15360 scripts/start.js", "build": "cross-env NODE_ENV=production node --max_old_space_size=15360 scripts/build.js", - "test-build": "NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js", + "test-build": "cross-env NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js", "pre-build": "NODE_ENV=preBuild node --max_old_space_size=15360 scripts/build.js", "gen_stats": "NODE_ENV=production webpack --profile --config=./config/webpack.config.prod.js --json > stats.json", "ana": "webpack-bundle-analyzer ./stats.json", diff --git a/public/css/edu-purge.css b/public/css/edu-purge.css index fe8784145..708648ebb 100644 --- a/public/css/edu-purge.css +++ b/public/css/edu-purge.css @@ -1526,7 +1526,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; } @@ -1546,6 +1554,9 @@ a.edu-txt-w80, .font-25 { font-size: 25px !important; } +.font-26 { + font-size: 26px !important; +} .font-24 { font-size: 24px !important; @@ -1567,6 +1578,9 @@ a.edu-txt-w80, font-size: 36px !important; } +.font-40 { + font-size: 40px !important; +} .font-50 { font-size: 50px !important; } @@ -1752,6 +1766,14 @@ a.decoration { margin-bottom: 10px; } +.mb12 { + margin-bottom: 12px; +} + +.mb13 { + margin-bottom: 13px; +} + .mb14 { margin-bottom: 14px; } @@ -2440,7 +2462,7 @@ a.hoverLine:hover{ .color-grey-9 { - color: #333333 !important; + color: #999 !important; } a:hover{ @@ -2466,7 +2488,7 @@ a:hover{ .color-grey-B3 { color: #B3B3B3 !important; } -` + .color-grey-B4 { color: #B4B4B4 !important; } diff --git a/public/css/iconfont.css b/public/css/iconfont.css index b670775ca..3866189c2 100644 --- a/public/css/iconfont.css +++ b/public/css/iconfont.css @@ -1,8 +1,8 @@ @font-face { font-family: "iconfont"; /* Project id 2340181 */ - src: url('iconfont.woff2?t=1632738478946') format('woff2'), - url('iconfont.woff?t=1632738478946') format('woff'), - url('iconfont.ttf?t=1632738478946') format('truetype'); + src: url('iconfont.woff2?t=1632964996877') format('woff2'), + url('iconfont.woff?t=1632964996877') format('woff'), + url('iconfont.ttf?t=1632964996877') format('truetype'); } .iconfont { @@ -13,6 +13,10 @@ -moz-osx-font-smoothing: grayscale; } +.icon-wenjian7:before { + content: "\e8e0"; +} + .icon-xiangyoujiantou:before { content: "\e8de"; } diff --git a/public/css/iconfont.js b/public/css/iconfont.js index 1363ceabe..0e23ffb85 100644 --- a/public/css/iconfont.js +++ b/public/css/iconfont.js @@ -1 +1 @@ -!function(c){var l,a,h,i,o,z='',t=(t=document.getElementsByTagName("script"))[t.length-1].getAttribute("data-injectcss"),p=function(c,l){l.parentNode.insertBefore(c,l)};if(t&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}function v(){o||(o=!0,h())}function m(){try{i.documentElement.doScroll("left")}catch(c){return void setTimeout(m,50)}v()}l=function(){var c,l;(l=document.createElement("div")).innerHTML=z,z=null,(c=l.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",l=c,(c=document.body).firstChild?p(l,c.firstChild):c.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(l,0):(a=function(){document.removeEventListener("DOMContentLoaded",a,!1),l()},document.addEventListener("DOMContentLoaded",a,!1)):document.attachEvent&&(h=l,i=c.document,o=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,v())})}(window); \ No newline at end of file +!function(c){var a,l,h,i,o,z='',t=(t=document.getElementsByTagName("script"))[t.length-1].getAttribute("data-injectcss"),p=function(c,a){a.parentNode.insertBefore(c,a)};if(t&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}function v(){o||(o=!0,h())}function m(){try{i.documentElement.doScroll("left")}catch(c){return void setTimeout(m,50)}v()}a=function(){var c,a;(a=document.createElement("div")).innerHTML=z,z=null,(c=a.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",a=c,(c=document.body).firstChild?p(a,c.firstChild):c.appendChild(a))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(a,0):(l=function(){document.removeEventListener("DOMContentLoaded",l,!1),a()},document.addEventListener("DOMContentLoaded",l,!1)):document.attachEvent&&(h=a,i=c.document,o=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,v())})}(window); \ No newline at end of file diff --git a/public/css/iconfont.json b/public/css/iconfont.json index 3d3db1638..5acfb6e98 100644 --- a/public/css/iconfont.json +++ b/public/css/iconfont.json @@ -5,6 +5,13 @@ "css_prefix_text": "icon-", "description": "", "glyphs": [ + { + "icon_id": "24656750", + "name": "文件", + "font_class": "wenjian7", + "unicode": "e8e0", + "unicode_decimal": 59616 + }, { "icon_id": "630094", "name": "向右箭头", diff --git a/public/css/iconfont.ttf b/public/css/iconfont.ttf index 26a5c80d6..cffaad689 100644 Binary files a/public/css/iconfont.ttf and b/public/css/iconfont.ttf differ diff --git a/public/css/iconfont.woff b/public/css/iconfont.woff index 6c2fafd6a..af2a764e6 100644 Binary files a/public/css/iconfont.woff and b/public/css/iconfont.woff differ diff --git a/public/css/iconfont.woff2 b/public/css/iconfont.woff2 index 16677ef86..7d4cb19bb 100644 Binary files a/public/css/iconfont.woff2 and b/public/css/iconfont.woff2 differ diff --git a/src/App.js b/src/App.js index 21e88e990..58cf72c7f 100644 --- a/src/App.js +++ b/src/App.js @@ -101,6 +101,10 @@ const Home = Loadable({ loader: () => import('./home/Index'), loading: Loading, }) +// const CreateMerge = Loadable({ +// loader: () => import('./forge/Merge/NewMerge'), +// loading: Loading, +// }) // 此处仅维护前端可能的一级路由,不用进行项目或者组织判断的字段。 const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize"]; @@ -279,7 +283,7 @@ class App extends Component { } /> {/* 项目PR */} - () } diff --git a/src/common/TextUtil.js b/src/common/TextUtil.js index 94e736314..d1aa0e9cd 100644 --- a/src/common/TextUtil.js +++ b/src/common/TextUtil.js @@ -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 diff --git a/src/forge/Activity/Activity.js b/src/forge/Activity/Activity.js index 0272f0652..4a7a1d345 100644 --- a/src/forge/Activity/Activity.js +++ b/src/forge/Activity/Activity.js @@ -10,6 +10,10 @@ import ActivityItem from './ActivityItem'; import axios from 'axios'; const LIMIT = 15; const ARRAY = [ + { + id:"", + name:'全部' + }, { id:1, name:'1天' @@ -32,10 +36,15 @@ class Activity extends Component{ constructor(props){ super(props); this.state={ - time:'30', + time:undefined, type:undefined, state:undefined, page:1, + pr_count:undefined, + new_pr_count:undefined, + close_issues_count:undefined, + open_issues_count:undefined, + pr_all_count:undefined,issues_count:undefined, data:undefined, project_trends:undefined, @@ -63,8 +72,15 @@ class Activity extends Component{ this.setState({ data:result.data, project_trends:result.data.project_trends, - isSpin:false + isSpin:false, + pr_count:result.data.pr_count, + new_pr_count:result.data.new_pr_count, + close_issues_count:result.data.close_issues_count, + open_issues_count:result.data.open_issues_count, + pr_all_count:result.data.pr_all_count, + issues_count:result.data.issues_count, }) + window.scrollTo(0,0); } }).catch(error=>{ console.log(error); @@ -74,19 +90,19 @@ class Activity extends Component{ // 切换周期 changeTime=(e)=>{ this.setState({ - time:e.key, + time:e.key ==="item_0"?undefined:e.key, isSpin:true }) const { type,status,page } = this.state; - this.getInfo(e.key,type,status,page); + this.getInfo(e.key ==="item_0"?undefined:e.key,type,status,page); } //筛选 changeTrends=(type,status)=>{ this.setState({ - type,status + type,status,page:1 }) - const {time,page}=this.state; - this.getInfo(time,type,status,page); + const {time}=this.state; + this.getInfo(time,type,status,1); } // 分页 ChangePage=(page)=>{ @@ -108,12 +124,14 @@ class Activity extends Component{ ) render(){ - const { time , data , page , project_trends , isSpin } = this.state; + const { time , data , page , project_trends , isSpin , pr_count , new_pr_count , close_issues_count , open_issues_count , pr_all_count ,issues_count } = this.state; + let name = time ? ARRAY.filter(item=>item.id === parseInt(time)) :[{name:"全部"}]; - let name = time && ARRAY.filter(item=>item.id === parseInt(time)) ; - const second_per = (parseInt(data && data.close_issues_count)/parseInt(data && data.issues_count)*100)+'%'; - const third_per = (parseInt(data && data.close_issues_count)/parseInt(data && data.issues_count)*100)+'%'; - const fourth_per = (parseInt(data && data.open_issues_count)/parseInt(data && data.issues_count)*100)+'%'; + const first_per = pr_all_count > 0 ? `${parseFloat(pr_count/pr_all_count).toFixed(2)*100}%` :"50%"; + const second_per =pr_all_count > 0 ? `${parseFloat(new_pr_count/pr_all_count).toFixed(2)*100}%` :"50%"; + const third_per =issues_count > 0 ?`${parseFloat(close_issues_count/issues_count).toFixed(2)*100}%` :"50%"; + const fourth_per =issues_count > 0 ?`${parseFloat(open_issues_count/issues_count).toFixed(2)*100}%` :"50%"; + return(
@@ -122,7 +140,7 @@ class Activity extends Component{
-

+

{data && data.pr_all_count}合并请求 @@ -132,25 +150,25 @@ class Activity extends Component{

- {data && data.issues_count}任务 + {data && data.issues_count}易修
diff --git a/src/forge/Activity/ActivityItem.js b/src/forge/Activity/ActivityItem.js index 2b1ad3c8c..48a72e797 100644 --- a/src/forge/Activity/ActivityItem.js +++ b/src/forge/Activity/ActivityItem.js @@ -27,7 +27,7 @@ class ActivityItem extends Component { : // 如果是合并请求

- {item.name} + {item.name} {item.trend_type}

} diff --git a/src/forge/Branch/Select.jsx b/src/forge/Branch/Select.jsx index 073658d93..ff3dd829e 100644 --- a/src/forge/Branch/Select.jsx +++ b/src/forge/Branch/Select.jsx @@ -1,32 +1,61 @@ -import React , { useState , useEffect } from 'react'; -import { Popover , Dropdown , Input , Spin } from 'antd'; +import React , { useState , useEffect , useRef } from 'react'; +import { Dropdown} from 'antd'; import './branch.scss'; -import { getBranch , getTag } from '../GetData/getData'; import SelectOverlay from './SelectOverlay'; - +import { findDOMNode } from 'react-dom'; export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true })=>{ const [ showValue , setShowValue ] = useState(branch); + const [ visible , setVisible ] = useState(false); + + const refFa = useRef(null); + const refBox = useRef(null); + + useEffect(() => { + document.addEventListener('click', clickMe , false); + }, []) + + const clickMe = ({ target }) => { + // 查找父组件 + const faComponent = findDOMNode(refFa.current); + const boxComponent = findDOMNode(refBox.current); + + if (faComponent && boxComponent) { + const isChild = faComponent.contains(target); + const isBox = boxComponent.contains(target); + if(!isChild && !isBox){ + setVisible(false); + } + } + } useEffect(()=>{ setShowValue(branch); },[branch]) + function ChangeB(params) { + setVisible(false); + changeBranch(params); + } + const menu = ( - + + ); return( - -
+ +
setVisible(visible ? false : true)}> {/* {nav === 0 ?"分支":"标签"} */} - + {showValue} diff --git a/src/forge/Branch/SelectOverlay.jsx b/src/forge/Branch/SelectOverlay.jsx index d536d1c99..0be567324 100644 --- a/src/forge/Branch/SelectOverlay.jsx +++ b/src/forge/Branch/SelectOverlay.jsx @@ -2,7 +2,7 @@ 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 }) { +function SelectOverlay({ changeBranch , tagflag , projectsId , owner , visible }) { const [ inputValue , setInputValue] = useState(undefined); const [ nav , setNav ] = useState(0); const [ isSpin , setIsSpin ] = useState(true); @@ -12,12 +12,12 @@ function SelectOverlay({ changeBranch , tagflag , branchList , projectsId , owne const [ keys ,setKeys] = useState("branch"); useEffect(()=>{ - if(branchList){ - setData(branchList); - setDatas(branchList); - setIsSpin(false); + if(visible){ + setKeys("branch"); + getBranchs(projectsId,owner); + setIsSpin(true); } - },[branchList]) + },[visible]) async function getBranchs(id,owner){ let result = await getBranch(id,owner); @@ -45,8 +45,10 @@ function SelectOverlay({ changeBranch , tagflag , branchList , projectsId , owne setIsSpin(true); if(e.key === "branch"){ getBranchs(projectsId,owner); + setNav(0); }else{ getTags(projectsId,owner); + setNav(1); } } @@ -55,7 +57,7 @@ function SelectOverlay({ changeBranch , tagflag , branchList , projectsId , owne
} - placeholder="请输入分支或标签名称搜索" + placeholder={`请输入分支${tagflag ? "或标签" :""}名称搜索`} autocomplete="off" className="OptionsInput" value={inputValue} onChange={changeInputValue} @@ -68,12 +70,16 @@ function SelectOverlay({ changeBranch , tagflag , branchList , projectsId , owne
    { - datas && datas.length>0 ? + datas && datas.length>0 && datas.map((item,key)=>{ return(
  • chooseitem(item.name)}>{item.name}
  • ) - }): + }) + + } + { + datas && datas.length === 0 &&

    暂无{inputValue}{nav === 0 ?"分支":"标签"}~

    }
diff --git a/src/forge/Branch/branch.scss b/src/forge/Branch/branch.scss index b0f8ca2c9..030b05cd1 100644 --- a/src/forge/Branch/branch.scss +++ b/src/forge/Branch/branch.scss @@ -23,6 +23,7 @@ max-height: 300px; } .OptionsUl{ + min-height: 50px; max-height: 220px; overflow-y: auto; } @@ -87,6 +88,13 @@ line-height: 30px; padding:0px 5px; margin-left: 20px!important; + &.ant-menu-item-selected{ + border-color:#466aff!important; + color:#466aff!important; + } + &.ant-menu-item-active{ + border-color:transparent ; + } } } } @@ -109,7 +117,7 @@ color: #333; } &.ant-menu-item-selected{ - border-color:#1890ff!important; + border-color:#466aff!important; } &.ant-menu-item-active{ border-color:transparent ; diff --git a/src/forge/Component/NoticeModal/Index.scss b/src/forge/Component/NoticeModal/Index.scss new file mode 100644 index 000000000..18e4dcda0 --- /dev/null +++ b/src/forge/Component/NoticeModal/Index.scss @@ -0,0 +1,90 @@ +.systemBox{ + .ant-modal-body{ + padding:1px 0px 0px 0px; + .sysBox{ + background-image: url('./bg.png'); + background-repeat: no-repeat; + background-size: 100% 334px; + margin-top: -55px; + } + .sysnoticeBox{ + width: 100%; + padding:80px 0px 34px; + display: flex; + flex-direction: column; + width: 780px; + margin: 0px auto; + p.ntitle{ + height: 33px; + font-size: 24px; + font-weight: 500; + color: #31FFF7; + line-height: 33px; + text-align: center; + } + p.nSubtitle{ + height: 25px; + line-height: 25px; + font-size: 18px; + font-weight: 500; + color: #FFFFFF; + margin-top: 60px; + padding-left: 20px; + } + .markdown-body{ + box-shadow: 0px 0px 17px rgba(0,0,0,0.2); + border-radius: 4px; + margin-top: 17px!important; + } + .nContent{ + padding:20px 34px; + background-color: #fff; + line-height: 30px; + font-size: 15px; + font-weight: 400; + color: #333; + .realmName{ + margin-top: 20px; + display: flex; + ul{ + width: 50%; + padding-left: 0px!important; + li{ + font-size: 15px; + font-weight: 500; + line-height: 32px; + text-align: left; + color: #000; + list-style-type: none!important; + &:first-child{ + color: #E65714; + } + } + } + } + .nSubdesc{ + font-size: 15px; + font-weight: 400; + color: #000000; + line-height: 31px; + margin-top: 20px; + } + .nInfo{ + font-size: 14px; + font-weight: 400; + color: #333333; + text-align: right; + margin-top: 25px; + p{ + height: 20px; + line-height: 20px; + } + } + } + .nBtn{ + text-align: center; + margin-top: 33px; + } + } + } +} \ No newline at end of file diff --git a/src/forge/Component/NoticeModal/SystemNotice.jsx b/src/forge/Component/NoticeModal/SystemNotice.jsx new file mode 100644 index 000000000..1560c1ffc --- /dev/null +++ b/src/forge/Component/NoticeModal/SystemNotice.jsx @@ -0,0 +1,76 @@ +import React , { useEffect , useState } from 'react'; +import { Modal , Button } from 'antd'; +import './Index.scss'; +import '../../css/index.scss'; +import RenderHtml from '../../../components/render-html'; +import cookie from 'react-cookies'; + +function SystemNotice({system_notification,history}){ + const [ visible , setVisible ] = useState(false); + + useEffect(()=>{ + if(system_notification && !cookie.load('notice_stage')){ + setVisible(true); + } + },[system_notification,history.location]) + + function sureContinue() { + cookie.remove('notice_stage'); + + let inFifteenMinutes = new Date(new Date().getTime() + 24 * 3600 * 1000);//一天 + // let inFifteenMinutes = new Date(new Date().getTime() + 60 * 1000);//一分钟 + cookie.save('notice_stage', true,{ expires: inFifteenMinutes,path:"/" }); + + setVisible(false); + } + + return ( + +
+
+

{system_notification && system_notification.subject}

+

{system_notification && system_notification.sub_subject}

+ {/*
+
+ 为了给用户提供更加稳定、优质的服务,我们即将对平台门户首页、平台名称、平台域名进行一次全面升级与变更。原平台名称:Trustie(中文名:确实)将于2021年10月xx日统一更改为Gitlink(中文名:确实开源)。届时平台域名将统一进行更换,更换规则如下 +
+
+
    +
  • 原域名:
  • +
  • 官网顶级域名https://www.trustie.net
  • +
  • 版本库子域名https://forgeplus.trustie.net
  • +
  • 论坛子域名https://forum.trustie.net/forums
  • +
+
    +
  • 更换后域名:
  • +
  • 官网顶级域名https://www.gitlink.org.cn
  • +
  • 版本库子域名https://www.git.gitlink.org.cn
  • +
  • 论坛子域名https://forum.gitlink.org.cn
  • +
+
+
+ 自2021年10月xx日起,旧域名将停止访问。因平台名称与域名变更给您带来的不便,我们深表歉意!非常感谢您一直以来对本平台的信任与支持,我们将一如既往地为您提供优质的服务。 特此通知! +
+
+

Gitlink运营团队

+

2021年10月xx日

+
+
*/} + +
+ +
+
+
+
+ ) +} +export default SystemNotice; \ No newline at end of file diff --git a/src/forge/Component/NoticeModal/bg.png b/src/forge/Component/NoticeModal/bg.png new file mode 100644 index 000000000..625b3c311 Binary files /dev/null and b/src/forge/Component/NoticeModal/bg.png differ diff --git a/src/forge/Component/Releases.jsx b/src/forge/Component/Releases.jsx index 3983f600f..260e6bd2d 100644 --- a/src/forge/Component/Releases.jsx +++ b/src/forge/Component/Releases.jsx @@ -2,8 +2,7 @@ import React from 'react'; import { AlignTop } from '../Component/layout'; import { Link } from 'react-router-dom'; -function Releases({owner,projectsId,releaseVersions , baseOperate , projectType}){ - +function Releases({ owner, projectsId, releaseVersions, distribution }) { return(
@@ -16,8 +15,9 @@ function Releases({owner,projectsId,releaseVersions , baseOperate , projectType} return( key === 0 &&
-

- {item.name} +

+ {/* 如果是点击最新则发行版列表页只展示最新的一个 */} + {item.name} 最新

{item.created_at}

@@ -27,7 +27,8 @@ function Releases({owner,projectsId,releaseVersions , baseOperate , projectType} }) :
- 您暂未发布任何版本{baseOperate && projectType !==2 && 创建新版本} + 您暂未发布任何版本 + {distribution && 创建新版本}
} diff --git a/src/forge/Component/User.jsx b/src/forge/Component/User.jsx index bc652dcfb..0d970173f 100644 --- a/src/forge/Component/User.jsx +++ b/src/forge/Component/User.jsx @@ -5,6 +5,7 @@ import { Link } from 'react-router-dom'; export default ({ url , name , column , id , login })=>{ const Img = styled.span` display:flex; + font-weight: bold; ${column && "flex-direction: column;text-align:center;"} align-items: center; & img{ diff --git a/src/forge/DevOps/Dispose/PipelineName.jsx b/src/forge/DevOps/Dispose/PipelineName.jsx index 4acaa2068..63ee54378 100644 --- a/src/forge/DevOps/Dispose/PipelineName.jsx +++ b/src/forge/DevOps/Dispose/PipelineName.jsx @@ -51,7 +51,7 @@ function PipelineName({visible,onCancel,onOk,value ,branchList}){ }) } - {setEventValue(e)}}> { EVENT.map((item,key)=>{ return( diff --git a/src/forge/DevOps/ssh/XmlPanel.jsx b/src/forge/DevOps/ssh/XmlPanel.jsx index ae642caa3..295d96ce0 100644 --- a/src/forge/DevOps/ssh/XmlPanel.jsx +++ b/src/forge/DevOps/ssh/XmlPanel.jsx @@ -24,7 +24,6 @@ function onLayout(term, el) { entry.target.offsetHeight, term, ); - console.log('cols, rows', cols, rows); term.resize(cols, rows); mediator.publish('ssh-xterm-resize', { columns: cols, @@ -139,12 +138,10 @@ export default ({ sshConfigData, sid }) => { }, 1000); } isFirstConnected.current = true; - console.log('event:', event); const data = Base64.decode(event.data.toString()); let w = term._core._renderService.dimensions.actualCellWidth || 9.5; - console.log('data:', data, w, term); term.write(data); }; diff --git a/src/forge/Head/Footer.jsx b/src/forge/Head/Footer.jsx index 78d6394b6..3998a3c3a 100644 --- a/src/forge/Head/Footer.jsx +++ b/src/forge/Head/Footer.jsx @@ -19,10 +19,10 @@ function Footer(){ return(
-
+ {value && showhtml(value)} + {/*
- {value && showhtml(value)} - {/*
+
    Gitlink(确实开源) @@ -57,8 +57,8 @@ function Footer(){

©Copyright 2007~2021 国防科技大学Gitlink团队 & IntelliDE
湘ICP备 17009477号

-
*/} -
+
+
*/}
) } diff --git a/src/forge/Head/Header.js b/src/forge/Head/Header.js index 41d7fcfd3..ac139351e 100644 --- a/src/forge/Head/Header.js +++ b/src/forge/Head/Header.js @@ -120,7 +120,6 @@ class NewHeader extends Component { }) }; HideAddcoursestypess = (i) => { - console.log("调用了"); this.setState({ Addcoursestypes: false, mydisplay: true, @@ -269,7 +268,7 @@ class NewHeader extends Component { ) }) } -
  • 设置
  • + {/*
  • 设置
  • */} this.educoderloginysl()}>退出 ) @@ -368,7 +367,6 @@ class NewHeader extends Component { } let search_url = settings && settings.common && settings.common.search; - let notice_url = settings && settings.common && settings.common.notice; return (
    @@ -439,7 +437,7 @@ class NewHeader extends Component { :"" } - {current_user && current_user.login ? + { (settings && settings.common && settings.common.notice) && (current_user && current_user.login)? - + {current_user && - + } : "" diff --git a/src/forge/Main/CoderDepot.jsx b/src/forge/Main/CoderDepot.jsx index be568ca9f..f50c134a3 100644 --- a/src/forge/Main/CoderDepot.jsx +++ b/src/forge/Main/CoderDepot.jsx @@ -22,6 +22,7 @@ import UpdateDescModal from './sub/UpdateDescModal'; import Nodata from '../Nodata'; import Invite from './sub/Invite'; import CheckProfile from '../Component/ProfileModal/Profile'; +import RenderHtml from '../../components/render-html'; /** * projectDetail.type:0是托管项目,1是镜像项目,2是同步镜像项目(为2时不支持在线创建、在线上传、在线修改、在线删除、创建合并请求等功能) */ @@ -67,6 +68,7 @@ function CoderDepot(props){ const [ editReadme , setEditReadme ] = useState(false); const [ pullsFlag , setPullsFlag ] = useState(true); const [ issuesFlag , setIssuesFlag ] = useState(true); + const [ releaseVersions , setReleaseVersions] = useState(undefined); const owner = props.match.params.owner; const projectsId = props.match.params.projectsId; @@ -74,7 +76,8 @@ function CoderDepot(props){ branchName = returnbar(branchName); const details = props.projectDetail; let pathname = props.history.location.pathname; - + //distribution:判断此用户是否可以创建发行版 + const distribution = details && details.type != 2 && (details.permission === "Admin" || details.permission === "Owner" || details.permission === "Manager"); const { bannerList } = props; useEffect(()=>{ @@ -119,14 +122,47 @@ function CoderDepot(props){ setTreeValue(url); getFileInfo(url,branchName); setType("file"); + // getReadmeInfo(url,branchName); + // setReadme(undefined); }else{ setTreeValue(undefined); getDirInfo(branchName || defaultBranch); setType("dir"); + // getReadmeInfo('', branchName || defaultBranch); } } },[projectsId,owner,pathname,defaultBranch]) + useEffect(()=>{ + axios.get(`/${owner}/${projectsId}/releases.json`).then((result)=>{ + if(result && result.data){ + const release = { + "list":result.data.releases, + "total_count":result.data.releases.length + } + setReleaseVersions(release); + } + }) + },[]) + + // 获取readme信息 + function getReadmeInfo(path, ref) { + axios.get(`/${owner}/${projectsId}/readme.json`, { + params:{ + owner: owner, + repo: projectsId, + filepath:path, + ref:ref || branchName + } + }).then((result) => { + if (result) { + setReadme(result.data); + } else { + setReadme(undefined); + } + }) + } + // 获取主目录列表 function getDirInfo(branch){ setIsSpin(true); @@ -146,9 +182,10 @@ function CoderDepot(props){ setLastCommitAuthor(c && c.committer); setMainFlag(true); setReadOnly(true); - setReadme(result.data.readme); + // setReadme(result.data.readme); setEditReadme(false); setHide(true); + getReadmeInfo('', branchName || defaultBranch); } setTimeout(function(){setIsSpin(false);},500); }).catch(error=>{setIsSpin(false);}) @@ -160,7 +197,7 @@ function CoderDepot(props){ let ele = document.getElementById("ptxt"); if(ele){ let h = ele.offsetHeight; - if( h > 18 ) setHideBtn(true); + if( h > 35 ) setHideBtn(true); } } },[projectDetail,lastCommit]) @@ -181,15 +218,18 @@ function CoderDepot(props){ setDirInfo(undefined); setFileInfo(en); setType(en.type); + setReadme(undefined); }else{ setFileInfo(undefined); setDirInfo(en); setType("dir"); + getReadmeInfo(path, branchName || defaultBranch); } let c = result.data.last_commit setLastCommit(c && c.commit); setLastCommitAuthor(c && c.committer); setMainFlag(false); + setReadOnly(true); setReadOnly(!editReadme); setHide(true); } @@ -301,7 +341,8 @@ function CoderDepot(props){ const mdFlag = n && n.substring(n.length-3,n.length) === ".md"; const { current_user } = props; - const baseOperate = projectDetail && projectDetail.permission && projectDetail.permission !=="Reporter"; + const baseOper = current_user && current_user.login && issuesFlag; + const baseOperate = projectDetail && projectDetail.permission && projectDetail.permission !=="Reporter" && projectDetail.type !== 2 && pullsFlag; const fileOperate = type === "dir" && projectDetail && projectDetail.type !== 2 && ((projectDetail.permission && projectDetail.permission !=="Reporter") || (current_user && current_user.admin)); return( @@ -348,34 +389,47 @@ function CoderDepot(props){ branchList={projectDetail && projectDetail.branches && projectDetail.branches.list} > : - 分支:{branchName || defaultBranch} + 分支:{branchName || defaultBranch} }
    - - - - 分支 - {projectDetail && projectDetail.branches && projectDetail.branches.total_count} - - - - - - 标签 - {projectDetail && projectDetail.tags && projectDetail.tags.total_count} - - + { + treeValuePath && treeValuePath.length > 0 ? + + : + + + + + 分支 + {projectDetail && projectDetail.branches_count} + + + + + + 标签 + {projectDetail && projectDetail.tags_count} + + + + } { - baseOperate && ((projectDetail.type !== 2 && pullsFlag) || issuesFlag )&& + (baseOperate || baseOper) &&
    { - projectDetail.type !== 2 && pullsFlag && - urlLink(`/${owner}/${projectsId}/pulls/new`)} >+ 合并请求 + baseOperate && + urlLink(`/${owner}/${projectsId}/compare/master...${branchName || defaultBranch}`)} >+ 合并请求 } { - issuesFlag && + baseOper && urlLink(`/${owner}/${projectsId}/issues/new`)} >+ 易修 }
    @@ -403,8 +457,8 @@ function CoderDepot(props){ lastCommit &&
    -
    props.history.push(`/${owner}/${projectsId}/commits/${truncateCommitId(lastCommit.sha)}`)} className={hideBtn && hide ? "ellipsistxt hidetxt" :"ellipsistxt"}> -
    {lastCommit.message}
    +
    +
    { hideBtn && changeHide(hide)}> } @@ -418,16 +472,6 @@ function CoderDepot(props){
    }
      - { - treeValuePath && treeValuePath.length > 0 && - - } { dirInfo && dirInfo.length > 0 && dirInfo.map((item,key)=>{ @@ -461,11 +505,11 @@ function CoderDepot(props){ (dirInfo && dirInfo.length === 0) && !fileInfo ? :"" } {/* readme文件显示(显示文件详情时不显示readme文件) */} - { dirInfo && (readme && readme.content) ? :"" } + { (readme && readme.content) ? :"" }
    { - !fileInfo && + (!(treeValuePath && treeValuePath.length > 0) && !fileInfo) &&
    @@ -516,16 +560,15 @@ function CoderDepot(props){ } {/* 发布 */} { - projectDetail && projectDetail.release_versions && + releaseVersions && } @@ -535,7 +578,7 @@ function CoderDepot(props){ } {/* 语言 */} - { projectDetail && projectDetail.languages && + { projectDetail && projectDetail.languages && diff --git a/src/forge/Main/CoderDepotPath.jsx b/src/forge/Main/CoderDepotPath.jsx index ad4bb1096..89d6a5ca3 100644 --- a/src/forge/Main/CoderDepotPath.jsx +++ b/src/forge/Main/CoderDepotPath.jsx @@ -1,3 +1,4 @@ +import { result } from 'lodash'; import React from 'react'; diff --git a/src/forge/Main/CoderRootBranch.js b/src/forge/Main/CoderRootBranch.js deleted file mode 100644 index 4982414a2..000000000 --- a/src/forge/Main/CoderRootBranch.js +++ /dev/null @@ -1,92 +0,0 @@ -import React , { useState, useEffect } from 'react'; -import { Link } from "react-router-dom"; -import { Dropdown , Menu , Icon , Tooltip , Spin } from 'antd'; -import { truncateCommitId } from '../common/util'; -import { getBranch } from '../GetData/getData'; -import Nodata from '../Nodata'; -import './list.scss'; - -function turnbar(str){ - if(str && str.length>0 && str.indexOf("/")>-1){ - return str.replaceAll('/','%2F'); - } - return str; -} -export default ((props)=>{ - const [ data , setData ] =useState(undefined); - const [ isSpin , setIsSpin ] =useState(true); - - const { projectsId , owner } = props.match.params; - const { isManager , isDeveloper , projectDetail } = props; - useEffect(()=>{ - getBranchs(projectsId, owner); - },[projectsId]) - - async function getBranchs(id,owner){ - let result = await getBranch(id,owner); - setData(result); - setIsSpin(false); - } - - const list =()=>{ - if(data && data.length>0){ - return( - -
      - { - data.map((item,key)=>{ - return( -
    • -
      - {item.name} -

      - {item.last_commit && truncateCommitId(item.last_commit.sha)} - {item.last_commit && item.last_commit.message} - 最后更新于{item.last_commit && item.last_commit.time_from_now} -

      -
      - - { - (isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) && - 创建合并请求 - } - - - - - - -
    • - ) - }) - } -
    -
    - ) - }else if(data && data.length === 0){ - return ( ) - } - } - const menu =(zip_url,tar_url)=> ( - - ZIP - TAR.GZ - - ) - - return( - -
    - -
    -

    分支列表

    -
    {list()}
    -
    -
    -
    -
    - ) -}) - - - diff --git a/src/forge/Main/CoderRootCommit.js b/src/forge/Main/CoderRootCommit.js index a715fe74e..b542c3905 100644 --- a/src/forge/Main/CoderRootCommit.js +++ b/src/forge/Main/CoderRootCommit.js @@ -1,13 +1,19 @@ import React , { Component } from 'react'; -import { Spin , Pagination } from 'antd'; +import { Spin , Pagination, Timeline } from 'antd'; import { getImageUrl } from 'educoder'; -import { truncateCommitId } from '../common/util'; +import { truncateCommitId ,timeFormat } from '../common/util'; import { AlignTop } from '../Component/layout'; import SelectBranch from '../Branch/Select'; import Nodata from '../Nodata'; +import User from '../Component/User'; +import RenderHtml from '../../components/render-html.jsx'; +import Tree from './img/tree.png'; import axios from 'axios'; import {Link} from "react-router-dom"; +import CopyTool from '../Component/CopyTool'; + +import './tree/Index.scss' function returnbar(str){ if(str && str.length>0 && str.indexOf("%2F")>-1){ @@ -15,14 +21,16 @@ function returnbar(str){ } return str; } + +//代码库--提交页面 class CoderRootCommit extends Component{ constructor(props){ - super(props) + super(props); this.state={ commitDatas:undefined, dataCount:undefined, - limit:20, - page:1, + limit:10, + page: 1, isSpining:false, branchList:undefined } @@ -50,20 +58,34 @@ class CoderRootCommit extends Component{ this.Init(); } } + + UrlParamHash(url){ + const params = {}; + let h; + let hash = url.slice(url.indexOf('?')+1).split('&'); + for(let i = 0; i{ const { branchName } = this.props.match.params; - const { page , limit } = this.state; + const { limit } = this.state; + const {search} = this.props.location; + const realPage = (search && this.UrlParamHash(search).page) ? parseInt(this.UrlParamHash(search).page) : 1; this.setState({ - isSpining:true + isSpining:true, + page:realPage }) - this.getCommitList( branchName , page , limit ); + this.getCommitList( branchName , realPage , limit ); } getCommitList=(branch , page , limit)=>{ this.setState({ isSpining:true }) - console.log(returnbar(branch)); const { projectsId , owner } = this.props.match.params; const url = `/${owner}/${projectsId}/commits.json`; axios.get(url,{ @@ -86,7 +108,8 @@ class CoderRootCommit extends Component{ image_url:item.author && item.author.image_url, sha:item.sha, time_from_now:item.time_from_now, - message:item.message + message:item.message, + timestamp:item.timestamp }) }) this.setState({ @@ -105,10 +128,9 @@ class CoderRootCommit extends Component{ } ChangePage=(page)=>{ - const { branchName } = this.props.match.params; - const { limit } = this.state; - this.getCommitList(branchName , page , limit); + this.props.history.push({pathname: this.props.history.location.pathname,search: `page=${page}`}) } + render(){ const { commitDatas , dataCount , limit , page , isSpining , branchList } = this.state; const { projectDetail, commit_class , defaultBranch } = this.props; @@ -129,46 +151,50 @@ class CoderRootCommit extends Component{ >
    -
    -
    -
    - {dataCount}次提交代码({branch}) -
    -
    -
    - { - commitDatas && commitDatas.length > 0 && commitDatas.map((item,k)=>{ - return( -
    - - {truncateCommitId(`${item.sha}`)} - {item.message} - -

    - { - item.id ? - - {item.image_url?:""} - - : - - {item.image_url?:""} - - - } - -

    + + { + commitDatas && commitDatas.length > 0 && commitDatas.map((item,k)=>{ + return( + 最新:}> +
    +
    + +
    +
    +

    + + {item.timestamp && } +

    +
    +
    +
    +
    + + sha + {truncateCommitId(`${item.sha}`)} + + + +
    + +
    +
    - ) - }) - } - {commitDatas && commitDatas.length === 0 && } -
    -
    + + ) + }) + } + {commitDatas && commitDatas.length === 0 && } + { dataCount > limit ?
    - +
    :"" } diff --git a/src/forge/Main/CoderRootFileDetail.js b/src/forge/Main/CoderRootFileDetail.js index d5a9670c6..bdcfc98a7 100644 --- a/src/forge/Main/CoderRootFileDetail.js +++ b/src/forge/Main/CoderRootFileDetail.js @@ -1,10 +1,12 @@ import React, { Component } from "react"; -import { Popconfirm , Select } from "antd"; +import { Popconfirm , Select , Dropdown , Spin , Anchor } from "antd"; import "./list.scss"; import axios from "axios"; import Meditor from "../Newfile/m_editor"; import RenderHtml from "../../components/render-html"; +import ReadmeCatelogue from "./sub/ReadmeCatelogue"; +const $ = window.$; function bytesToSize(bytes) { if (bytes === 0) return "0 B"; let k = 1024, @@ -19,11 +21,13 @@ class CoderRootFileDetail extends Component { value: undefined, language: undefined, languages: undefined, - description: props.detail.content + description: props.detail.content, + menuList:undefined }; } componentDidMount = () => { + window.scrollTo(0, 0); const { detail , mdFlag } = this.props; this.setState({ value: detail.content, @@ -169,6 +173,31 @@ class CoderRootFileDetail extends Component { }); }; + renderMenulist=()=>{ + const { description } = this.state; + if(description){ + const items = $.map($("#files-md").find("h1,h2,h3,h4,h5,h6"), function (el, _) { + const anchor = el.id; + const level = el.tagName.replace("H", ""); + const href = `#${anchor}`; + return { href:`${href}`,text:el.textContent , level:level } + }); + return items; + } + return []; + } + + menu=()=>{ + const menuList = this.renderMenulist(); + if(menuList && menuList.length > 0){ + return( + + ) + }else{ + return + } + } + render() { const { readOnly, @@ -186,79 +215,88 @@ class CoderRootFileDetail extends Component { const Option = Select.Option; return ( -
    -
    - + +
    + { + md && readOnly && + + + + 目录 + + + } + {bytesToSize(detail && detail.size)}

    - {flag && platform && ( -

    - {readOnly ? ( - - { - !detail.direct_download? - - this.DownLoadFile(detail.download_url)} className="ml20"> - - - { - type !==2 && - this.EditFile(false)} className="ml20"> - + {flag && platform && ( +
    + {readOnly ? ( + + { + !detail.direct_download? + + this.DownLoadFile(detail.download_url)} className="ml20"> + - } - :"" - } - - ) : ( - - - - - )} - { - type !==2 && - - - - - - } - -
    - )} -

    -
    + { + type !==2 && + this.EditFile(false)} className="ml20"> + + + } +
    :"" + } + + ) : ( + + + + + )} + { + type !==2 && + + + + + + } + +
    + )} +

    +
    {detail.image_type ? (
    @@ -272,7 +310,7 @@ class CoderRootFileDetail extends Component {
    ) : ( md && readOnly ? -
    +
    : diff --git a/src/forge/Main/CoderRootIndex.js b/src/forge/Main/CoderRootIndex.js index 0fb30c4e1..7ff25dae1 100644 --- a/src/forge/Main/CoderRootIndex.js +++ b/src/forge/Main/CoderRootIndex.js @@ -1,9 +1,9 @@ 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 +18,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, @@ -50,41 +50,41 @@ class CoderRootIndex extends Component{ } } - componentDidMount=()=>{ - this.Init(); - } - componentDidUpdate=(prevProps)=>{ - const { location } = this.props; - const prevlocation = prevProps && prevProps.location; - if (location !== prevlocation) { - this.Init(); - } - } + // componentDidMount=()=>{ + // this.Init(); + // } + // componentDidUpdate=(prevProps)=>{ + // const { location } = this.props; + // const prevlocation = prevProps && prevProps.location; + // if (location !== prevlocation) { + // this.Init(); + // } + // } - Init=()=>{ - const { branchName } = this.props.match.params; - const { defaultBranch } = this.props; - this.getTopCount(branchName || defaultBranch); - } + // Init=()=>{ + // const { branchName } = this.props.match.params; + // const { defaultBranch } = this.props; + // this.getTopCount(branchName || defaultBranch); + // } // 获取组件里要显示的数据 - getTopCount=(branch)=>{ - const { projectsId , owner } = this.props.match.params; - const url = `/${owner}/${projectsId}/top_counts.json`; - axios.get(url,{params:{ - ref:branch - }}).then(result=>{ - if(result){ - this.setState({ - coderCount:result.data - }) - } - }).catch(error=>{console.log(error);}) - } + // getTopCount=(branch)=>{ + // const { projectsId , owner } = this.props.match.params; + // const url = `/${owner}/${projectsId}/top_counts.json`; + // axios.get(url,{params:{ + // ref:branch + // }}).then(result=>{ + // if(result){ + // this.setState({ + // coderCount:result.data + // }) + // } + // }).catch(error=>{console.log(error);}) + // } render(){ return( -
    - +
    + {/* */} {/* 新建文件 */} () + (props) => () } > () + () => () } > () + () => () } > - () } @@ -126,7 +126,7 @@ class CoderRootIndex extends Component{ render={ () => () } - > + > */} () diff --git a/src/forge/Main/Detail.js b/src/forge/Main/Detail.js index 3d82db26f..06d2fc44b 100644 --- a/src/forge/Main/Detail.js +++ b/src/forge/Main/Detail.js @@ -70,7 +70,7 @@ const MergeIndexDetail = Loadable({ }) const CreateMerge = Loadable({ - loader: () => import('../Merge/NewMerge'), + loader: () => import('../Merge/CreateMerge'), loading: Loading, }) @@ -150,7 +150,9 @@ function checkPathname(projectsId, owner, pathname) { name = "about" } else if (url.indexOf("/issues") > -1 || url.indexOf("Milepost") > 0) { name = "issues"; - } else if (url.indexOf("/pulls") > -1) { + } else if (url.indexOf("/pulls") > -1 || url.indexOf("/compare") > -1) { + // /pulls,合并请求除新建合并请求外, + // /compare,新建合并请求 name = "pulls" } else if (url.indexOf("/milestones") > -1) { name = "milestones" @@ -318,6 +320,9 @@ class Detail extends Component { const url = `/${owner}/${projectsId}/detail.json`; axios.get(url).then((result) => { if (result && result.data) { + if (result.data.status === 404) { + this.props.history.push('/nopage'); + } this.setState({ projectDetail: result.data, project_id: result.data.project_id, @@ -552,7 +557,7 @@ class Detail extends Component { - 复刻 + 复刻(Fork) { @@ -688,16 +693,12 @@ class Detail extends Component { } > {/* 复制详情 copyetail*/} - {/* () - } - > */} - () } > + {/* 任务详情 */} {/* 新建合并请求 */} - () + } + > */} + () } > - () - } - > - () } > - () + } + > + () + } + > + () } diff --git a/src/forge/Main/Diff.jsx b/src/forge/Main/Diff.jsx index 0daa63193..8dad59fba 100644 --- a/src/forge/Main/Diff.jsx +++ b/src/forge/Main/Diff.jsx @@ -1,35 +1,65 @@ import React, { useEffect, useState } from "react"; import styled from "styled-components"; import { Button ,Spin } from "antd"; -import { truncateCommitId } from '../common/util'; +import { timeFormat, truncateCommitId } from '../common/util'; import { getImageUrl } from 'educoder'; import Files from '../Merge/Files'; - +import Tree from "./img/tree.png"; import User from "../Component/User"; -import Keys from "../Component/Keys"; - +import RenderHtml from "../../components/render-html"; import axios from "axios"; +import { Link } from "react-router-dom"; const Infos = styled.div` - border: 1px solid #dddddd; + border: 1px solid #FAFCFF; margin-bottom:15px; & .commitinfos { background-color: #f1f8ff; - border-bottom: 1px solid #ddd; - padding: 20px; + border: 1px solid rgba(42, 97, 255, 0.23); + border-radius: 3px 3px 0px 0px; + padding: 10px 20px 10px 16px; + & .markdown-body table{ + background: #f1f8ff; + } + & .btnblue{ + margin-top: 12px; + } + & .task-hide{ + width: 65rem; + overflow:hidden; + white-space:normal; + word-break:break-all; + font-weight: bold; + color: #333333; + font-size: 16px; + } } & > .f-wrap-between { - padding: 10px 20px; + padding: 14px 20px 14px 16px; + border-radius: 3px 3px 0px 0px; + border: 1px solid #D0D0D0; + .df{ + align-items: center; + & .underline:hover{ + text-decoration: underline; + } + } } `; - -export default ({ match , history }) => { +function turnbar(str){ + if(str && str.length>0 && str.indexOf("/")>-1){ + return str.replaceAll('/','%2F'); + } + return str; +} +//提交详情页 +export default (props) => { + const {match , history } = props; const [data, setData] = useState({undefined}); const [commit, setCommit] = useState(undefined); const [parents, setParents] = useState(undefined); const [committer, setCommitter] = useState(undefined); const [isSpin, setIsSpin] = useState(true); - const { sha , projectsId, owner } = match.params; useEffect(() => { if (projectsId && owner && sha) { @@ -43,6 +73,7 @@ export default ({ match , history }) => { setParents(result.data.parents); setCommitter(result.data.committer || (result.data.commit && result.data.commit.committer)); setIsSpin(false); + } }) .catch(error => { @@ -56,29 +87,42 @@ export default ({ match , history }) => {
    - {commit && commit.message && -
    {commit.message}
    - } - +
    + {commit && commit.message && + + } + {data.branch} +
    +
      - {committer && committer.time_from_now &&
    • {committer.time_from_now}
    • } + {commit && commit.timestamp &&
    • 提交于{timeFormat(commit.timestamp)}
    • }
  • { parents && parents.length > 0 && parents.map((item,key)=>{ return( - +
    + + sha + {truncateCommitId(item.sha)} +
    ) }) } - +
    + + sha + {truncateCommitId(sha)} +
  • @@ -87,6 +131,7 @@ export default ({ match , history }) => { data={data} owner={owner} projectsId={projectsId} + parentsSha={parents && parents.length > 0 && parents[0].sha} />
    diff --git a/src/forge/Main/Index.scss b/src/forge/Main/Index.scss index 1158c38e6..5f3692929 100644 --- a/src/forge/Main/Index.scss +++ b/src/forge/Main/Index.scss @@ -189,13 +189,13 @@ flex-wrap: wrap; padding-bottom: 2px; a{ - margin: 0px 17px 0px 0px; + margin: 0px 17px 10px 0px; img{ border-radius: 50%; width: 40px; height: 40px; } - &:nth-child(6){ + &:nth-child(5n){ margin-right: 0px; } } @@ -224,7 +224,7 @@ height: 8px; width: 8px; left: 0px; - top:10px + top:8px; } &>span{ padding-left: 15px; @@ -252,8 +252,14 @@ border: 1px solid rgba(42, 97, 255, 0.23); background-color: #FAFCFF; .ellipsistxt{ - margin-top: 6px; - cursor: pointer; + &:hover .markdown-body{ + color: #466AFF; + & a{ + color: #466AFF; + } + } + margin-top: 2px; + // cursor: pointer; #ptxt{ margin-bottom: 0px; word-break: break-all; @@ -263,6 +269,27 @@ white-space:-pre-wrap; /* Opera 4-6 */ white-space:-o-pre-wrap; /* Opera 7 */ word-wrap:break-word; + .markdown-body{ + line-height: 10px; + font-size: 14px; + & p { + margin: 1px 0px 0px !important; + font-size: 14px !important; + } + & ol,ul{ + padding-bottom: 3px; + & li{ + min-height: 18px; + } + } + & table{ + line-height: 1; + background: #FAFCFF; + } + &:first-child { + margin-top: -1px !important; + } + } } margin-left: 13px; line-height:18px; @@ -270,7 +297,7 @@ width: 0; color: #666; &.hidetxt{ - height: 18px; + height: 24px; overflow: hidden; position: relative; padding-right:8px; @@ -402,6 +429,16 @@ cursor: pointer; background: #FAFBFC; border-radius: 4px; + .ant-dropdown-menu-item{ + border-radius: 8px; + text-align: left!important; + a{ + width: 350px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } border: 1px solid #D0D0D0; font-size: 15px; font-weight: normal; @@ -443,8 +480,32 @@ } } .ant-anchor-wrapper{ - padding-left: 2px; + padding-left: 2px!important; .ant-anchor-ink::before{ background-color: #fff; } +} +.coderSubPage{ + width: 1200px; + margin:0px auto; +} +.griditemAnchor{ + margin-left: 0px!important; + padding: 0px!important; + border-bottom: 1px solid #ddd; + .ant-anchor{ + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 20px; + } + .griditemCate{ + color: #333; + font-size: 16px; + display: flex; + align-items: center; + .catelogue{ + margin-left: 0px; + } + } } \ No newline at end of file diff --git a/src/forge/Main/img/tree-black.png b/src/forge/Main/img/tree-black.png new file mode 100644 index 000000000..02aa71c3a Binary files /dev/null and b/src/forge/Main/img/tree-black.png differ diff --git a/src/forge/Main/img/tree.png b/src/forge/Main/img/tree.png new file mode 100644 index 000000000..56247256c Binary files /dev/null and b/src/forge/Main/img/tree.png differ diff --git a/src/forge/Main/list.scss b/src/forge/Main/list.scss index 017a151c4..59589fb62 100644 --- a/src/forge/Main/list.scss +++ b/src/forge/Main/list.scss @@ -575,6 +575,9 @@ border:1px solid #ddd; margin-top: 18px; border-radius: 4px; + .ant-anchor-wrapper{ + overflow: unset!important; + } } .commonBox .commonBox-title{ padding:0px 20px; @@ -719,12 +722,84 @@ a.color-grey-ccc:hover{ padding:0px 30px; min-height: 400px; } -.commitList > div{ - border-bottom: 1px solid #EEEEEE; - padding:16px 0px; -} -.commitList > div:last-child{ - border-bottom: none; + +.main{ + margin: 30px auto; + .ant-timeline{ + margin-top: 28px; + .commitList-item{ + position: relative; + padding: 20px 20px; + background: #FAFCFF; + border: 1px solid rgba(42, 97, 255, 0.23); + border-radius: 4px; + margin-left: 16px; + & .treecopy{ + margin-top: 20px; + } + & .markdown-body table{ + background: #FAFCFF; + } + &:after,&:before{ + content: ""; + position: absolute; + left: -10px; + top: 10px; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + border-right: 10px solid rgba(42, 97, 255, 0.23); + } + &:after{ + left: -8px; + border-right: 10px solid #FAFCFF; + &:hover{ + border-right: 10px solid #EEF6FF; + } + } + &:hover{ + background: #EEF6FF; + border: 1px solid rgba(42, 97, 255, 0.58); + &:after{ + border-right: 10px solid #EEF6FF; + } + &:before{ + border-right: 10px solid rgba(42, 97, 255, 0.58); + } + & .markdown-body table{ + background: #EEF6FF; + } + } + .treecopy-cont{ + padding: 4px 15px; + } + .btn-83{ + margin-left: 20px; + } + } + .ant-timeline-item{ + padding: 8px 0 20px; + } + .ant-timeline-item-tail{ + height: calc(100% - 20px); + border-left: 2px solid #EEEEEE; + top: 12px; + &:after{ + content: ' '; + height: 0; + position: absolute; + width: 0; + border: 7px solid transparent; + border-top-color: #EEEEEE; + top: 100%; + left: 50%; + margin-left: -8px; + } + } + .ant-timeline-item-head-custom{ + top:20px; + padding: 0 1px; + } + } } diff --git a/src/forge/Main/sub/DetailBanner.jsx b/src/forge/Main/sub/DetailBanner.jsx index 83268b9e9..22a5ce419 100644 --- a/src/forge/Main/sub/DetailBanner.jsx +++ b/src/forge/Main/sub/DetailBanner.jsx @@ -50,7 +50,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa - 易修 + 易修(Issue) {projectDetail && projectDetail.issues_count ? {numFormat(projectDetail.issues_count)} : ""} @@ -86,7 +86,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa :"" } - { + {/* { item.menu_name === "resources" &&
  • @@ -95,7 +95,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa {projectDetail && projectDetail.source_count ? {projectDetail.source_count} :""}
  • - } + } */} { item.menu_name === "versions" &&
  • diff --git a/src/forge/Main/sub/ReadmeCatelogue.jsx b/src/forge/Main/sub/ReadmeCatelogue.jsx index d1e018bb6..6dab7d792 100644 --- a/src/forge/Main/sub/ReadmeCatelogue.jsx +++ b/src/forge/Main/sub/ReadmeCatelogue.jsx @@ -1,7 +1,7 @@ -import React , { useState , useEffect } from 'react'; +import React , { useState } from 'react'; import { Anchor , Input } from 'antd'; import './sub.scss'; -import { Base64 } from 'js-base64'; +import { useEffect } from 'react'; const { Link } = Anchor; @@ -18,7 +18,7 @@ function ReadmeCatelogue({ menuList , hash }) { function changeValue(e) { setValue(e.target.value); if(e.target.value){ - let m = menuList.filter(i=>i.text.indexOf(e.target.value)>-1); + let m = menuList.filter(i=>i.text.toLowerCase().indexOf(e.target.value.toLowerCase())>-1); setMenu(m); }else{ setMenu(menuList); diff --git a/src/forge/Main/sub/SubMenu.jsx b/src/forge/Main/sub/SubMenu.jsx new file mode 100644 index 000000000..78f37b4de --- /dev/null +++ b/src/forge/Main/sub/SubMenu.jsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import'./sub.scss' + +function SubMenu({tab,owner,projectsId}) { + return( +
      + 标签 + 发行版 +
    + ) +} +export default SubMenu; \ No newline at end of file diff --git a/src/forge/Main/sub/sub.scss b/src/forge/Main/sub/sub.scss index 4e6a3d8ac..7716f0c50 100644 --- a/src/forge/Main/sub/sub.scss +++ b/src/forge/Main/sub/sub.scss @@ -64,4 +64,28 @@ background-color: #fff; } } +} +.subMenu{ + display: flex; + padding-top: 30px; + a{ + width: 83px; + font-weight: 500; + line-height: 30px; + height: 32px; + color: #333333!important; + text-align: center; + border: 1px solid #D0D0D0; + border-radius: 0px 4px 4px 0px; + background: rgba(250, 251, 252, 0); + &:first-child{ + border-right: none; + border-radius: 4px 0px 0px 4px; + } + &.active{ + background-color: #466AFF; + color: #fff!important; + border-color: #466AFF; + } + } } \ No newline at end of file diff --git a/src/forge/Main/tag/Index.jsx b/src/forge/Main/tag/Index.jsx new file mode 100644 index 000000000..ff7648513 --- /dev/null +++ b/src/forge/Main/tag/Index.jsx @@ -0,0 +1,138 @@ +import React,{ useEffect , useState } from 'react'; +import SubMenu from '../sub/SubMenu'; +import { Table , Tooltip , Spin } from 'antd'; +import axios from 'axios'; +import { Link } from 'react-router-dom'; +import { truncateCommitId } from '../../common/util'; +import { getImageUrl } from 'educoder'; +import Nonedata from '../../Nodata'; +import './Index.scss'; +import Tree from '../img/tree.png' +import moment from 'moment'; + +function Tags(props) { + + const [ source , setSource ] = useState(undefined); + const [ isSpin , setIsSpin ] = useState(true); + + 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); + setIsSpin(false); + } + }).catch(error => {}) + } + }, [owner, projectsId]); + + const columns=[ + { + title:"标签名", + dataIndex:"name", + key:1, + ellipsis:true, + width:"200px", + render:(txt,item)=>{ + return( +
    + {item.name} +
    + ) + } + }, + { + title:"创建时间", + dataIndex:"time_ago", + key:2, + ellipsis:true, + render:(txt,item)=>{ + return ( + + { + item.tagger && + + { + item.tagger.id ? + + + + : + + + + } + + } + 创建于{txt} + + ) + } + }, + { + title:"提交ID", + dataIndex:"id", + key:3, + ellipsis:true, + render:(txt,item)=>{ + return ( + + 提交ID + {truncateCommitId(item.id)} + + ) + } + }, + { + title:"描述信息", + dataIndex:"message", + key:4, + ellipsis:true, + render:(txt,item)=>{ + return item.message || "--" + } + }, + { + title:"下载", + dataIndex:"stage_type", + key:5, + ellipsis:true, + align:"center", + width:"204px", + render:(txt,item)=>{ + return ( + + + TAR + + + ZIP + + + ) + } + } + ] + return( +
    + + +
    + { + source && source.length > 0 && +
    + } + { + source && source.length === 0 && + } +
    +
    +
    + ) +} +export default Tags; \ No newline at end of file diff --git a/src/forge/Main/tag/Index.scss b/src/forge/Main/tag/Index.scss new file mode 100644 index 000000000..6adba91e3 --- /dev/null +++ b/src/forge/Main/tag/Index.scss @@ -0,0 +1,58 @@ +.tagTable{ + margin-top: 30px; + thead{ + tr th{ + background-color: #fff; + padding:5px 0px; + width: 172px; + .ant-table-column-title{ + font-size: 16px; + font-weight: 500; + color: #333333; + } + } + } + tbody{ + .btn-83{ + margin:0px 8px; + } + tr{ + &:hover td{ + background-color: #fff!important; + } + td{ + padding:0px; + height: 69px; + line-height: 69px; + color:#333333; + div{ + font-weight: 500; + } + } + &:last-child{ + td{ + border-bottom: none!important; + } + } + } + } +} +.tagSpin{ + min-height: 300px; +} +.tagBranch{ + padding-right: 15px; + text-overflow: ellipsis; + overflow: hidden; + .tagClass{ + color:#333333; + } +} +.tagModel{ + font-weight: 400; + .tagModelImg img{ + width: 25px; + height: 25px; + border-radius: 50%; + } +} \ No newline at end of file diff --git a/src/forge/Main/tree/Index.jsx b/src/forge/Main/tree/Index.jsx new file mode 100644 index 000000000..2fc574349 --- /dev/null +++ b/src/forge/Main/tree/Index.jsx @@ -0,0 +1,114 @@ +import React , { useEffect , useState } from 'react'; +import CopyTool from '../../Component/CopyTool'; +import { truncateCommitId } from '../../common/util'; +import { Link } from 'react-router-dom'; +import { getImageUrl } from 'educoder'; +import { Dropdown , Menu , Spin } from 'antd'; +import './Index.scss'; + +import Tree from '../img/tree.png'; +import Axios from 'axios'; + +function turnbar(str){ + if(str && str.length>0 && str.indexOf("/")>-1){ + return str.replaceAll('/','%2F'); + } + return str; +} +function Index(props) { + const [ list , setList ] = useState([]); + const [ isSpin , setIsSpin ] = useState(true); + + const { projectsId , owner } = props.match.params; + const { isManager , isDeveloper , projectDetail } = props; + + useEffect(()=>{ + getList(); + },[]) + + + const menu =(zip_url,tar_url)=> ( + + ZIP + TAR.GZ + + ) + + 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( + +
    + { + list && list.length>0 && list.map((item,key)=>{ + return( + +

    {item.branch_type === "default" ? "默认分支" : item.branch_type==="protected"?"保护分支":"其它分支"}

    + { + item.list && item.list.length>0 && +
      + { + item.list.map((i,k)=>{ + let last_commit = i.last_commit; + return( +
    • +
      + {i.name} +
      + { + last_commit && last_commit.committer && last_commit.committer.id? + + + {last_commit && last_commit.committer && last_commit.committer.name} + + : + + + {last_commit && last_commit.committer && last_commit.committer.name} + + } + 更新于{last_commit && last_commit.time_from_now} +
      +
      +
      +
      + + sha + {truncateCommitId(last_commit && last_commit.sha)} + + + +
      +
      +
      + { + (isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) && + + 合并请求 + } + + 下载 + +
      +
    • + ) + }) + } +
    + } +
    + ) + }) + } +
    +
    + ) +} +export default Index; \ No newline at end of file diff --git a/src/forge/Main/tree/Index.scss b/src/forge/Main/tree/Index.scss new file mode 100644 index 000000000..f65a1c68f --- /dev/null +++ b/src/forge/Main/tree/Index.scss @@ -0,0 +1,101 @@ +.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{ + width: 399px; + flex:1; + flex-direction: column; + &>a{ + display: block; + width: 399px; + + } + a:hover{ + span{ + color: #466AFF!important; + } + } + img{ + height: 20px; + width: 20px; + margin-right: 5px; + } + } + .treeabout{ + flex:1; + text-align: right; + } + } +} +.treecopy{ + flex:1; + display: flex; + justify-content: center; + &>div{ + height: 32px; + background: #FAFBFC; + border-radius: 4px; + border: 1px solid #D0D0D0; + position: relative; + z-index: 1; + display: flex; + align-items: center; + &>span{ + padding:0px 15px; + border-right: 1px solid rgba(153, 153, 153, 0.4); + height: 100%; + img{ + margin-right: 4px; + } + a{ + color: #466AFF; + &:hover{ + text-decoration: underline; + } + } + } + &>i{ + margin:0px 12px; + color: #333!important; + } + input{ + position: absolute; + z-index: 0; + opacity: 0; + top: 32px; + } + } +} +.new-conmmit{ + width: 30px; + height: 18px; + line-height: 18px; + display: block; + background: #FF6832; + color: white; + font-size: 12px; + border-radius: 4px; +} +.icon-a-yuanquan2x{ + color: #466AFF; +} \ No newline at end of file diff --git a/src/forge/Main/version/Empty.jsx b/src/forge/Main/version/Empty.jsx new file mode 100644 index 000000000..3200d3e8f --- /dev/null +++ b/src/forge/Main/version/Empty.jsx @@ -0,0 +1,22 @@ +import { Button } from 'antd'; +import React from 'react'; +import './version.scss'; + +function Empty({operation,addFunc}) { + return( +
    + + 这里暂未发布过任何版本 + 发行版功能基于仓库中的历史标记
    建议使用类似 V1.0 的版本标记作为发布点
    +
    + { + operation ? + + : + 该项目暂时没有发布版本 + } +
    +
    + ) +} +export default Empty; \ No newline at end of file diff --git a/src/forge/Main/version/Index.jsx b/src/forge/Main/version/Index.jsx new file mode 100644 index 000000000..37cc8c128 --- /dev/null +++ b/src/forge/Main/version/Index.jsx @@ -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( +
    + + + () + } + > + () + } + > + () + } + > + +
    + ) +} +export default Index; \ No newline at end of file diff --git a/src/forge/Main/version/New.jsx b/src/forge/Main/version/New.jsx new file mode 100644 index 000000000..8adde9b01 --- /dev/null +++ b/src/forge/Main/version/New.jsx @@ -0,0 +1,266 @@ +import React, { useState, useEffect, forwardRef } from "react"; +import styled from "styled-components"; +import { AutoComplete , Input, Checkbox, Button, Form } from "antd"; +import SelectBranch from '../../Branch/Select'; + +import Editor from "../../../modules/tpm/challengesnew/tpm-md-editor"; +import Upload from "../../Upload/Index"; +import Attachments from "../../Upload/attachment"; +import axios from "axios"; +import "./version.scss"; +import { trim } from "lodash"; + +const { Option } = AutoComplete; + +const Span = styled.span` + margin: 0px 15px; + color: #bbb; + line-height: 35px; + font-size:16px; + font-weight:400; + color:#666; +`; +export default Form.create()( + forwardRef( + ( + { form, projectDetail , match, showNotification, history }, + ref + ) => { + const { getFieldDecorator, validateFields, setFieldsValue } = form; + const [tagList, setTagList] = useState(undefined); + const [desc, setDesc] = useState(null); + const [branch, setBranch ] = useState(null); + const [fileList, setFileList] = useState(undefined); + const [attachment, setAttachment] = useState(undefined); + const [options , setOptions] = useState(undefined); + const stable = history && history.location && history.location.state.stable; + const { projectsId, versionId , owner } = match.params; + + useEffect(()=>{ + if(projectDetail && projectDetail.default_branch){ + setBranch(projectDetail.default_branch); + } + },[projectDetail]) + + + useEffect(() => { + if (versionId) { + const url = `/${owner}/${projectsId}/releases/${versionId}/edit.json`; + axios.get(url).then(result => { + if (result) { + setFieldsValue(result.data); + setDesc(result.data.body); + setAttachment(result.data.attachments); + } + }); + } + }, [versionId]); + + useEffect(() => { + if (projectsId) { + const url = `/${owner}/${projectsId}/tags.json`; + axios + .get(url,{params:{ + limit:1000 + }}) + .then(result => { + if (result) { + setTagList(result.data); + setOptions(renderTagList(result.data)); + } + }) + .catch(error => { + console.log(error); + }); + } + }, [projectsId]); + + function renderTagList(list) { + if (list) { + let array = list.map((item, key) => { + return ( + + ); + }); + 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 ( +
    +
    +
    + + {getFieldDecorator("tag_name", + { rules:[ + { required: true, message: "请输入获取或选择一个标签" }, + { validator: (rule,val,callback) =>{ + if(val.length>30 || val.indexOf(' ')>0 || val.match(/^\s+$/) || trim(val).length!=val.length){ + callback('无效的标签名称,请参考右侧建议命名标签并确认长度在1~30个字符之间'); + }else{ + callback(); + } + }}], + validateFirst: true + })( + + {options} + + )} + + @ + +

    选择一个已经存在的标签,或者在发布时新建一个标签

    +
    + + {getFieldDecorator("name", + { rules:[ + { required: true, message: "请输入发行版的标题" }, + { validator: (rule,val,callback) =>{ + if(val.length>50){ + callback('标题长度在1~50个字符之间'); + }else{ + callback(); + } + }}], + validateFirst: true + })( + + )} + + + +
    + + } + size={100} + showNotification={showNotification} + /> + {versionId && attachment && attachment.length > 0 ? ( + + ) : ( + "" + )} +
    + + {getFieldDecorator("prerelease", + { rules:[], + validateFirst: true + })( + 这是一个预览版本 + )} + +

    + + +

    + +
    +
    +

    标签命名建议

    +

    + 通常的做法是在版本名称前加上字母 v 前缀, v1.0 或者 v2.3.4。 +

    +

    + 如果标签不适合在生产环境下使用,请在版本名称后添加预发行版本。例如:v0.2-alpha + 或者 v5.9-beta.3。 +

    +
    +
    +

    语义化版本

    +

    + 如果你是第一次发布版本,我们强烈建议你阅读语义化版本。 +

    +
    +
    +

    附件大小说明

    +

    + 单个附件不能超过 100M(GVP 项目200M),每个仓库总附件不可超过 + 1G(推荐项目不可超过 5G;GVP 项目不可超过 + 20G)。附件总容量统计包括仓库附件和发行版附件。 +

    +
    +
    +
    + ); + } + ) +); diff --git a/src/forge/Main/version/version.js b/src/forge/Main/version/version.js new file mode 100644 index 000000000..2896899fc --- /dev/null +++ b/src/forge/Main/version/version.js @@ -0,0 +1,150 @@ +import React, { useEffect , useState } from "react"; +import { Link } from 'react-router-dom'; +import { Spin , Button } from 'antd'; +import { getImageUrl } from 'educoder'; +import {truncateCommitId} from '../../common/util'; +import Empty from './Empty'; +import './version.scss'; +import axios from 'axios'; +import Tree from '../img/tree-black.png'; +import RenderHtml from '../../../components/render-html'; +import User from "../../Component/User"; + +function version(props) { + const [ data , setData ] = useState(undefined); + const [ releases , setReleases ] = useState(undefined); + const [ isSpin , setIsSpin ] = useState(true); + const { projectsId ,owner } = props.match.params; + const { location } = props; + const type = props.projectDetail && props.projectDetail.type; + const turnFromNew = location && location.query && location.query.turnFromNew; + useEffect(()=>{ + getIssueList(); + },[]) + // 获取列表数据 + function getIssueList(){ + const url = `/${owner}/${projectsId}/releases.json`; + axios.get(url).then((result) => { + if (result) { + setData(result.data); + const { releases = [] } = result.data; + //默认第一个展开(body参数) + releases.length && (releases[0].bodyshow = true); + setReleases(result.data.releases); + setIsSpin(false); + } + }).catch((error) => { + console.log(error); + }) + } + // 显示版本描述 + function showBody(key,flag){ + var lists = releases.concat(); + lists[key].bodyshow = !flag ? true : false; + lists.splice(); + setReleases(lists); + } + //删除 + function deleteRelease(releaseId) { + if(releaseId){ + axios.delete(`/${owner}/${projectsId}/releases/${releaseId}.json`).then((result)=>{ + if(result){ + getIssueList(); + } + }) + } + } + function release(item,key){ + return ( +
    + + {item.draft} + + + {item.tag_name} + + + + {truncateCommitId(item.sha)} + + +
    +
    + {item.name} + + {data && data.user_admin_permission && type !== 2 && } + {data && data.user_admin_permission && type !== 2 && {deleteRelease(item.version_id)}}>} + +
    + + showBody(key,item.bodyshow)}> + + 发布于{item.created_at} + + { + item.bodyshow && +
    + +
    + } + +

    + {/* 发行版附件下载 */} + {item.attachments && item.attachments.map((item)=>{ + return(下载 {item.title}) + })} + {/* 发行版下载包 */} + 下载 {item.tag_name}.TAR.gz + 下载 {item.tag_name}.ZIP +

    +
    +
    + ) + } + function renderList(releases){ + if (releases && releases.length > 0) { + return ( + + { + data && data.user_admin_permission && type !== 2 && +
    + +
    + } +
    + {!turnFromNew ? releases.map((item, key) => release(item,key)) : release(releases[0],0)} +
    +
    + ) + } else if (releases && releases.length === 0) { + return ( + + ) + } else{ + return (
    ) + } + } + + function addFunc(){ + props.history.push({pathname:`/${owner}/${projectsId}/releases/new`,state:{stable:true}}); + } + + return ( +
    +
    + + {renderList(releases)} + +
    +
    + ) +} +export default version; \ No newline at end of file diff --git a/src/forge/Main/version/version.scss b/src/forge/Main/version/version.scss new file mode 100644 index 000000000..7cd5ddb46 --- /dev/null +++ b/src/forge/Main/version/version.scss @@ -0,0 +1,357 @@ +.topWrapper { + padding: 20px 0; + box-sizing: border-box; + display: flex; + justify-content: space-between; + border-bottom: 1px solid #EEEEEE; + align-items: center; +} +.topWrapper_btn_new { + background: #fff; + color: #5091FF!important; + padding:0px 12px; + text-align: center; + height: 32px; + line-height: 32px; + border-radius: 4px; + border:1px solid #5091FF; +} +.versionInfo{ + display: flex; + width: 100%; +} +.versionInfo_left{ + display: flex; + width: 182px; + flex-direction: column; + align-items: flex-end; + padding-right: 15px; + &>.color-grey-3{ + max-width: 10rem; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } +} +.versionInfo_right{ + flex: 1; + display: flex; + flex-direction: column; + align-items: flex-start; + border-left: 1px solid #eee; + position: relative; + padding: 0px 30px 60px 24px; + &::before{ + position: absolute; + left: -4px; + top:0px; + content: ''; + width: 8px; + height: 8px; + background-color: #466AFF; + border-radius: 50%; + } + .sendAuthorImg{ + width: 20px; + height: 20px; + border-radius: 50%; + margin-right: 5px; + } + .body-show{ + padding: 5px 10px 10px 10px; + } + & .version-user>a>span{ + display: inline-block; + & img{ + width: 20px; + height: 20px; + } + } +} +.versionTag{ + display: inline; + padding:0px 9px; + color: #fff; + position: relative; + margin-top: -8px; + height: 22px; + line-height: 20px; + border-radius: 4px; + &::before{ + position: absolute; + content: ""; + width: 0; + height: 0px; + border-left: 4px solid #cccccc; + border-top: 4px solid transparent; + border-bottom: 4px solid transparent; + border-right: 4px solid transparent; + z-index: 9; + top: 6px; + right: -9px; + } + &:after{ + width: 0px; + height: 0px; + top:6px; + right: -7px; + position: absolute; + border-left:4px solid #fff; + border-top:4px solid transparent; + border-bottom:4px solid transparent; + border-right:4px solid transparent; + content:''; + z-index:10; + } +} +.versionFile{ + margin-top: 5px; + padding-top: 20px; + border-top: 1px solid #eee; + // width: 100%; + a{ + display: block; + color: #333; + font-weight: 400; + height: 20px; + margin-bottom: 10px; + } +} +.versionTag.yellow{ + border: 1px solid #FBBC06; + color: #FBBC06; + &::before{ + border-left-color: #FBBC06; + } +} +.versionTag.green{ + border: 1px solid #2DB44D; + color: #2DB44D; + &::before{ + border-left-color: #2DB44D; + } +} +.versionTag.orange{ + border: 1px solid #FF6E23; + color: #FF6E23; + &::before{ + border-left-color: #FF6E23; + } +} +.addReleaseBtn{ + text-align: right; + margin-bottom: 30px; +} +.versionName{ + font-size: 16px; + color: #333; + margin-bottom: 15px; + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + height: 18px; + line-height: 18px; + margin-top: -5px; +} + + +.versionmilepostleft{ + padding: 15px; + margin-right: 50px; + width: 80%; + } +.topWrapper_btn_close { + background: #504b4b; + color: #FFFFFF!important; + padding:0px 12px; + text-align: center; + height: 32px; + line-height: 32px; + border-radius: 4px; + } + + .topWrapper_btn_delete { + background: #da1010; + color: #FFFFFF!important; + padding:0px 12px; + text-align: center; + height: 32px; + line-height: 32px; + border-radius: 4px; + } + + .versionrighe{ + flex: 2; + } + .versionleft{ + flex: 1; + text-align: right; + display: flex; + justify-content: right; + } + + /* .version_line{ + display: flex; + height: 30px; + margin: auto; + border-left:1px solid #eee; + } */ + .version_line_one{ + display: flex; + height: 45px; + margin: auto; + border-left:1px solid #eee; + } + + .version_line_tpw{ + display: flex; + height: 80px; + margin: auto; + border-left:1px solid #eee; + } + + .versiondiv{ + display: flex; + } + .verwinth{ + width: 80%; + } + + /*开启中 关闭中*/ +.opendversionetail{ + display: inline-block; + background: #21ba45; + color: #ffffff!important; + padding:0px 5px; + text-align: center; + height: 25px; + /*width: 110px;*/ + border-radius: 4px; + line-height: 25px; +} +.closedversionetail{ + display: inline-block; + background: #e60b0b; + color: #ffffff!important; + padding:0px 5px; + text-align: center; + height: 25px; + /*width: 110px;*/ + border-radius: 4px; + line-height: 25px; +} +.versionrectangle { + width: 8px; + height: 8px; + border-radius: 100%; + margin-top: 15px; + margin-left: -4px; + margin-bottom: 10px; + background: rgb(83, 81, 81); + } +.ver-middle{ + vertical-align: middle; +} +/* new */ +.versionForm{ + flex:1; + padding-right: 40px; + box-sizing: border-box; + .ant-select-auto-complete.ant-select .ant-input:hover,.ant-input:hover { + border-color: rgba(153, 153, 153, 0.8); + } +} +.versionTips{ + width:268px; + box-sizing: border-box; +} +.infosTip{ + border-bottom: 1px solid #EEEEEE; + color: #333; + padding-bottom: 26px; + margin-bottom: 26px; + font-weight: 400; + text-align: justify; + &:last-child{ + border-bottom: none; + } +} +.dragBox{ + background: rgba(153, 153, 153, 0.04); + border-radius: 4px; + border: 1px dashed #d9d9d9; + padding:20px; + .versionStyle{ + border: none!important; + padding-bottom:20px; + .dragIcon{ + font-size: 40px!important; + color: #666!important; + line-height: 40px; + height: 40px; + margin-bottom: 14px; + display: block; + } + } + .ant-upload-list-item:hover .ant-upload-list-item-info { + background-color: rgba(239, 244, 255, 1); + } + .ant-upload-list-item-info{ + padding:0px 20px 0px 8px; + &>span{ + display: flex; + align-items: center; + } + } +} + +.set-ant-row .ant-row{ + display: flex; + height: 20px; + align-items: center; +} +.itemInline{ + display: flex; + align-items: flex-start; + position: relative; + &>p{ + position: absolute; + bottom: -5px; + } +} +.itemInline .ant-row{ + margin-bottom: 0px; +} +.prerelease{ + padding-top: 20px; + .ant-form-item-control{ + height: 20px; + line-height: 20px; + } +} +.releaseIndex{ + margin: 30px auto; + width: 1200px; +} +.emptyPanel{ + width: 100%; + background: #FAFCFF; + border-radius: 4px; + border: 1px solid rgba(42, 97, 255, 0.23); + min-height: 418px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + .operation{ + width: 400px; + border-top: 1px solid #eee; + padding-top: 34px; + text-align: center; + margin-top: 30px; + } +} +.ant-form-item-control{ + line-height: initial; +} \ No newline at end of file diff --git a/src/forge/Merge/CreateMerge.js b/src/forge/Merge/CreateMerge.js new file mode 100644 index 000000000..d7a320099 --- /dev/null +++ b/src/forge/Merge/CreateMerge.js @@ -0,0 +1,448 @@ +import React, { Component } from 'react'; +import { Input, Select, Spin, Alert } from 'antd'; +import axios from 'axios'; +import MergeForm from './merge_form'; +import MergeFooter from './merge_footer'; + +import '../Order/order.css'; +import './merge.css'; + +/** + * 根据url获取目标仓库、目标分支、源仓库、源分支 + * 路由规则:owner/projectId/compare/merge...pullowner:pullBranch + * 可能存在的情况 + * 1、代码库首页跳转,仓库相同,目标分支为默认分支,owner/projectId/compare/pullBranch + * 2、代码库分支列表,仓库相同,目标分支为默认分支,owner/projectId/compare/pullBranch + * 3、合并请求列表页(新建、无数据时的提示),仓库相同,源、目标都为默认分支,owner/projectId/compare + * 4、新建页面,切换分支、切换目标仓库、刷新页面等,存在所有可能情况 + */ +function getBranchParams(pathname) { + const result = { + // 目标仓库所有者 + mergeOwner: undefined, + // 目标分支 + mergeBranch: 'master', + // 源仓库所有者 + pullOwner: undefined, + // 源分支 + pullBranch: 'master', + // 仓库名称 + projectId: undefined, + }; + // 去掉第一个字符/ + const _pathname = pathname.slice(1); + const [ownerProject, branchUrl] = _pathname.split('/compare'); + const [mergeOwner, projectId] = ownerProject.split('/'); + // 同仓库时 + result.mergeOwner = mergeOwner; + result.pullOwner = mergeOwner; + result.projectId = projectId; + if (branchUrl) { + // 如果存在具体的分支 + const _branchUrl = branchUrl.slice(1); + if (_branchUrl.indexOf('...') > -1) { + // 存在源分支与目标分支 + const [mergeBranch, pullObj] = _branchUrl.split('...'); + result.mergeBranch = mergeBranch; + if (pullObj.indexOf(':') > -1) { + // 存在源仓库 + const [pullOwner, pullBranch] = pullObj.split(':'); + result.pullOwner = pullOwner; + result.pullBranch = pullBranch; + } else { + result.pullBranch = pullObj; + } + } else { + result.pullBranch = _branchUrl; + } + } + return result; +} + +const Option = Select.Option; + +class CreateMerge extends Component { + constructor(props) { + super(props); + const { pullBranch, mergeBranch } = getBranchParams( + this.props.location.pathname + ); + this.state = { + data: undefined, + pullBranches: undefined, + mergeBranches: undefined, + mergeProjects: undefined, + merge: mergeBranch || 'master', + pull: pullBranch || 'master', + id: undefined, + // isFork: false, + projects_names: undefined, + isSpin: true, + showMessage: false, + merge_head: false, // 是否向fork后的源项目发起合并请求 + defaultMessage: '必须选择不同的分支', + project_id: undefined, // 当前项目的id,也即开始发送合并请求的源项目id + merge_project_user: undefined, + comparesData: undefined, //提交和文件的内容,保存compare接口返回的数据 + // 比较分支时的加载效果 + isCompareSpin: true, + // 是否是初次加载,用这个字段来控制提示组件和文件组件的显示、隐藏比直接用isCompareSpin交互友好些 + isFirstLoading: true, + }; + } + + componentDidMount = () => { + // 初始化时根据url获取目标仓库、分支,源仓库、分支; + // 再获取对应的仓库列表、分支列表 + // 再调用比较接口 + const branchParams = getBranchParams(this.props.location.pathname); + this.getMergeInfo(branchParams); + }; + + componentDidUpdate = (preProps) => { + // url变化触发时(切换源分支、切换目标仓库、切换目标分支;回退) + const oldPathname = preProps.location.pathname; + const newPathname = this.props.location.pathname; + if (oldPathname !== newPathname) { + const branchParams = getBranchParams(newPathname); + this.getMergeInfo(branchParams); + } + }; + + //获取新建合并请求数据 + getMergeInfo = (branchParams) => { + this.setState({ isSpin: true }); + const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId } = + branchParams; + const url = `/${pullOwner}/${projectId}/pulls/new.json`; + axios + .get(url) + .then((result) => { + if (result) { + // 如果url上的分支不存在,取默认值master + const noMergeBranch = + (result.data.branches || []).filter( + (branch) => branch.name === mergeBranch + ).length === 0; + const noPullBranch = + (result.data.branches || []).filter( + (branch) => branch.name === pullBranch + ).length === 0; + this.setState({ + // isFork: result.data.is_fork, + projects_names: result.data.projects_names, + mergeProjects: result.data.merge_projects, + pullBranches: result.data.branches, + mergeBranches: result.data.branches, + project_id: result.data.project_id, + id: result.data.id, + merge: mergeBranch, + pull: pullBranch, + }); + + //判断源分支是否存在 + if(noPullBranch){ + this.setState({ + showMessage: true, + defaultMessage:'源分支不存在', + isCompareSpin: false, + }); + }else{ + if(pullOwner === mergeOwner){ + if (!noMergeBranch) { + this.compareProject(true, branchParams); + } else { + this.setState({ + showMessage: true, + defaultMessage:'目标分支不存在', + isCompareSpin: false, + }); + } + }else{ + this.getBranchList(branchParams); + } + } + } + this.setState({ isSpin: false }); + }) + .catch((error) => { + this.setState({ isSpin: false }); + console.log(error); + }); + }; + + // compare接口,获取分支对比信息 + compareProject = (sameProject, branchParams) => { + // const { project } = this.props; + // const { owner, projectsId } = this.props.match.params; + const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId } = + branchParams; + + let url = `/${mergeOwner}/${projectId}/compare`; + if (sameProject) { + url += `/${pullBranch}...${mergeBranch}.json`; + } else { + url += `/${mergeBranch}...${pullOwner}/${projectId}:${pullBranch}.json`; + } + this.setState({ isSpin: false, isCompareSpin: true }); + axios + .get(url) + .then((result) => { + if (result) { + if (result.data.status === 0) { + this.setState({ + showMessage: false, + }); + } else { + this.setState({ + showMessage: true, + defaultMessage: result.data.message, + }); + } + this.setState({ + comparesData: result.data, + }); + } + this.setState({ + isFirstLoading: false, + isSpin: false, + isCompareSpin: false, + }); + }) + .catch((error) => { + this.setState({ isSpin: false, isCompareSpin: false }); + }); + }; + + // 根据所有者、仓库名,获取分支列表,目前仅涉及目标仓库分支查询 + getBranchList = (branchParams) => { + const { mergeOwner, projectId, mergeBranch } = branchParams; + this.setState({ isSpin: true }); + const url = `/${mergeOwner}/${projectId}/pulls/get_branches.json`; + axios + .get(url) + .then((result) => { + if (result) { + const noMergeBranch = + (result.data || []).filter((branch) => branch.name === mergeBranch) + .length === 0; + this.setState({ + mergeBranches: result.data, + showMessage: noMergeBranch, + defaultMessage: '目标分支不存在', + isCompareSpin: false, + }); + !noMergeBranch && this.compareProject(false, branchParams); + } + this.setState({ isSpin: false }); + }) + .catch((error) => { + this.setState({ isSpin: false }); + console.log(error); + }); + }; + + // 切换分支事件 + selectBrach = (type, value) => { + const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId } = + getBranchParams(this.props.location.pathname); + let _url = `/${mergeOwner}/${projectId}/compare/`; + // type为pull时,pullBranch取value,否则取原有值 + // type为pull时,mergeBranch取原有值,否则取value + let _pullBranch = type === 'pull' ? value : pullBranch; + let _mergeBranch = type === 'pull' ? mergeBranch : value; + if (pullOwner === mergeOwner) { + // 如果仓库相同, compare/目标分支...源分支 + _url += `${_mergeBranch}...${_pullBranch}`; + } else { + // 如果仓库不同, compare/目标分支...源分支 + _url += `${_mergeBranch}...${pullOwner}:${_pullBranch}`; + } + this.props.history.push(_url); + }; + + // 切换仓库响应事件,目前仅目标分支可切换仓库 + selectProjectName = (value) => { + const { projects_names, id } = this.state; + const { pullOwner, pullBranch } = getBranchParams( + this.props.location.pathname + ); + let arr = + projects_names && projects_names.filter((item) => item.id === value); + let identifier = arr && arr[0].project_id; + let login = arr && arr[0].project_user_login; + // 目标仓库与源仓库不是一个仓库 + let is_fork = parseInt(value, 10) !== parseInt(id, 10); + this.setState({ + isSpin: true, + // merge_head: is_fork, + data: { + is_original: is_fork, + fork_project_id: is_fork ? id : '', + merge_user_login: is_fork + ? projects_names[0].project_user_login + : undefined, + }, + }); + if (login === pullOwner) { + // 如果切换后, 仓库与源仓库一致了 + this.props.history.push( + `/${login}/${identifier}/compare/master...${pullBranch}` + ); + } else { + this.props.history.push( + `/${login}/${identifier}/compare/master...${pullOwner}:${pullBranch}` + ); + } + // this.newMergelist(login, identifier); + }; + + // 渲染分支列表 + renderBrances = (list) => { + if (list && list.length > 0) { + return list.map((item, key) => { + return ( + + ); + }); + } + }; + + // 渲染项目列表 + renderProjectNames = (list) => { + if (list && list.length > 0) { + return list.map((item, key) => { + return ( + + ); + }); + } + }; + + // 渲染html内容 + withHtml = (html) => { + return
    ; + }; + + render() { + const { + data, + pullBranches, + mergeBranches, + mergeProjects, + pull, + merge, + isSpin, + isCompareSpin, + isFirstLoading, + showMessage, + defaultMessage, + projects_names, + id, + comparesData, + } = this.state; + + let { project } = this.props; + + return ( +
    + +
    +
    +
    +
    源分支:
    + + + + +
    +
    + +
    +
    +
    +
    目标分支:
    + + + + +
    +
    +
    + {/* 非加载状态且有提示 */} + {!isCompareSpin && showMessage && ( +
    + +
    + )} + {/* 非加载状态且可以提交 */} + {!isCompareSpin && !showMessage && ( + + )} +
    + {!isFirstLoading && ( + + )} +
    +
    + ); + } +} + +export default CreateMerge; diff --git a/src/forge/Merge/Files.jsx b/src/forge/Merge/Files.jsx index 82a8638c6..b4cf5b488 100644 --- a/src/forge/Merge/Files.jsx +++ b/src/forge/Merge/Files.jsx @@ -1,17 +1,24 @@ import React ,{useEffect,useState } from 'react'; import { truncateCommitId } from '../common/util'; import { AlignCenter , FlexAJ } from '../Component/layout'; -import { Button } from 'antd'; +import { Tooltip,Progress } from 'antd'; import './merge.css'; +import './Index.scss'; -function Files({data,history,owner,projectsId}){ +function Files({ data,history,owner,projectsId , parentsSha }){ const [ files , setFiles ] = useState(data && data.files); - + const [ copyfileTipTitle, setCopyfileTipTitle] = useState("复制文件路径"); + const [ isOpen, setIsOpen] = useState(false); + useEffect(()=>{ if(data){ setFiles(data.files); } - },[data]) + },[data]); + + useEffect(()=>{ + document.addEventListener('click',()=>{setIsOpen(false)}) + }) function showDown(flag,index,isBin){ if(!isBin){ @@ -22,35 +29,86 @@ function Files({data,history,owner,projectsId}){ } } + function copyFileName(fileName){ + var copyCont = document.createElement('input'); + copyCont.defaultValue = fileName; + document.body.appendChild(copyCont); + copyCont.select(); // 选择对象 + document.execCommand("Copy"); // 执行浏览器复制命令 + copyCont.className = 'copyCont'; + copyCont.style.display='none'; + setCopyfileTipTitle("复制成功"); + } + + const folderOpen = ( + + ) + return( -
    - - - - 共有 {data && data.files_count} 个文件被更改,包括 +
    {e.nativeEvent.stopImmediatePropagation()}}> + +
    {setIsOpen(!isOpen)}}> + + + 共有 {data && data.files_count} 个文件 被更改,包括 { data && data.total_addition ? {data && data.total_addition} 次插入:"" } { data && data.total_addition && data.total_deletion ? " 和 ":""} { data && data.total_deletion ? {data && data.total_deletion} 次删除:""} - + +
    + {isOpen && folderOpen}
    { files && files.length>0 && -
    +
    { files.map((item,key)=>{ return(
    - showDown(item.flag,key,item.isBin)}> + + - {!item.isBin ? :""} - - {item.name} + {!item.isBin ? showDown(item.flag,key,item.isBin)}>:""} + showDown(item.flag,key,item.isBin)}>{item.name} + setCopyfileTipTitle("复制文件路径")} + > + copyFileName(item.name)}> + - - - +{item.addition} - -{item.deletion} - +
    + 0 ? ":":""} ${item.addition > 0 ? item.addition + "处添加" : ""}${item.addition > 0 && item.deletion > 0 ? "和" : ""}${item.deletion > 0 ? item.deletion + "处删除" : ""}`}> + + {item.addition+item.deletion}处 + + { + !item.isSubmodule && + {history.push(`/${owner}/${projectsId}${item.isDeleted ? `/commits/${truncateCommitId(parentsSha)}`:`/tree/${truncateCommitId(item.sha)}/${item.name}`}`)}}>查看文件 + } +
    { item.sections && item.sections.length >= 1 && !item.flag && diff --git a/src/forge/Merge/Index.scss b/src/forge/Merge/Index.scss index 936b868f8..16cc95632 100644 --- a/src/forge/Merge/Index.scss +++ b/src/forge/Merge/Index.scss @@ -18,4 +18,86 @@ .pr_tags_closed{ border:1px solid #FA6400; color: #FA6400; +} +.update-file-count{ + cursor: pointer; + & .color-grey-3{ + font-weight: bold; + } +} +.fileList{ + .sc-bxivhb{ + width: 55rem; + overflow: hidden; + white-space: normal; + word-break: break-all; + } + .see-file{ + width: 14rem; + .ml10{ + display: inline-block; + width: 4.5rem; + cursor: default; + } + span{ + width: 7%; + } + } + .anchorPoint{ + position: relative; + top: -5rem; + display: block; + height: 0; + } +} +.filesInfo{ + background: #FAFCFF; + border-color:rgba(42, 97, 255, 0.23); + .ant-progress-line { + width: 5rem; + } + .ant-progress-inner{ + background-color: #D14A4A; + } +} +.folders,.ant-anchor{ + margin-left: 0; + padding-left: 0; +} +.folders{ + position: absolute; + z-index: 2; + left: 0px; + top: 37px; + color: #333333; + width: 75rem; + box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5); + border-radius: 4px; + border: 1px solid rgba(153, 153, 153, 0.32); + .ant-anchor-link-active > .ant-anchor-link-title { + color: #466AFF; + } + .ant-anchor-link { + padding: 0px; + } + .folderList{ + max-height: 275px; + overflow:auto; + .files{ + border: 0px; + } + .filesInfo { + padding: 10px 18px 10px 15px; + height: 55px; + background: #FFF; + border-bottom: 1px solid #EEEEEE; + &:hover{ + background: #F3F4F6; + } + .color-green,.color-red{ + width: 3%; + text-align: right; + } + } + } } \ No newline at end of file diff --git a/src/forge/Merge/MergeDetail.js b/src/forge/Merge/MergeDetail.js index 76c31ba0a..11bd3858b 100644 --- a/src/forge/Merge/MergeDetail.js +++ b/src/forge/Merge/MergeDetail.js @@ -228,7 +228,7 @@ class MergeDetail extends Component {
    { data && data.issue.user_permission ? - 编辑 + 编辑 : '' }
    diff --git a/src/forge/Merge/MergeItem.js b/src/forge/Merge/MergeItem.js index 884c50feb..61477c142 100644 --- a/src/forge/Merge/MergeItem.js +++ b/src/forge/Merge/MergeItem.js @@ -62,9 +62,9 @@ class MergeItem extends Component {

    {item.name} @@ -110,7 +110,7 @@ class MergeItem extends Component { {item.is_original ? item.fork_project_user @@ -134,7 +134,7 @@ class MergeItem extends Component { {/* {item.is_fork ? item.pull_request_base : `${item.author_name}:${item.pull_request_base}`} */} {project_author_name}:{item.pull_request_base} @@ -175,7 +175,7 @@ class MergeItem extends Component { {item.journals_count ? ( {item.journals_count} @@ -196,7 +196,7 @@ class MergeItem extends Component { >

    diff --git a/src/forge/Merge/MergeLinkFooter.jsx b/src/forge/Merge/MergeLinkFooter.jsx new file mode 100644 index 000000000..2c9aa4814 --- /dev/null +++ b/src/forge/Merge/MergeLinkFooter.jsx @@ -0,0 +1,210 @@ +import React, { Component } from 'react'; +import { Tabs, Spin } from 'antd'; +import { Link } from 'react-router-dom'; +import axios from 'axios'; + +import Commits from './Commits'; +import Comments from '../comments/comments'; +import Files from './Files'; + +import '../Order/order.css'; +import './merge.css'; + +const { TabPane } = Tabs; + +class MergeFooter extends Component { + constructor(props) { + super(props); + this.state = { + commitsData: [], + filesData: undefined, + isSpin: false, + activeKey: '1', + commitCount: 0, + filesCount: 0, + // 总评论数量,包含回复 + commentsTotalCount: 0, + }; + } + componentDidMount() { + this.Init(); + // 为父组件绑定当前,以方便调用方法 + this.props.bindFootRef && this.props.bindFootRef(this); + } + + componentDidUpdate(prevProps) { + // 解决切换tab后浏览器回退不刷新的问题、点击tab后url变化但tab未切换的问题 + const newPathname = this.props.location.pathname; + const prevPathname = prevProps.location.pathname; + if (newPathname !== prevPathname) { + this.Init(true); + } + } + + Init = (isTabChange) => { + const { data, location, match } = this.props; + const { pathname } = location; + const { projectsId, owner, mergeId } = match.params; + + let activeKey = '1'; + if (pathname.indexOf('commits') > -1) { + activeKey = '2'; + this.getCommit(owner, projectsId, mergeId); + } else if (pathname.indexOf('files') > -1) { + activeKey = '3'; + this.getFile(owner, projectsId, mergeId); + } + if (isTabChange && activeKey === '1') { + this.refreshComment(); + } + this.setState({ + activeKey: activeKey, + commitCount: data && data.commits_count, + filesCount: data && data.files_count, + }); + }; + + bindCommentRef = (commentRef) => { + this.childComment = commentRef; + } + + refreshComment = () => { + this.childComment && this.childComment.getjournalslist(); + } + + getCommit = (owner, projectsId, mergeId) => { + this.setState({ isSpin: true }); + const url = `/${owner}/${projectsId}/pulls/${mergeId}/commits.json`; + axios + .get(url) + .then((result) => { + if (result) { + this.setState({ + commitsData: result.data.commits, + commitCount: result.data.commits_count, + }); + } + this.setState({ isSpin: false }); + }) + .catch((error) => { + this.setState({ isSpin: false }); + }); + }; + + getFile = (owner, projectsId, mergeId) => { + this.setState({ isSpin: true }); + const url = `/${owner}/${projectsId}/pulls/${mergeId}/files.json`; + axios + .get(url) + .then((result) => { + if (result) { + this.setState({ + filesData: result.data, + filesCount: result.data.files_count, + }); + } + this.setState({ isSpin: false }); + }) + .catch((error) => { + this.setState({ isSpin: false }); + }); + }; + + render() { + const { projectsId, owner, mergeId } = this.props.match.params; + + const { order_id, data = {} } = this.props; + const { + isSpin, + activeKey, + filesCount, + commitCount, + filesData, + commitsData = [], + } = this.state; + + // 评论数量优先取Comment组件中列表接口返回的,其次取合并请求详情接口中的,都没有取默认值0 + const commentsTotalCount = parseInt( + this.state.commentsTotalCount || data.comments_total_count || 0, + 10 + ); + + return ( +
    + + + + 评论 + {commentsTotalCount > 0 && ( + {commentsTotalCount} + )} + + } + key="1" + > + { + this.setState({ commentsTotalCount: commentsCount || 0 }); + }} + {...this.props} + bindCommentRef={this.bindCommentRef} + /> + + {commitCount > 0 && ( + + 提交 + {commitCount > 0 && ( + {commitCount} + )} + + } + key="2" + > + {commitsData.length > 0 && ( + + )} + + )} + {filesCount > 0 && ( + + 文件 + {filesCount > 0 && ( + {filesCount} + )} + + } + key="3" + > + + + )} + + +
    + ); + } +} +export default MergeFooter; diff --git a/src/forge/Merge/MessageCount.js b/src/forge/Merge/MessageCount.js index b064e3c2f..6d01e8a37 100644 --- a/src/forge/Merge/MessageCount.js +++ b/src/forge/Merge/MessageCount.js @@ -1,7 +1,6 @@ import React, { Component } from "react"; import { Tabs } from 'antd'; import { Link } from "react-router-dom"; -import { AlignCenter } from '../Component/layout'; import axios from "axios"; import { getImageUrl } from "educoder"; import { @@ -11,7 +10,6 @@ import { Dropdown, Icon, Menu, - Select, Tag, Button, Alert, @@ -19,9 +17,8 @@ import { import "./merge.css"; import RenderHtml from "../../components/render-html"; import "../Order/order.css"; -import MergeFooter from "./merge_footer"; +import MergeLinkFooter from "./MergeLinkFooter"; -const Option = Select.Option; const TextArea = Input.TextArea; function turnbar(str){ @@ -61,6 +58,11 @@ class MessageCount extends Component { // this.clickBody(); }; + + bindFootRef = (footRef) => { + this.footRef = footRef; + } + clickBody=()=>{ document.body.addEventListener('click', e => { let name = e.target.className; @@ -150,6 +152,8 @@ class MessageCount extends Component { }); const { getDetail } = this.props; getDetail && getDetail(); + // 调用子组件的方法刷新评论列表 + this.footRef && this.footRef.refreshComment(); } else { this.setState({ SpinMerge: false }); } @@ -283,13 +287,13 @@ class MessageCount extends Component { conflict_files && conflict_files.length>0 &&

    如下文件有代码冲突:

    -

    +

    { conflict_files.map((i,k)=>{ - return

    {i}

    + return

    {i}

    }) } -

    +
    }
    @@ -336,11 +340,11 @@ class MessageCount extends Component {
    -
    -
    +
    +
    - + {data.issue.subject} @@ -362,9 +366,9 @@ class MessageCount extends Component { - {data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}: {turnbar(data.pull_request && data.pull_request.head)} + {data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}: {data.pull_request && data.pull_request.head} @@ -377,7 +381,7 @@ class MessageCount extends Component { {data.issue.project_author_name}:{data.pull_request.base} @@ -441,14 +445,13 @@ class MessageCount extends Component {
    -
    -
    +
    {operate && ( @@ -465,7 +468,6 @@ class MessageCount extends Component { )}
    -
    { data.issue.description ? @@ -543,7 +545,7 @@ class MessageCount extends Component { onChange={this.changbodypr} />
    -

    @@ -558,19 +560,19 @@ class MessageCount extends Component { 取消 -

    +
    )}
    - + bindFootRef={this.bindFootRef} + >
    ) : ( "" diff --git a/src/forge/Merge/NewMerge.js b/src/forge/Merge/NewMerge.js index 8913b0d1c..900dea824 100644 --- a/src/forge/Merge/NewMerge.js +++ b/src/forge/Merge/NewMerge.js @@ -6,6 +6,11 @@ import "./merge.css"; import MergeForm from "./merge_form"; import MergeFooter from "./merge_footer"; const Option = Select.Option; +/** + * 此文件已废弃,新文件为CreateMerge.js + * 2021.10.12 + */ + class NewMerge extends Component { constructor(props) { super(props); @@ -194,7 +199,7 @@ class NewMerge extends Component { // this.ischeckmerge(); let { id ,merge , pull } = this.state; if(type==="pull"){ - this.props.history.push(`/${owner}/${projectsId}/pulls/new/${pull}`) + this.props.history.push(`/${owner}/${projectsId}/compare/${pull}`) this.compareProject(id,value,merge); }else{ this.compareProject(id,pull,value); @@ -216,7 +221,7 @@ class NewMerge extends Component { merge_user_login: is_fork_id ? projects_names[0].project_user_login : undefined } }) - this.props.history.push(`/${login}/${identifier}/pulls/new`); + this.props.history.push(`/${login}/${identifier}/compare`); this.newMergelist(login,identifier); }; diff --git a/src/forge/Merge/UpdateMerge.js b/src/forge/Merge/UpdateMerge.js index 8ed8034af..8918db6eb 100644 --- a/src/forge/Merge/UpdateMerge.js +++ b/src/forge/Merge/UpdateMerge.js @@ -64,12 +64,12 @@ class UpdateMerge extends Component {
    源分支:
    - {" "} {" "} @@ -83,12 +83,12 @@ class UpdateMerge extends Component {
    目标分支 :
    {" "} - {" "} {" "} diff --git a/src/forge/Merge/merge.css b/src/forge/Merge/merge.css index 6b50eeb10..d61543b49 100644 --- a/src/forge/Merge/merge.css +++ b/src/forge/Merge/merge.css @@ -40,6 +40,7 @@ form .ant-cascader-picker, form .ant-select { } .merge-header-button{ background:rgba(241,248,255,1); + text-align: left; } .width70{ width:70%; @@ -152,13 +153,23 @@ form .ant-cascader-picker, form .ant-select { margin-top: 15px; border-radius: 2px; } +.see-file-btn{ + color: #466AFF; + cursor: pointer; +} .filesInfo{ padding:10px 15px; background-color: #fafafa; } +.filesInfo .cursor-pointer{ + cursor: pointer; +} .filesContent{ border-top: 1px solid #ddd; } +.icon-fuzhiicon:hover{ + color: #466AFF; +} .linesContent{ display: flex; min-height: 30px; @@ -198,4 +209,17 @@ form .ant-cascader-picker, form .ant-select { } .linesContent.add{ background: rgba(48, 232, 132, 0.15); -} \ No newline at end of file +} + +.mergeRequest .folders{ + /* width: 72rem; */ + width: 100%; + } + + .matchwidth .ant-select-selection__rendered{ + width: 200px; + } + .overlihide li{ + max-width: 450px; + + } \ No newline at end of file diff --git a/src/forge/Merge/merge.js b/src/forge/Merge/merge.js index 399c9bd91..8a0eaedea 100644 --- a/src/forge/Merge/merge.js +++ b/src/forge/Merge/merge.js @@ -213,7 +213,7 @@ class merge extends Component { checkOperation() { const { projectsId,owner } = this.props.match.params; - this.props.history.push(`/${owner}/${projectsId}/pulls/new`); + this.props.history.push(`/${owner}/${projectsId}/compare/master...master`); } render() { const { projectsId , owner } = this.props.match.params; diff --git a/src/forge/Merge/merge_footer.js b/src/forge/Merge/merge_footer.js index 6502827cd..868e736fe 100644 --- a/src/forge/Merge/merge_footer.js +++ b/src/forge/Merge/merge_footer.js @@ -1,169 +1,84 @@ -import React, { Component } from "react"; -import { Tabs, Spin } from "antd"; -import "../Order/order.css"; -import "./merge.css"; -import Commits from "./Commits"; -import Comments from "../comments/comments"; -import Files from "./Files"; -import axios from 'axios'; +import React, { Component } from 'react'; +import { Tabs } from 'antd'; +import Commits from './Commits'; +import Files from './Files'; + +import '../Order/order.css'; +import './merge.css'; + const { TabPane } = Tabs; class MergeFooter extends Component { - constructor(props){ + constructor(props) { super(props); - this.state={ - pageData:undefined, - commitsData:undefined, - filesData:undefined, - isSpin:false, - activeKey:"1", - commitCount:0, - filesCount:0 - } - } - componentDidMount=()=>{ - const { footer_type ,data } = this.props; - if(footer_type){ - const { projectsId , owner , mergeId } = this.props.match.params; - this.getCommit(owner,projectsId,mergeId); - this.getFile(owner,projectsId,mergeId); - } - this.setState({ - activeKey:footer_type ? "1" : "2", - commitCount:data && data.commits_count, - filesCount:data && data.files_count - }) - } - componentDidUpdate=(prevProps)=>{ - const { comparesData } = this.props; - const { footer_type } = this.props; - if(footer_type){ - const { data } = this.props; - if(data !== prevProps.data){ - this.setState({ - commitCount:data && data.commits_count, - filesCount:data && data.files_count - }) - } - } - if(comparesData !== prevProps.comparesData){ - this.setState({ - activeKey:footer_type ? "1" : "2" - }) - this.changeTab(footer_type ? "1" : "2"); - } + this.state = { + activeKey: '1', + }; } - changeTab=(index)=>{ + changeTab = (index) => { this.setState({ - isSpin:true - }) - this.setState({ - activeKey:index - }) - const { footer_type , comparesData } = this.props; - const { projectsId , owner , mergeId } = this.props.match.params; - - if(footer_type){ - if(index === "2"){ - this.getCommit(owner,projectsId,mergeId); - }else if(index === "3"){ - this.getFile(owner,projectsId,mergeId); - }else{ - this.setState({ - isSpin:false - }) - } - }else{ - this.setState({ - commitsData:comparesData.commits, - filesData:comparesData.diff, - commitCount:comparesData.commits_count, - filesCount:comparesData.diff && comparesData.diff.files_count, - isSpin:false - }) - } - } - - getCommit =(owner,projectsId,mergeId)=>{ - const url = `/${owner}/${projectsId}/pulls/${mergeId}/commits.json`; - axios.get(url).then(result=>{ - if(result){ - this.setState({ - commitsData:result.data.commits, - isSpin:false, - commitCount:result.data.commits_count - }) - } - }).catch(error=>{}) - } - - getFile =(owner,projectsId,mergeId)=>{ - const url = `/${owner}/${projectsId}/pulls/${mergeId}/files.json`; - axios.get(url).then(result=>{ - if(result){ - this.setState({ - filesData:result.data, - isSpin:false, - filesCount:result.data.files_count, - }) - } - }).catch(error=>{}) - } + activeKey: index, + }); + }; render() { - const { projectsId , owner } = this.props.match.params; + const { projectsId, owner } = this.props.match.params; + const { comparesData = {} } = this.props; + const { commits, diff, commits_count } = comparesData; + const { activeKey } = this.state; - const { footer_type, order_id, data , comparesData } = this.props; - let { isSpin , activeKey , filesCount, commitCount , filesData , commitsData } = this.state; - - return ( - !footer_type && !comparesData || (comparesData && ((comparesData.commits && comparesData.commits.length===0)||(comparesData && !comparesData.diff)) )?"": -
    - - - { - footer_type && - 评论 - {data && parseInt(data.comments_count) > 0 && {data.comments_count}} - - } key="1"> - - - } - { - commitsData && commitsData.length > 0 && - 提交 - {commitCount > 0 && {commitCount}} - } key="2"> - - - } - { - filesData && filesData.files && filesData.files.length>0 && - 文件 - {filesCount > 0 && {filesCount}} - - } key="3"> - - - } - - - + return (commits && commits.length === 0) || !diff ? ( + '' + ) : ( +
    + + {commits && commits.length > 0 && ( + + 提交 + {commits_count > 0 && ( + {commits_count} + )} + + } + key="1" + > + + + )} + {diff && diff.files && diff.files.length > 0 && ( + + 文件 + {diff.files_count > 0 && ( + {diff.files_count} + )} + + } + key="3" + > + + + )} +
    ); } diff --git a/src/forge/Merge/merge_form.js b/src/forge/Merge/merge_form.js index 5df9794bb..e63781391 100644 --- a/src/forge/Merge/merge_form.js +++ b/src/forge/Merge/merge_form.js @@ -165,7 +165,8 @@ class MergeForm extends Component { this.setState({ isSpin: false, }); - this.props.history.push(`/${owner}/${projectsId}/pulls`); + const { pull_request_id } = result.data; + this.props.history.push(`/${owner}/${projectsId}/pulls/${pull_request_id}`); const { getDetail } = this.props; getDetail && getDetail(); } else { @@ -195,7 +196,7 @@ class MergeForm extends Component { isSpin: false, }); this.props.history.push( - `/${owner}/${projectsId}/pulls/${mergeId}/Messagecount` + `/${owner}/${projectsId}/pulls/${mergeId}` ); } else { this.setState({ @@ -264,7 +265,7 @@ class MergeForm extends Component { }, ], initialValue: title, - })()} + })()} { - this.props.history.push(merge_type === "new" ? `/${owner}/${projectsId}/pulls` : `/${owner}/${projectsId}/pulls/${mergeId}/detail`) + this.props.history.push(merge_type === "new" ? `/${owner}/${projectsId}/pulls` : `/${owner}/${projectsId}/pulls/${mergeId}`) }} > 取消 diff --git a/src/forge/Merge/no_data.js b/src/forge/Merge/no_data.js index d5584797f..d5e4ca89b 100644 --- a/src/forge/Merge/no_data.js +++ b/src/forge/Merge/no_data.js @@ -12,7 +12,7 @@ class Nodata extends Component{

    欢迎使用合并请求!

    - 合并请求可以帮助您与他人协作编写代码。在使用之前,请先创建一个 合并请求 + 合并请求可以帮助您与他人协作编写代码。在使用之前,请先创建一个 合并请求
    diff --git a/src/forge/New/Index.js b/src/forge/New/Index.js index c6eb2c3d5..e9aa1f952 100644 --- a/src/forge/New/Index.js +++ b/src/forge/New/Index.js @@ -285,12 +285,16 @@ class Index extends Component { if(value.indexOf("/") > -1){ let arr = value.split("/"); let first = arr[arr.length-1]; - if(first.indexOf(".git") > -1){ + if(first.indexOf(".") > -1){ let second = first.split('.')[0]; if(!second)return; this.props.form.setFieldsValue({ repository_name:second }) + }else{ + this.props.form.setFieldsValue({ + repository_name:first + }) } } } @@ -351,7 +355,7 @@ class Index extends Component { required: true, message: '请填写镜像版本库地址' }], })( - + )}

    示例:https://github.com/facebook/reack.git

    diff --git a/src/forge/Newfile/Index.js b/src/forge/Newfile/Index.js index 9b7769552..953f50720 100644 --- a/src/forge/Newfile/Index.js +++ b/src/forge/Newfile/Index.js @@ -65,16 +65,18 @@ class Index extends Component {
    - +
    + +
    diff --git a/src/forge/Newfile/UserSubmitComponent.js b/src/forge/Newfile/UserSubmitComponent.js index 65fa7ec24..aa4bba6e9 100644 --- a/src/forge/Newfile/UserSubmitComponent.js +++ b/src/forge/Newfile/UserSubmitComponent.js @@ -83,8 +83,8 @@ class UserSubmitComponent extends Component { if (result.data && result.data.name) { this.props.showNotification("文件新建成功!"); if(submitType === "1"){ - const { getTopCount } = this.props; - getTopCount && getTopCount(values.branchname); + const { getDetail } = this.props; + getDetail && getDetail(); } let url = `/${owner}/${projectsId}${values.branchname ? `/tree/${turnbar(values.branchname)}`: (branch ? `/tree/${turnbar(branch)}` : "")}`; this.props.history.push(url); @@ -147,6 +147,7 @@ class UserSubmitComponent extends Component { const { current_user, filepath, projectDetail , currentBranch } = this.props; const { editor_type } = this.props; let b = currentBranch || branch; + return (
    diff --git a/src/forge/Newfile/index.css b/src/forge/Newfile/index.css index 242fd4516..746febe55 100644 --- a/src/forge/Newfile/index.css +++ b/src/forge/Newfile/index.css @@ -8,7 +8,13 @@ border: 1px solid #d9d9d9!important; border-right: none!important; } - +.editorBorder .editorBorderBox{ + border:1px solid #eee; + border-radius: 2px; +} +.editorBorder .editorBorderSubmitBox{ + padding:20px 0px!important; +} .userScrew{ margin:20px 0px; border:1px solid #f4f4f4; @@ -39,7 +45,7 @@ z-index: 1; } .ant-input-group .ant-input:focus{ - border-right: 1px solid #d9d9d9!important; + border-right: 1px solid rgba(70, 106, 255, 1)!important; } .ant-btn-primary.grey{ border:1px solid #BBBBBB; diff --git a/src/forge/Newfile/m_editor.js b/src/forge/Newfile/m_editor.js index 05a7b2ac0..13d2ec466 100644 --- a/src/forge/Newfile/m_editor.js +++ b/src/forge/Newfile/m_editor.js @@ -1,5 +1,7 @@ import React, { Component } from "react"; import Editor from "react-monaco-editor"; +// import {UnControlled as CodeMirror} from 'react-codemirror2' + import UserSubmitComponent from "./UserSubmitComponent"; import "./index.css"; @@ -10,6 +12,7 @@ class m_editor extends Component { super(props); this.state = { editorValue: this.props.content, + prevHeight:0 }; } componentDidUpdate=(prevProps)=>{ @@ -41,42 +44,92 @@ class m_editor extends Component { folding: true, foldingStrategy: "indentation", // 代码可分小段折叠 automaticLayout: true, // 自适应布局 - // overviewRulerBorder: false, // 不要滚动条的边框 - // scrollBeyondLastLine: false, // 取消代码后面一大段空白 + overviewRulerBorder: false, // 不要滚动条的边框 + scrollBeyondLastLine: false, // 取消代码后面一大段空白 minimap: { // 不要小地图 enabled: false, }, }; + + const handleEditorMount = (editor, monaco) => { + editor.onDidChangeModelDecorations(() => { + requestAnimationFrame(updateEditorHeight); // folding + }); + + const updateEditorHeight = () => { + const editorElement = editor.getDomNode(); + + if (!editorElement) { + return; + } + + const padding = 40; + + const lineHeight = editor.getOption( + monaco.editor.EditorOption.lineHeight + ); + + const lineCount = editor.getModel().getLineCount() || 1; + let height = + editor.getTopForLineNumber(lineCount + 1) + + lineHeight + + padding ; + + if(height<400){height = 400;} + + if (this.state.prevHeight !== height) { + this.setState({ + prevHeight:height + }) + // setPrevHeight(height); + editorElement.style.height = `${height}px`; + editor.layout(); + } + }; + + updateEditorHeight(); // typing + }; + + return ( -
    -
    - -
    - {!readOnly && ( -
    - -
    - )} -
    +
    + + {/* */} +
    + {!readOnly && ( +
    + +
    + )}
    ); } diff --git a/src/forge/Order/Detail.js b/src/forge/Order/Detail.js index b377b6a1d..4d1b47cfc 100644 --- a/src/forge/Order/Detail.js +++ b/src/forge/Order/Detail.js @@ -123,22 +123,25 @@ class Detail extends Component { //复制 copydetail = () => { const { projectsId, orderId, owner } = this.props.match.params; - const url = `/${owner}/${projectsId}/issues/${orderId}/copy.json`; - axios - .post(url, { - project_id: projectsId, - id: orderId, - }) - .then((result) => { - if (result) { - this.props.history.push( - `/${owner}/${projectsId}/issues/${result.data.issue_id}/copyetail` - ); - } - }) - .catch((error) => { - console.log(error); - }); + // const url = `/${owner}/${projectsId}/issues/${orderId}/copy.json`; + // axios + // .post(url, { + // project_id: projectsId, + // id: orderId, + // }) + // .then((result) => { + // if (result) { + // this.props.history.push( + // `/${owner}/${projectsId}/issues/${result.data.issue_id}/copyetail` + // ); + // } + // }) + // .catch((error) => { + // console.log(error); + // }); + this.props.history.push( + `/${owner}/${projectsId}/issues/${orderId}/copyetail` + ); }; // 翻页 @@ -230,7 +233,7 @@ class Detail extends Component { : "合并请求"} 】
    - {data && data.subject} + {data && data.subject} {data && data.priority && ( diff --git a/src/forge/Order/order_form.js b/src/forge/Order/order_form.js index 2c572d594..3399a7feb 100644 --- a/src/forge/Order/order_form.js +++ b/src/forge/Order/order_form.js @@ -178,7 +178,6 @@ class order_form extends Component { this.setState({ isSpin: false, }); - console.log(error); }); } else { const url = `/${owner}/${projectsId}/issues/${orderId}.json`; @@ -321,7 +320,7 @@ class order_form extends Component { message: "请填写易修标题", }, ] - })()} + })()}
    @@ -59,11 +60,11 @@ function Index(props){
  • 个人信息
  • -1 ?"active":""}>基本资料
  • -
      + {notice_url &&
      • 消息通知
      • -1 && pathname.indexOf("/settings/notice/config") == -1) || pathname.indexOf("/settings/notice/privateLetter")>-1 ?"active":""}>我的通知
      • - {/*
      • -1 ?"active":""}>通知管理
      • */} -
      +
    • -1 ?"active":""}>通知管理
    • +
    }
    • 安全设置
    • -1 ?"active":""}>SSH密钥
    • @@ -72,18 +73,24 @@ function Index(props){ - ( - - )} - > ( )} > + ( + + )} + > + ( + + )} + > ( @@ -102,12 +109,6 @@ function Index(props){ )} > - ( - - )} - > diff --git a/src/forge/SecuritySetting/notice/manager/Index.jsx b/src/forge/SecuritySetting/notice/manager/Index.jsx index ebe84beac..5ba82d60c 100644 --- a/src/forge/SecuritySetting/notice/manager/Index.jsx +++ b/src/forge/SecuritySetting/notice/manager/Index.jsx @@ -1,9 +1,52 @@ -import { Button, Checkbox } from "antd"; -import React from "react"; - +import { Checkbox } from "antd"; +import React, { useEffect, useState } from "react"; +import axios from 'axios'; import './Index.scss'; function NoticeManager(props){ + const {current_user} = props; + + const [settingTypes, setSettingTypes] = useState(); + const [userNotification, setUserNotification] = useState(); + const [userEmail, setUserEmail] = useState(); + + function onChange(type,e,setting){ + let notification_body = userNotification; + let email_body = userEmail; + if(type){//站内信 + notification_body[setting] = e.target.checked; + }else{//邮件 + email_body[setting] = e.target.checked; + } + axios.post(`/users/${current_user.login}/template_message_settings/update_setting.json`,{ + setting:{ + notification_body:notification_body, + email_body:email_body + } + }).then(response=>{ + if(response && response.status === 0){ + getUserSettings(); + } + }) + } + + function getUserSettings(){ + axios.get(`/users/${current_user.login}/template_message_settings.json`).then((response)=>{ + if(response && response.status === 200 ){ + setUserEmail(response.data.email_body); + setUserNotification(response.data.notification_body); + } + }) + } + + useEffect(()=>{ + axios.get("/template_message_settings.json").then(response => { + if (response && response.status === 200) { + setSettingTypes(response.data.setting_types); + } + }) + getUserSettings(); + },[]) return(
      @@ -12,87 +55,23 @@ function NoticeManager(props){
      您可以通过通知管理来选择接受通知的方式 -
      - 我创建或负责的 -
      -
      -
      易修状态变更
      - 站内信 - 邮件 -
      -
      -
      易修截止日期到达最后一天
      - 站内信 - 邮件 -
      -
      -
      合并请求状态变更
      - 站内信 - 邮件 -
      -
      -
      易修有新的评论
      - 站内信 - 邮件 -
      -
      -
      合并请求有新的评论
      - 站内信 - 邮件 -
      - -
      - 我管理的仓库 -
      -
      -
      被关注
      - 站内信 - 邮件 -
      -
      -
      被点赞
      - 站内信 - 邮件 -
      -
      -
      被复刻
      - 站内信 - 邮件 -
      -
      -
      有新的里程碑
      - 站内信 - 邮件 -
      - -
      - 我关注的仓库 -
      -
      -
      被删除
      - 站内信 - 邮件 -
      -
      -
      被转移
      - 站内信 - 邮件 -
      -
      -
      有新的易修
      - 站内信 - 邮件 -
      -
      -
      有新的合并请求
      - 站内信 - 邮件 -
      -
      -
      有新的版本发布
      - 站内信 - 邮件 -
      + {settingTypes && userNotification && userEmail && settingTypes.map((item,key)=>{ + return( + item.type_name &&
      +
      {item.type_name}
      + {item.settings.map((i, k) => { + const setting = item.type.substring(item.type.indexOf("::")+2)+"::"+i.key; + return ( +
      +
      {i.name}
      + {onChange(true,e,setting)}}>站内信 + {onChange(false,e,setting)}}>邮件 +
      + ) + })} +
      + ) + })}
    ) diff --git a/src/forge/SecuritySetting/notice/myNotice/Index.jsx b/src/forge/SecuritySetting/notice/myNotice/Index.jsx index 2de2b8c3f..226606919 100644 --- a/src/forge/SecuritySetting/notice/myNotice/Index.jsx +++ b/src/forge/SecuritySetting/notice/myNotice/Index.jsx @@ -9,10 +9,9 @@ import './Index.scss'; import '../manager/Index.scss' function MyNotice(props) { - let current_user = props.current_user; - let resetUserInfo = props.resetUserInfo; + let { current_user, resetUserInfo, location, mygetHelmetapi, history}= props; //消息悬停框选择tab - let popover = props.location.query && props.location.query.noticeType; + let popover = location && location.query && location.query.noticeType; let pageSize = 15; const [noticeType, setNoticeType] = useState(popover==="atme"?"2":"0");//消息类别tab栏选择 const [selectedNum, setSelectedNum] = useState(0);//@我批量删除选择消息条数 @@ -27,6 +26,18 @@ function MyNotice(props) { const [currentPage, setCurrentPage] = useState(1);//当前页数 const [onlyUnread, setOnlyUnread] = useState(); + //登录情况下,通过地址访问,直接跳转:/settings/profile + //未登录情况下,通过地址访问,直接跳转:/explore + useEffect(()=>{ + let notice = mygetHelmetapi && mygetHelmetapi.common && mygetHelmetapi.common.notice; + let login = current_user && current_user.login; + if(!login){ + history.push(`/explore`); + }else if(!notice){ + history.push(`/settings/profile`); + } + },[mygetHelmetapi]) + useEffect(()=>{ popover==="atme" ? setNoticeType("2"):setNoticeType("0"); },[popover]) @@ -46,7 +57,7 @@ function MyNotice(props) { limit: pageSize, page: currentPage, }; - axios.get(`/users/${current_user.login}/messages.json`, { + current_user && axios.get(`/users/${current_user.login}/messages.json`, { params: params, }).then((response) => { if(response && response.data){ @@ -59,7 +70,7 @@ function MyNotice(props) { } function readNotice(id){ - if(id){ + if(id && current_user){ const params = { type: noticeType === "0" ? "notification" : noticeType === "2" ? "atme" : "", ids:id, diff --git a/src/forge/Settings/Setting.js b/src/forge/Settings/Setting.js index d6d3cdc60..deccb3daf 100644 --- a/src/forge/Settings/Setting.js +++ b/src/forge/Settings/Setting.js @@ -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"}, ] @@ -153,18 +153,22 @@ class Setting extends Component { name: values.project_name, description: values.project_description, private: private_check, + identifier:values.project_identifier, ...values, }).then((result) => { if (result) { this.props.showNotification(`仓库信息修改成功!`); - const { getDetail } = this.props; - getDetail && getDetail(); - this.setState({ - loading:false - }) + if(values.project_identifier !== projectsId){ + this.props.history.push(`/${owner}/${values.project_identifier}/settings`); + }else{ + const { getDetail } = this.props; + getDetail && getDetail(); + } } + this.setState({ + loading:false + }) }).catch((error) => { - console.log(error); this.setState({ loading:false }) @@ -283,6 +287,20 @@ class Setting extends Component { )}
    + 项目标识 (项目url标识部分,更改项目标识将导致原仓库地址失效)} + > + {getFieldDecorator("project_identifier", { + rules: [ + { + required: true, + message: "请输入项目标识", + }, + ], + })( + + )} + {getFieldDecorator("project_description", { rules: [], diff --git a/src/forge/Team/List.jsx b/src/forge/Team/List.jsx index ea23ab079..48a19c227 100644 --- a/src/forge/Team/List.jsx +++ b/src/forge/Team/List.jsx @@ -19,7 +19,6 @@ function List(props){ const [ search , setSearch ] = useState(undefined); const [ page , setPage ] = useState(1); const [ sortBy , setSortBy ] = useState("updated_on"); - const [ sortDirection , setSortDirection ] = useState("asc"); const OIdentifier = props.match.params.OIdentifier; const organizeDetail = props.organizeDetail; @@ -37,7 +36,7 @@ function List(props){ params:{ search,page,limit, sort_by:sortBy, - sort_direction:sortDirection + sort_direction:"desc" } }).then(result=>{ if(result && result.data){ diff --git a/src/forge/Team/New.jsx b/src/forge/Team/New.jsx index 414a8d158..46e13c3e0 100644 --- a/src/forge/Team/New.jsx +++ b/src/forge/Team/New.jsx @@ -87,7 +87,7 @@ export default Form.create()( } ], )} diff --git a/src/forge/Team/Setting/TeamSettingCommon.jsx b/src/forge/Team/Setting/TeamSettingCommon.jsx index 499a00c20..e4f5cf7a6 100644 --- a/src/forge/Team/Setting/TeamSettingCommon.jsx +++ b/src/forge/Team/Setting/TeamSettingCommon.jsx @@ -122,7 +122,7 @@ export default Form.create()( validator:checkname } ], - ,true + ,true )} {helper( "组织名称:", diff --git a/src/forge/Team/Sub/SubDetail.jsx b/src/forge/Team/Sub/SubDetail.jsx index 8307a8b14..278fef07e 100644 --- a/src/forge/Team/Sub/SubDetail.jsx +++ b/src/forge/Team/Sub/SubDetail.jsx @@ -50,7 +50,7 @@ export default ((props)=>{ {detail && detail.organization && detail.organization.nickname} - {detail ? detail.name : "新建团队"} + {detail ? detail.nickname : "新建团队"}
    { detail && diff --git a/src/forge/Upload/Index.js b/src/forge/Upload/Index.js index 5b09ca071..713803aa3 100644 --- a/src/forge/Upload/Index.js +++ b/src/forge/Upload/Index.js @@ -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 { : {icon || } -

    拖动文件或点击此处上传

    +

    拖动文件或点击此处上传

    ) } diff --git a/src/forge/Upload/untitled b/src/forge/Upload/untitled deleted file mode 100644 index 2796e4d71..000000000 --- a/src/forge/Upload/untitled +++ /dev/null @@ -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, 才是创建成功,其余均为创建失败 - - diff --git a/src/forge/Version/New.jsx b/src/forge/Version/New.jsx deleted file mode 100644 index 0678a3457..000000000 --- a/src/forge/Version/New.jsx +++ /dev/null @@ -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 ( - - ); - }); - 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) => ( - - {label} - - {getFieldDecorator(name, { rules, validateFirst: true })(widget)} - - - ), - [] - ); - // 输入标签名 - function changeAuto(value){ - let l = tagList.filter(item=>item.name.indexOf(value) > -1); - setOptions(renderTagList(l)); - } - return ( -
    -
    -
    -

    {versionId?"编辑":"创建"}发行版

    -
    -
    - {helper( - "", - "tag_name", - [{ required: true, message: "请输入获取或选择一个标签" }], - - {options} - - )} - @ - {helper( - "", - "target_commitish", - [{ required: true, message: "请选择一个分支" }], - - )} -
    -

    - 选择一个已经存在的标签,或者在发布时新建一个标签 -

    -
    -
    - {helper( - "", - "name", - [{ required: true, message: "请输入发行版的标题" }], - - )} -
    -
    - -
    -
    - {helper( - "", - "prerelease", - [], - 这是一个预览版本 - )} -
    -
    - - } - size={100} - showNotification={showNotification} - /> - {versionId && attachment && attachment.length > 0 ? ( - - ) : ( - "" - )} -
    -

    - - -

    -
    -
    -
    -
    -

    标签命名建议

    -

    - 通常的做法是在版本名称前加上字母 v 前缀, v1.0 或者 v2.3.4。 -

    -

    - 如果标签不适合在生产环境下使用,请在版本名称后添加预发行版本。例如:v0.2-alpha - 或者 v5.9-beta.3。 -

    -
    -
    -

    语义化版本

    -

    - 如果你是第一次发布版本,我们强烈建议你阅读语义化版本。 -

    -
    -
    -

    附件大小说明

    -

    - 单个附件不能超过 100M(GVP 项目200M),每个仓库总附件不可超过 - 1G(推荐项目不可超过 5G;GVP 项目不可超过 - 20G)。附件总容量统计包括仓库附件和发行版附件。 -

    -
    -
    -
    - ); - } - ) -); diff --git a/src/forge/Version/version.css b/src/forge/Version/version.css deleted file mode 100644 index ddfbe7d64..000000000 --- a/src/forge/Version/version.css +++ /dev/null @@ -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; -} \ No newline at end of file diff --git a/src/forge/Version/version.js b/src/forge/Version/version.js deleted file mode 100644 index 5049b31d9..000000000 --- a/src/forge/Version/version.js +++ /dev/null @@ -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 ( -
    - - {item.draft} - {item.created_at} - - - {item.tag_name} - - -
    - - {item.name} - { - (isManager || isDeveloper) && type !==2 && - (编辑) - } - - - this.showBody(key,item.bodyshow)}> - {item.user_name}:发布了这个版本,并在发布后提交给{item.target_commitish} - - { - item.bodyshow && - } - -

    - TAR - ZIP -

    -
    -
    - ) - }) - ) - } else if (releases && releases.length === 0) { - return ( ) - } - } - - render() { - const { projectsId ,owner } = this.props.match.params; - const { data , releases , isSpin } = this.state; - const type = this.props.projectDetail && this.props.projectDetail.type; - return ( -
    -
    - 版本发布 - { - data && data.user_permission && type !== 2 ? - + 发布新版 - : '' - } -
    -
    -
    {this.renderList(releases)}
    -
    -
    - ) - } -} -export default version; \ No newline at end of file diff --git a/src/forge/comments/children_comments.js b/src/forge/comments/children_comments.js index 450a30f13..75330161a 100644 --- a/src/forge/comments/children_comments.js +++ b/src/forge/comments/children_comments.js @@ -17,6 +17,7 @@ class children_comments extends Component { page: 1, journal_spin: false, search_count: 0, + isSpin: false, }; } @@ -71,6 +72,9 @@ class children_comments extends Component { .then((result) => { if (result) { this.getChildrenJournals(); + // 删除回复后,如果需手动调用父组件查询评论列表的接口,以保持角标(评论数量)的一致(合并请求页面), + // 否则直接查顶级评论列表,否则只查询当前子评论列表(易修页面) + this.props.refreshCommentList && this.props.refreshCommentList(); } }) .catch((error) => { @@ -80,9 +84,15 @@ class children_comments extends Component { // 翻页 ChangePage = (page) => { - this.state.page = page; - this.state.isSpin = true; - this.getChildrenJournals(); + // this.state.page = page; + // this.state.isSpin = true; + // 使用回调的写法,这样在getChildrenJournals中使用的就是最新的state + this.setState({ + page, + isSpin: true + }, () => { + this.getChildrenJournals(); + }); }; commentCtx = (v) => { @@ -183,7 +193,7 @@ class children_comments extends Component { size="large" loading={isSpin} dataSource={journalsdata.issue_journals} - renderItem={(item) => {this.renderList(item)}} + renderItem={(item) => {this.renderList(item)}} /> {this.Paginations()}
    diff --git a/src/forge/comments/comments.js b/src/forge/comments/comments.js index c27bb12af..dca7581f2 100644 --- a/src/forge/comments/comments.js +++ b/src/forge/comments/comments.js @@ -35,6 +35,8 @@ class comments extends Component { componentDidMount = () => { this.getjournalslist(); + // 给父组件绑定,以使父组件可以使用组件内方法,用于切换tab时重新请求评论列表、合并请求完之后重新请求评论列表 + this.props.bindCommentRef && this.props.bindCommentRef(this); }; //添加评论 @@ -151,6 +153,8 @@ class comments extends Component { isSpin: false, fileList: undefined, }); + const { updateCommentsNum } = this.props; + updateCommentsNum && updateCommentsNum(result.data.journals_total_count); } }) .catch((error) => { @@ -372,7 +376,7 @@ class comments extends Component { const renderList = (item) => { return ( -
    +
    @@ -500,7 +505,7 @@ class comments extends Component { loading={isSpin} header="" dataSource={journalsdata.issue_journals} - renderItem={(item) => {renderList(item)}} + renderItem={(item) => {renderList(item)}} /> )} {this.Paginations()} @@ -558,7 +563,7 @@ class comments extends Component { header="" dataSource={journalsdata.issue_journals} renderItem={(item) => ( - {renderList(item)} + {renderList(item)} )} /> )} diff --git a/src/forge/common/util.js b/src/forge/common/util.js index 4f8f0bf32..1b35ea23b 100644 --- a/src/forge/common/util.js +++ b/src/forge/common/util.js @@ -6,3 +6,11 @@ export function truncateCommitId(str) { return str } } + +// 秒数转2021-9-29 01:01 +export function timeFormat(SecondsStr){ + const time = new Date(SecondsStr*1000); + const hour = time.getHours()<10?"0".concat(time.getHours()):time.getHours(); + const minutes = time.getMinutes()<10?"0".concat(time.getMinutes()):time.getMinutes(); + return time.getFullYear()+"-"+(time.getMonth()+1)+"-"+time.getDate()+" "+hour+":"+minutes; +} \ No newline at end of file diff --git a/src/forge/css/index.scss b/src/forge/css/index.scss index d9a5b071c..a19619d73 100644 --- a/src/forge/css/index.scss +++ b/src/forge/css/index.scss @@ -88,14 +88,26 @@ ul,ol,dl{ display: flex; flex-wrap: wrap; align-items: center; + &>span, & a:link, a:visited{ + color: #333; + } + &>span{ + cursor: default; + } } .commitDesc{ flex:1; - margin-left:20px; - font-size:16px; - color:#333; - line-height:26px; + line-height:20px; word-break: break-all; + width: 49rem; + overflow: hidden; + white-space: normal; + &:hover{ + text-decoration: underline; + & .markdown-body{ + color: #466AFF; + } + } } .normalBox{ @@ -143,7 +155,7 @@ form.ant-form{ } form{ .ant-row.ant-form-item{ - margin-bottom: 15px; + margin-bottom: 20px; } } @media screen and (max-width: 1000px){ @@ -285,4 +297,50 @@ form{ border-bottom: none; } } +} +.btn-83{ + width: 83px; + height: 32px; + line-height: 30px; + text-align: center; + background: #FAFBFC; + border: 1px solid #D0D0D0; + display: inline-block; + border-radius: 5px; + font-weight: 500; + color: #333333!important; + margin-right: 15px; + &:hover{ + background: #F3F4F6; + color: #333333!important; + } + &:active{ + background: #D0D0D0; + color: #333333!important; + } +} +.shadow:hover{ + background: #eeeff1; + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} +a.hover:hover{ + text-decoration: underline; +} +button.ant-btn-primary.btnblue{ + background-color:rgba(70, 106, 255, 1); + border-color:rgba(70, 106, 255, 1); + &:hover{ + background-color:rgba(70, 106, 255, 0.85); + border-color:rgba(70, 106, 255, 0.85); + } +} +button.btngrey{ + background-color:#FFFFFF; + border-color:#D0D0D0; + color: #666666; + &:hover,&:focus{ + border-color:rgba(153, 153, 153, 0.5); + color: #666666; + } } \ No newline at end of file diff --git a/src/forge/users/Material/Base.jsx b/src/forge/users/Material/Base.jsx index f9707ab0d..61a9d6f1c 100644 --- a/src/forge/users/Material/Base.jsx +++ b/src/forge/users/Material/Base.jsx @@ -11,7 +11,6 @@ export default Form.create()( const { getFieldDecorator, validateFields , setFieldsValue } = props && props.form; // const { username } = props && props.match && props.match.params; const { resetUserInfo , current_user } = props; - console.log(props); useEffect(()=>{ if(current_user && current_user.login){ diff --git a/src/index.css b/src/index.css index e58df61f0..4c75d804f 100644 --- a/src/index.css +++ b/src/index.css @@ -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 { diff --git a/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfpeopledata.js b/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfpeopledata.js index 4f1e6d813..d6df12c4e 100644 --- a/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfpeopledata.js +++ b/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfpeopledata.js @@ -53,8 +53,6 @@ class CompetitionContentspdfpeopledata extends Component { let url = `/users/accounts/${id}.json`; axios.get(url).then((result) => { if (result.data) { - console.log("GetuseridApi"); - console.log(result.data); this.setState({ userdata:result.data }) diff --git a/src/modules/courses/css/Courses.css b/src/modules/courses/css/Courses.css index 73d320ed7..0d550a5c0 100644 --- a/src/modules/courses/css/Courses.css +++ b/src/modules/courses/css/Courses.css @@ -298,7 +298,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket { .CodeMirror-scroll { overflow: scroll !important; margin-bottom: -30px; - margin-right: -30px; + margin-right: -30px!important; padding-bottom: 30px; height: 100%; outline: none; @@ -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; diff --git a/src/modules/courses/publicNav/nav.css b/src/modules/courses/publicNav/nav.css index b6d8c7aab..1d6edf785 100644 --- a/src/modules/courses/publicNav/nav.css +++ b/src/modules/courses/publicNav/nav.css @@ -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; diff --git a/src/modules/tpm/TPMIndex.css b/src/modules/tpm/TPMIndex.css index 859ddcf96..bdd6d36a8 100644 --- a/src/modules/tpm/TPMIndex.css +++ b/src/modules/tpm/TPMIndex.css @@ -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 { diff --git a/src/modules/tpm/TPMIndexHOC.js b/src/modules/tpm/TPMIndexHOC.js index bf64e69ba..40b6acc46 100644 --- a/src/modules/tpm/TPMIndexHOC.js +++ b/src/modules/tpm/TPMIndexHOC.js @@ -7,6 +7,7 @@ import './TPMIndex.css'; import LoginDialog from '../login/LoginDialog'; import EducoderAccount from '../../forge/Component/EducoderAccount'; import ProfileModal from '../../forge/Component/ProfileModal/Index'; +import SystemNotice from '../../forge/Component/NoticeModal/SystemNotice'; export function TPMIndexHOC(WrappedComponent) { return class II extends React.Component { @@ -27,7 +28,7 @@ export function TPMIndexHOC(WrappedComponent) { giteaVisible:false, email:undefined, completeProfile:false, - showCP:false + showCP:false, } } @@ -216,9 +217,8 @@ export function TPMIndexHOC(WrappedComponent) { }) } - render() { - let { isRender , current_user , giteaVisible , email , completeProfile , showCP , publicNav } = this.state; + let { isRender , current_user , giteaVisible , email , completeProfile , showCP , publicNav , mygetHelmetapi } = this.state; const common = { showLoginDialog: this.showLoginDialog, checkIfLogin: this.checkIfLogin, @@ -227,6 +227,11 @@ export function TPMIndexHOC(WrappedComponent) { }; return (
    +