Compare commits

..

No commits in common. "master" and "master" have entirely different histories.

332 changed files with 12410 additions and 22758 deletions

1190
.idea/workspace.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +0,0 @@
{
}

124
LICENSE
View File

@ -1,124 +0,0 @@
木兰宽松许可证, 第2版
2020年1月 http://license.coscl.org.cn/MulanPSL2
您对“软件”的复制、使用、修改及分发受木兰宽松许可证第2版“本许可证”的如下条款的约束
0. 定义
“软件” 是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
“贡献” 是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
“贡献者” 是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
“法人实体” 是指提交贡献的机构及其“关联实体”。
“关联实体” 是指对“本许可证”下的行为方而言控制、受控制或与其共同受控制的机构此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
1. 授予版权许可
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。
2. 授予专利许可
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。
3. 无商标许可
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可但您为满足第4条规定的声明义务而必须使用除外。
4. 分发限制
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
5. 免责声明与责任限制
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。
6. 语言
“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。
条款结束
如何将木兰宽松许可证第2版应用到您的软件
如果您希望将木兰宽松许可证第2版应用到您的新软件为了方便接收者查阅建议您完成如下三步
1 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
2 请您在软件包的一级目录下创建以“LICENSE”为名的文件将整个许可证文本放入该文件中
3 请将如下声明文本放入每个源文件的头部注释中。
Copyright (c) [Year] [name of copyright holder]
[Software Name] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
Mulan Permissive Software LicenseVersion 2
Mulan Permissive Software LicenseVersion 2 (Mulan PSL v2)
January 2020 http://license.coscl.org.cn/MulanPSL2
Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions:
0. Definition
Software means the program and related documents which are licensed under this License and comprise all Contribution(s).
Contribution means the copyrightable work licensed by a particular Contributor under this License.
Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License.
Legal Entity means the entity making a Contribution and all its Affiliates.
Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, control means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity.
1. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not.
2. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.
3. No Trademark License
No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in section 4.
4. Distribution Restriction
You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software.
5. Disclaimer of Warranty and Limitation of Liability
THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW ITS CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
6. Language
THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL.
END OF THE TERMS AND CONDITIONS
How to Apply the Mulan Permissive Software LicenseVersion 2 (Mulan PSL v2) to Your Software
To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps:
Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner;
Create a file named "LICENSE" which contains the whole context of this License in the first directory of your software package;
Attach the statement to the appropriate annotated syntax at the beginning of each source file.
Copyright (c) [Year] [name of copyright holder]
[Software Name] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.

View File

@ -19,8 +19,7 @@ const getClientEnvironment = require("./env");
let publicPath = "/react/build/";
const publicUrl = publicPath.slice(0, -1);
// const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false";
const shouldUseSourceMap = process.env.NODE_ENV !== "production";
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false";
const env = getClientEnvironment(publicPath);
// This is the production configuration.
@ -55,8 +54,7 @@ module.exports = {
},
bail: true,
mode: "production",
// devtool: false, //测试版
devtool: shouldUseSourceMap?'source-map':false,
devtool: false, //测试版
entry: [require.resolve("./polyfills"), paths.appIndexJs],
output: {
path: paths.appBuild,

9906
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "forge",
"version": "3.0.0",
"version": "0.1.0",
"private": true,
"dependencies": {
"@monaco-editor/react": "^2.3.0",
@ -14,7 +14,6 @@
"babel-jest": "20.0.3",
"babel-loader": "7.1.2",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-polyfill": "^6.26.0",
"babel-preset-react-app": "^3.1.1",
"babel-runtime": "6.26.0",
"bizcharts": "^3.5.8",
@ -22,17 +21,15 @@
"case-sensitive-paths-webpack-plugin": "2.1.1",
"chalk": "1.1.3",
"classnames": "^2.2.5",
"clipboard": "^2.0.8",
"clipboard": "^2.0.6",
"code-prettify": "^0.1.0",
"codemirror": "^5.53.0",
"connected-react-router": "4.4.1",
"cross-env": "^7.0.3",
"css-loader": "^3.5.2",
"dompurify": "^2.0.15",
"dotenv": "4.0.0",
"dotenv-expand": "4.2.0",
"echarts": "^4.9.0",
"echarts-wordcloud": "^2.0.0",
"echarts": "^4.7.0",
"editor.md": "^1.5.0",
"eslint": "4.10.0",
"eslint-config-react-app": "^2.1.0",
@ -49,7 +46,6 @@
"install": "^0.12.2",
"jest": "20.0.4",
"js-base64": "^2.5.2",
"js2wordcloud": "^1.1.12",
"katex": "^0.11.1",
"lodash": "^4.17.15",
"loglevel": "^1.6.8",
@ -66,7 +62,7 @@
"postcss-loader": "2.0.8",
"promise": "8.0.1",
"prop-types": "^15.6.1",
"qrcode.react": "^1.0.1",
"qrcode.react": "^1.0.0",
"qs": "^6.9.3",
"quill": "^1.3.7",
"quill-delta-to-html": "^0.11.0",
@ -96,7 +92,6 @@
"react-resizable": "^1.10.1",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"react-slick": "^0.28.1",
"react-split-pane": "^0.1.91",
"react-url-query": "^1.5.0",
"react-zmage": "^0.8.5-beta.31",
@ -104,11 +99,9 @@
"redux-thunk": "2.3.0",
"rsuite": "^4.3.4",
"sass-loader": "7.3.1",
"save-dev": "0.0.1-security",
"scroll-into-view": "^1.14.2",
"showdown": "^1.9.1",
"showdown-katex": "^0.8.0",
"slick-carousel": "^1.8.1",
"store": "^2.0.12",
"style-loader": "0.19.0",
"styled-components": "^4.4.1",
@ -124,8 +117,8 @@
},
"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": "cross-env NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js",
"build": "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",
"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",
@ -187,7 +180,7 @@
"eslintConfig": {
"extends": "react-app"
},
"proxy": "http://localhost:3001",
"proxy": "http://localhost:3000",
"port": "3007",
"devDependencies": {
"@babel/runtime": "7.0.0-beta.51",
@ -195,7 +188,6 @@
"babel-core": "^6.26.0",
"babel-plugin-import": "^1.13.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
@ -206,7 +198,6 @@
"node-sass": "^4.12.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"purgecss": "^2.1.2",
"react-json-view": "^1.21.3",
"reqwest": "^2.0.5",
"resize-observer-polyfill": "^1.5.1",
"terser-webpack-plugin": "^2.3.5",

View File

@ -38,6 +38,78 @@
box-sizing: border-box;
}
.head-nav ul#header-nav li {
float: left;
height: 60px;
line-height: 60px;
margin-right: 30px;
cursor: pointer;
position: relative;
font-size: 16px
}
.head-nav ul#header-nav li a {
display: block;
height: 100%;
width: 100%;
color: #fff
}
.head-nav ul#header-nav li a:hover {
color: #cccccc;
}
.head-nav ul#header-nav li:last-child {
margin-right: 0px
}
.head-nav ul#header-nav li.active a {
color: #459be5 !important;
}
.head-nav ul#header-nav li.active p {
color: #459be5 !important;
}
.head-nav ul#header-nav li p:hover {
color: #cccccc;
}
.head-nav ul#header-nav li p {
display: block;
height: 100%;
width: 100%;
color: #fff
}
.head-nav ul#header-nav li.active div ul li a {
color: #000 !important;
}
.head-nav ul#header-nav li.active div ul li a:hover {
color: #FFF !important;
}
.head-nav ul#header-nav li.active ul li a {
color: #000 !important;
}
.head-nav ul#header-nav li.active ul li a:hover {
color: #FFF !important;
}
.head-nav ul#header-nav li.active:after {
content: '';
position: absolute;
left: 0px;
top: auto;
bottom: 10px;
right: auto;
height: 2px;
width: 14px;
background-color: #459be5;
}
.nav-img {
position: absolute;
top: 2px;

View File

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

View File

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

View File

@ -1,4 +1,3 @@
@charset "utf-8";
/* 头部 */
.header {
width: 100%;
@ -1272,7 +1271,7 @@ html body {
font-size: 14px;
line-height: 2.0;
background: #fafafa;
font-family: "Microsoft YaHei", "SimSun";
font-family: "微软雅黑", "宋体";
color: #05101a;
height: 100%;
position: relative;
@ -1308,7 +1307,6 @@ td,
span {
margin: 0;
padding: 0;
margin-bottom: 0px!important;
}
table,
@ -1365,6 +1363,10 @@ a:visited {
color: #05101a;
}
a:hover {
color: #459be5;
}
ol,
ul,
li {
@ -1471,7 +1473,7 @@ a.edu-txt-w80,
/*隐藏*/
.none {
display: none!important;
display: none
}
.block {
@ -1520,15 +1522,7 @@ 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;
}
@ -1548,9 +1542,6 @@ a.edu-txt-w80,
.font-25 {
font-size: 25px !important;
}
.font-26 {
font-size: 26px !important;
}
.font-24 {
font-size: 24px !important;
@ -1572,9 +1563,6 @@ a.edu-txt-w80,
font-size: 36px !important;
}
.font-40 {
font-size: 40px !important;
}
.font-50 {
font-size: 50px !important;
}
@ -1760,20 +1748,12 @@ a.decoration {
margin-bottom: 10px;
}
.mb12 {
margin-bottom: 12px;
}
.mb13 {
margin-bottom: 13px;
}
.mb14 {
margin-bottom: 14px;
}
.mb15 {
margin-bottom: 15px!important;
margin-bottom: 15px;
}
.mb16 {
@ -2444,23 +2424,13 @@ input::-ms-clear {
.color-grey-c {
color: #ccc !important;
}
a.hoverLine:hover{
text-decoration: underline;
}
.color-grey-cd {
color: #cdcdcd !important;
}
.color-grey-d {
color: #ddd;
}
.color-grey-9 {
color: #999 !important;
}
a:hover{
color: #466AFF !important;
color: #999999 !important;
}
.color-grey-98 {
@ -2495,23 +2465,33 @@ a:hover{
a.color-grey-name:hover,
a.color-dark:hover,
a.color-grey-6:hover,
a.color-grey-3:hover,a.color-ooo:hover {
color: #2A61FF !important;
a.color-grey-3:hover {
color: #4cacff !important;
}
a.color-grey-9:hover,
a.color-grey-8:hover,
a.color-grey-c:hover {
color: #111C24 !important;
}
/*蓝色*/
.color-blue {
color: #2A61FF !important;
}
.color-blue-file {
color: #4598FA!important;
color: #4CACFF !important;
}
/* 绿色 */
.color-green-file{
color: #28BD6C;
}
/*主*/
.color-blue_4C {
color: #4CACFF !important;
}
a.color-blue:hover,
a.color-blue_4C:hover {
color: #459BE6 !important;
}
/*橙色*/
.color-orange {
@ -3429,7 +3409,7 @@ a.user_bluebg_btn {
}
.cdefault {
cursor: default!important;
cursor: default
}
@ -3604,6 +3584,42 @@ a.user_bluebg_btn {
margin-right: 5px;
}
/*-------------------个人主页:右侧提示区域--------------------------*/
.-task-sidebar {
position: fixed;
width: 40px;
height: 180px;
right: 0;
bottom: 80px;
z-index: 10;
}
.-task-sidebar div {
height: 40px;
line-height: 40px;
box-sizing: border-box;
width: 40px;
background: #4CACFF;
color: #fff;
font-size: 20px;
text-align: center;
margin-bottom: 5px;
border-radius: 4px;
}
.-task-sidebar div i {
color: #fff;
}
.-task-sidebar div i:hover {
color: #fff !important;
}
.gotop {
background-color: rgba(208, 207, 207, 0.5) !important;
padding: 0px !important;
}
/***** loading ******/
/*****载入中******/
@ -3928,21 +3944,11 @@ html>body #ajax-indicator {
max-height: 340px;
}/*头部导航条样式---2018-03-19--by-cs*/
.privateTag{
display: block;
padding:0px 6px;
border-radius: 12px;
border:1px solid #2FC25B;
height: 18px;
line-height: 18px;
font-size: 12px;
margin-left: 10px;
color: #2FC25B;
}
.head-nav {
text-align: center;
height: 70px;
box-sizing: border-box;
min-width: 780px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@ -3964,7 +3970,7 @@ html>body #ajax-indicator {
cursor: pointer;
position: relative;
font-size: 16px;
padding-right:40px;
padding:0px 20px;
}
.head-nav ul#header-nav li a {
@ -6706,9 +6712,3 @@ p{
top:4px;
color: #999;
}
.ant-input, .ant-input .ant-input-suffix{
background-color: #fff!important;
}
.has-error .ant-input{
background-color: #FEF1F0!important;
}

File diff suppressed because one or more lines are too long

BIN
public/css/iconfont.eot Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -5,916 +5,6 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "24656750",
"name": "文件",
"font_class": "wenjian7",
"unicode": "e8e0",
"unicode_decimal": 59616
},
{
"icon_id": "630094",
"name": "向右箭头",
"font_class": "xiangyoujiantou",
"unicode": "e8de",
"unicode_decimal": 59614
},
{
"icon_id": "630095",
"name": "向左箭头",
"font_class": "xiangzuojiantou",
"unicode": "e8df",
"unicode_decimal": 59615
},
{
"icon_id": "24600282",
"name": "浏览icon@2x",
"font_class": "a-liulanicon2x",
"unicode": "e8dd",
"unicode_decimal": 59613
},
{
"icon_id": "24567893",
"name": "文件icon",
"font_class": "wenjianicon",
"unicode": "e8dc",
"unicode_decimal": 59612
},
{
"icon_id": "24527422",
"name": "圆圈@2x",
"font_class": "a-yuanquan2x",
"unicode": "e8db",
"unicode_decimal": 59611
},
{
"icon_id": "24378423",
"name": "项目标签",
"font_class": "xiangmubiaoqian",
"unicode": "e8da",
"unicode_decimal": 59610
},
{
"icon_id": "24368060",
"name": "icon",
"font_class": "icon",
"unicode": "e8ce",
"unicode_decimal": 59598
},
{
"icon_id": "24368061",
"name": "tar",
"font_class": "tar",
"unicode": "e8cf",
"unicode_decimal": 59599
},
{
"icon_id": "24289113",
"name": "复制 (2)",
"font_class": "a-fuzhi2",
"unicode": "e8d0",
"unicode_decimal": 59600
},
{
"icon_id": "24289114",
"name": "附件",
"font_class": "fujian1",
"unicode": "e8d1",
"unicode_decimal": 59601
},
{
"icon_id": "24289115",
"name": "编 辑",
"font_class": "a-bianji1",
"unicode": "e8d2",
"unicode_decimal": 59602
},
{
"icon_id": "24289116",
"name": "版本icon",
"font_class": "banbenicon",
"unicode": "e8d3",
"unicode_decimal": 59603
},
{
"icon_id": "24289117",
"name": "删除icon",
"font_class": "shanchuicon2",
"unicode": "e8d4",
"unicode_decimal": 59604
},
{
"icon_id": "24289118",
"name": "垃圾桶_icon@3x",
"font_class": "a-lajitong_icon3x",
"unicode": "e8d5",
"unicode_decimal": 59605
},
{
"icon_id": "24289119",
"name": "下拉按钮",
"font_class": "xialaanniu2",
"unicode": "e8d6",
"unicode_decimal": 59606
},
{
"icon_id": "24289120",
"name": "下载-icon",
"font_class": "xiazai-icon",
"unicode": "e8d7",
"unicode_decimal": 59607
},
{
"icon_id": "24289121",
"name": "master_icon",
"font_class": "master_icon1",
"unicode": "e8d8",
"unicode_decimal": 59608
},
{
"icon_id": "24289122",
"name": "上传icon",
"font_class": "shangchuanicon",
"unicode": "e8d9",
"unicode_decimal": 59609
},
{
"icon_id": "24059956",
"name": "个人资料",
"font_class": "gerenziliao1",
"unicode": "e8c7",
"unicode_decimal": 59591
},
{
"icon_id": "24059409",
"name": "里程碑icon",
"font_class": "lichengbeiicon",
"unicode": "e885",
"unicode_decimal": 59525
},
{
"icon_id": "24059410",
"name": "仓库设置icon",
"font_class": "cangkushezhiicon",
"unicode": "e889",
"unicode_decimal": 59529
},
{
"icon_id": "24059411",
"name": "动态icon",
"font_class": "dongtaiicon",
"unicode": "e88a",
"unicode_decimal": 59530
},
{
"icon_id": "24059412",
"name": "工作流icon",
"font_class": "gongzuoliuicon",
"unicode": "e88b",
"unicode_decimal": 59531
},
{
"icon_id": "24059413",
"name": "易修icon",
"font_class": "yixiuicon1",
"unicode": "e89b",
"unicode_decimal": 59547
},
{
"icon_id": "24059414",
"name": "wiki icon",
"font_class": "a-wikiicon1",
"unicode": "e8c6",
"unicode_decimal": 59590
},
{
"icon_id": "24047186",
"name": "代码库icon",
"font_class": "daimakuicon1",
"unicode": "e8c5",
"unicode_decimal": 59589
},
{
"icon_id": "24047189",
"name": "我的通知",
"font_class": "wodetongzhi",
"unicode": "e8c8",
"unicode_decimal": 59592
},
{
"icon_id": "24047190",
"name": "通知管理",
"font_class": "tongzhiguanli",
"unicode": "e8c9",
"unicode_decimal": 59593
},
{
"icon_id": "24047191",
"name": "选中",
"font_class": "xuanzhong3",
"unicode": "e8ca",
"unicode_decimal": 59594
},
{
"icon_id": "24047192",
"name": "系统通知icon",
"font_class": "xitongtongzhiicon",
"unicode": "e8cb",
"unicode_decimal": 59595
},
{
"icon_id": "24047193",
"name": "消息",
"font_class": "xiaoxi2",
"unicode": "e8cc",
"unicode_decimal": 59596
},
{
"icon_id": "24047194",
"name": "ssh密钥",
"font_class": "sshmiyue",
"unicode": "e8cd",
"unicode_decimal": 59597
},
{
"icon_id": "24014152",
"name": "个人资料",
"font_class": "gerenziliao",
"unicode": "e8c4",
"unicode_decimal": 59588
},
{
"icon_id": "23655968",
"name": "新手指引",
"font_class": "xinshouzhiyin",
"unicode": "e8e4",
"unicode_decimal": 59620
},
{
"icon_id": "23655969",
"name": "新建项目",
"font_class": "xinjianxiangmu",
"unicode": "e8e6",
"unicode_decimal": 59622
},
{
"icon_id": "23658111",
"name": "加入课堂",
"font_class": "jiaruketang1",
"unicode": "e8e9",
"unicode_decimal": 59625
},
{
"icon_id": "23791639",
"name": "项目公告",
"font_class": "xiangmugonggao",
"unicode": "e8c2",
"unicode_decimal": 59586
},
{
"icon_id": "23791640",
"name": "成果",
"font_class": "chengguo",
"unicode": "e8c3",
"unicode_decimal": 59587
},
{
"icon_id": "23791410",
"name": "成交公告",
"font_class": "chengjiaogonggao",
"unicode": "e8c0",
"unicode_decimal": 59584
},
{
"icon_id": "23791411",
"name": "技术资产",
"font_class": "jishuzichan",
"unicode": "e8c1",
"unicode_decimal": 59585
},
{
"icon_id": "23790928",
"name": "废标公告",
"font_class": "feibiaogonggao",
"unicode": "e8bc",
"unicode_decimal": 59580
},
{
"icon_id": "23790929",
"name": "中标公告",
"font_class": "zhongbiaogonggao",
"unicode": "e8bd",
"unicode_decimal": 59581
},
{
"icon_id": "23790930",
"name": "更正公告",
"font_class": "gengzhenggonggao",
"unicode": "e8be",
"unicode_decimal": 59582
},
{
"icon_id": "23790931",
"name": "招标公告",
"font_class": "zhaobiaogonggao",
"unicode": "e8bf",
"unicode_decimal": 59583
},
{
"icon_id": "23732532",
"name": "文件",
"font_class": "wenjian6",
"unicode": "e8ba",
"unicode_decimal": 59578
},
{
"icon_id": "23732533",
"name": "文件夹",
"font_class": "wenjianjia4",
"unicode": "e8bb",
"unicode_decimal": 59579
},
{
"icon_id": "23642443",
"name": "取消关注",
"font_class": "quxiaoguanzhu",
"unicode": "e89a",
"unicode_decimal": 59546
},
{
"icon_id": "23642444",
"name": "点赞_icon",
"font_class": "dianzan_icon",
"unicode": "e8a2",
"unicode_decimal": 59554
},
{
"icon_id": "23639530",
"name": "文件",
"font_class": "wenjian5",
"unicode": "e896",
"unicode_decimal": 59542
},
{
"icon_id": "23639533",
"name": "文件夹",
"font_class": "wenjianjia3",
"unicode": "e8a9",
"unicode_decimal": 59561
},
{
"icon_id": "23639440",
"name": "复制icon",
"font_class": "fuzhiicon",
"unicode": "e886",
"unicode_decimal": 59526
},
{
"icon_id": "23639422",
"name": "主页-fill",
"font_class": "zhuye-fill",
"unicode": "e876",
"unicode_decimal": 59510
},
{
"icon_id": "23639423",
"name": "代码库icon",
"font_class": "daimakuicon",
"unicode": "e884",
"unicode_decimal": 59524
},
{
"icon_id": "23572260",
"name": "新建",
"font_class": "xinjian2",
"unicode": "e8b0",
"unicode_decimal": 59568
},
{
"icon_id": "23567674",
"name": "协议icon",
"font_class": "xieyiicon",
"unicode": "e870",
"unicode_decimal": 59504
},
{
"icon_id": "23567675",
"name": "内存icon",
"font_class": "neicunicon",
"unicode": "e891",
"unicode_decimal": 59537
},
{
"icon_id": "23567676",
"name": "自述文件_icon",
"font_class": "zishuwenjian_icon",
"unicode": "e8a6",
"unicode_decimal": 59558
},
{
"icon_id": "23472253",
"name": "标签icon",
"font_class": "biaoqianicon",
"unicode": "e882",
"unicode_decimal": 59522
},
{
"icon_id": "23472254",
"name": "编 辑",
"font_class": "a-bianji",
"unicode": "e883",
"unicode_decimal": 59523
},
{
"icon_id": "23472258",
"name": "链接icon",
"font_class": "lianjieicon",
"unicode": "e887",
"unicode_decimal": 59527
},
{
"icon_id": "23472259",
"name": "合并请求icon",
"font_class": "hebingqingqiuicon",
"unicode": "e888",
"unicode_decimal": 59528
},
{
"icon_id": "23472263",
"name": "默认点赞_icon",
"font_class": "morendianzan_icon",
"unicode": "e88e",
"unicode_decimal": 59534
},
{
"icon_id": "23472265",
"name": "目录icon",
"font_class": "muluicon",
"unicode": "e894",
"unicode_decimal": 59540
},
{
"icon_id": "23472267",
"name": "设 置",
"font_class": "a-shezhi",
"unicode": "e899",
"unicode_decimal": 59545
},
{
"icon_id": "23472269",
"name": "提交icon",
"font_class": "tijiaoicon",
"unicode": "e89e",
"unicode_decimal": 59550
},
{
"icon_id": "23472270",
"name": "默认关注_ICON",
"font_class": "morenguanzhu_ICON",
"unicode": "e89f",
"unicode_decimal": 59551
},
{
"icon_id": "23472272",
"name": "下拉按钮",
"font_class": "xialaanniu1",
"unicode": "e8a4",
"unicode_decimal": 59556
},
{
"icon_id": "23472276",
"name": "左滑icon",
"font_class": "zuohuaicon",
"unicode": "e8b5",
"unicode_decimal": 59573
},
{
"icon_id": "23472277",
"name": "master_icon",
"font_class": "master_icon",
"unicode": "e8b6",
"unicode_decimal": 59574
},
{
"icon_id": "23472278",
"name": "默认复刻_icon",
"font_class": "morenfuke_icon",
"unicode": "e8b7",
"unicode_decimal": 59575
},
{
"icon_id": "23472279",
"name": "wiki icon",
"font_class": "a-wikiicon",
"unicode": "e8b8",
"unicode_decimal": 59576
},
{
"icon_id": "23472280",
"name": "易修icon",
"font_class": "yixiuicon",
"unicode": "e8b9",
"unicode_decimal": 59577
},
{
"icon_id": "23436350",
"name": "缩放",
"font_class": "suofang",
"unicode": "e87f",
"unicode_decimal": 59519
},
{
"icon_id": "23436351",
"name": "放大icon",
"font_class": "fangdaicon",
"unicode": "e881",
"unicode_decimal": 59521
},
{
"icon_id": "23384231",
"name": "搜索_icon",
"font_class": "sousuo_icon1",
"unicode": "e873",
"unicode_decimal": 59507
},
{
"icon_id": "23384232",
"name": "欢迎_icon",
"font_class": "huanying_icon",
"unicode": "e878",
"unicode_decimal": 59512
},
{
"icon_id": "23384233",
"name": "文件夹",
"font_class": "wenjianjia2",
"unicode": "e879",
"unicode_decimal": 59513
},
{
"icon_id": "23384234",
"name": "删除icon",
"font_class": "shanchuicon1",
"unicode": "e87a",
"unicode_decimal": 59514
},
{
"icon_id": "23261798",
"name": "请求icon",
"font_class": "qingqiuicon",
"unicode": "e871",
"unicode_decimal": 59505
},
{
"icon_id": "23261799",
"name": "响应icon",
"font_class": "xiangyingicon",
"unicode": "e87c",
"unicode_decimal": 59516
},
{
"icon_id": "23144143",
"name": "多选选中",
"font_class": "duoxuanxuanzhong",
"unicode": "e88f",
"unicode_decimal": 59535
},
{
"icon_id": "23144144",
"name": "错误icon",
"font_class": "cuowuicon",
"unicode": "e890",
"unicode_decimal": 59536
},
{
"icon_id": "23144146",
"name": "成功icon",
"font_class": "chenggongicon",
"unicode": "e892",
"unicode_decimal": 59538
},
{
"icon_id": "23144147",
"name": "未选中响应icon",
"font_class": "weixuanzhongxiangyingicon",
"unicode": "e893",
"unicode_decimal": 59539
},
{
"icon_id": "23144149",
"name": "必填icon",
"font_class": "bitianicon",
"unicode": "e895",
"unicode_decimal": 59541
},
{
"icon_id": "23144151",
"name": "未选中项目标签icon",
"font_class": "weixuanzhongxiangmubiaoqianicon",
"unicode": "e897",
"unicode_decimal": 59543
},
{
"icon_id": "23144152",
"name": "列表icon",
"font_class": "liebiaoicon",
"unicode": "e898",
"unicode_decimal": 59544
},
{
"icon_id": "23144158",
"name": "协作者管理icon",
"font_class": "xiezuozheguanliicon",
"unicode": "e8a1",
"unicode_decimal": 59553
},
{
"icon_id": "23144160",
"name": "选中分支icon",
"font_class": "xuanzhongfenzhiicon",
"unicode": "e8a3",
"unicode_decimal": 59555
},
{
"icon_id": "23144162",
"name": "选中基本设置icon",
"font_class": "xuanzhongjibenshezhiicon",
"unicode": "e8a5",
"unicode_decimal": 59557
},
{
"icon_id": "23144165",
"name": "选中项目标签icon",
"font_class": "xuanzhongxiangmubiaoqianicon",
"unicode": "e8aa",
"unicode_decimal": 59562
},
{
"icon_id": "23144167",
"name": "选中webhook icon",
"font_class": "a-xuanzhongwebhookicon",
"unicode": "e8af",
"unicode_decimal": 59567
},
{
"icon_id": "23046290",
"name": "shanchu_tc_icon",
"font_class": "shanchu_tc_icon",
"unicode": "e88c",
"unicode_decimal": 59532
},
{
"icon_id": "23046293",
"name": "wiki_icon",
"font_class": "wiki_icon",
"unicode": "e88d",
"unicode_decimal": 59533
},
{
"icon_id": "23046244",
"name": "导入模版_icon",
"font_class": "daorumoban_icon",
"unicode": "e86f",
"unicode_decimal": 59503
},
{
"icon_id": "23046252",
"name": "错误",
"font_class": "cuowu",
"unicode": "e872",
"unicode_decimal": 59506
},
{
"icon_id": "23046255",
"name": "更多_icon",
"font_class": "gengduo_icon",
"unicode": "e874",
"unicode_decimal": 59508
},
{
"icon_id": "23046258",
"name": "复层关闭_icon",
"font_class": "fucengguanbi_icon",
"unicode": "e875",
"unicode_decimal": 59509
},
{
"icon_id": "23046268",
"name": "删除icon",
"font_class": "shanchuicon",
"unicode": "e877",
"unicode_decimal": 59511
},
{
"icon_id": "23046273",
"name": "搜索_删除icon",
"font_class": "sousuo_shanchuicon",
"unicode": "e87b",
"unicode_decimal": 59515
},
{
"icon_id": "23046275",
"name": "搜索_icon",
"font_class": "sousuo_icon",
"unicode": "e87d",
"unicode_decimal": 59517
},
{
"icon_id": "23046276",
"name": "文档预览_icon",
"font_class": "wendangyulan_icon",
"unicode": "e87e",
"unicode_decimal": 59518
},
{
"icon_id": "23046278",
"name": "下拉按钮",
"font_class": "xialaanniu",
"unicode": "e880",
"unicode_decimal": 59520
},
{
"icon_id": "22906287",
"name": "二次确认_icon",
"font_class": "erciqueren_icon",
"unicode": "e867",
"unicode_decimal": 59495
},
{
"icon_id": "22906288",
"name": "选中ssh_icon",
"font_class": "xuanzhongssh_icon",
"unicode": "e868",
"unicode_decimal": 59496
},
{
"icon_id": "22906289",
"name": "未选中安全设置_icon",
"font_class": "weixuanzhonganquanshezhi_icon",
"unicode": "e869",
"unicode_decimal": 59497
},
{
"icon_id": "22906290",
"name": "未选中ssh_icon",
"font_class": "weixuanzhongssh_icon",
"unicode": "e86a",
"unicode_decimal": 59498
},
{
"icon_id": "22906291",
"name": "选中安全设置_icon",
"font_class": "xuanzhonganquanshezhi_icon",
"unicode": "e86b",
"unicode_decimal": 59499
},
{
"icon_id": "22906292",
"name": "删除_icon",
"font_class": "shanchu_icon",
"unicode": "e86c",
"unicode_decimal": 59500
},
{
"icon_id": "22906293",
"name": "列表ssh_icon",
"font_class": "liebiaossh_icon",
"unicode": "e86e",
"unicode_decimal": 59502
},
{
"icon_id": "17575494",
"name": "file-submodule",
"font_class": "file-submodule",
"unicode": "e866",
"unicode_decimal": 59494
},
{
"icon_id": "7539612",
"name": "nv",
"font_class": "nv1",
"unicode": "e864",
"unicode_decimal": 59492
},
{
"icon_id": "7539613",
"name": "nan",
"font_class": "nan1",
"unicode": "e865",
"unicode_decimal": 59493
},
{
"icon_id": "21936935",
"name": "邮箱",
"font_class": "youxiang",
"unicode": "e8b2",
"unicode_decimal": 59570
},
{
"icon_id": "21936924",
"name": "单位",
"font_class": "danwei",
"unicode": "e8a7",
"unicode_decimal": 59559
},
{
"icon_id": "21936925",
"name": "待办事项",
"font_class": "daibanshixiang",
"unicode": "e8a8",
"unicode_decimal": 59560
},
{
"icon_id": "21936928",
"name": "概览",
"font_class": "gailan",
"unicode": "e8ab",
"unicode_decimal": 59563
},
{
"icon_id": "21936929",
"name": "男",
"font_class": "nan",
"unicode": "e8ac",
"unicode_decimal": 59564
},
{
"icon_id": "21936930",
"name": "女",
"font_class": "nv",
"unicode": "e8ad",
"unicode_decimal": 59565
},
{
"icon_id": "21936931",
"name": "工作流",
"font_class": "gongzuoliu1",
"unicode": "e8ae",
"unicode_decimal": 59566
},
{
"icon_id": "21936934",
"name": "数据统计",
"font_class": "shujutongji",
"unicode": "e8b1",
"unicode_decimal": 59569
},
{
"icon_id": "21936936",
"name": "项目",
"font_class": "xiangmu",
"unicode": "e8b3",
"unicode_decimal": 59571
},
{
"icon_id": "21936937",
"name": "组织",
"font_class": "zuzhi",
"unicode": "e8b4",
"unicode_decimal": 59572
},
{
"icon_id": "14835599",
"name": "右箭头",
"font_class": "arrowRight",
"unicode": "e863",
"unicode_decimal": 59491
},
{
"icon_id": "21151489",
"name": "箭头镂空-左",
"font_class": "jiantouloukong-zuo",
"unicode": "e861",
"unicode_decimal": 59489
},
{
"icon_id": "21151557",
"name": "箭头镂空-右",
"font_class": "jiantouloukong-you",
"unicode": "e862",
"unicode_decimal": 59490
},
{
"icon_id": "21568989",
"name": "分享",
"font_class": "fenxiang1",
"unicode": "e89c",
"unicode_decimal": 59548
},
{
"icon_id": "21568990",
"name": "回到顶部",
"font_class": "huidaodingbu1",
"unicode": "e89d",
"unicode_decimal": 59549
},
{
"icon_id": "21568993",
"name": "帮助",
"font_class": "bangzhu",
"unicode": "e8a0",
"unicode_decimal": 59552
},
{
"icon_id": "991344",
"name": "提交",
@ -5146,7 +4236,7 @@
{
"icon_id": "1004630",
"name": "点赞2",
"font_class": "dianzaned",
"font_class": "dianzan1",
"unicode": "e639",
"unicode_decimal": 58937
},

1874
public/css/iconfont.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 733 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/favicon.ico Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="zh-CN" class="notranslate translated-ltr" translate="no">
<html lang="en">
<head>
<meta charset="utf-8">
<meta name=”Keywords” Content=”trustie,trustieforge,forge,确实让创建更美好,协同开发平台″>

View File

@ -3319,9 +3319,9 @@
text = text.replace(emailReg, function ($1, $2, $3, $4) {
return $1.replace(/@/g, "_#_&#64;_#_");
});
// " + editormd.urls.atLinkBase + "" + $2 + "
text = text.replace(atLinkReg, function ($1, $2) {
return "<span title=\"&#64;" + $2 + "\" class=\"at-link\"> " + $1 + " </span>";
return "<a href=\"" + editormd.urls.atLinkBase + "" + $2 + "\" title=\"&#64;" + $2 + "\" class=\"at-link\">" + $1 + "</a>";
}).replace(/_#_&#64;_#_/g, "@");
}

View File

@ -60,13 +60,12 @@ body {
.ant-progress-textno {
color: #f5222d;
}
.CodeMirror pre.CodeMirror-line{
font-size: 16px!important;
}
/* md多空格 */
.markdown-body p {
margin:10px 0px!important;
font-size: 16px !important;
line-height: 2 !important;
white-space: pre-wrap;
}
@ -88,10 +87,6 @@ body {
border-left: 1px solid rgb(221, 221, 221);
/* 某些情况下被cm盖住了 */
z-index: 99;
padding:8px 8px 50px;
}
.editormd-preview .markdown-body{
padding:0px !important;
}
/* 图片点击放大的场景,隐藏图片链接 */

View File

@ -3,7 +3,7 @@ import './App.css';
import { ConfigProvider } from 'antd'
import zhCN from 'antd/lib/locale-provider/zh_CN';
import {
// BrowserRouter as Router,
BrowserRouter as Router,
Route,
Switch
} from 'react-router-dom';
@ -17,9 +17,10 @@ import marked from './common/marked';
import moment from 'moment'
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
import SiderBar from './forge/Component/SiderBar'
import { SnackbarHOC } from 'educoder';
import history from './history';
import { SnackbarHOC } from 'educoder'
import { initAxiosInterceptors } from './AppConfig'
import { Provider } from 'react-redux';
import configureStore from './redux/stores/configureStore';
@ -39,16 +40,6 @@ const Projects = Loadable({
loader: () => import('./forge/Index'),
loading: Loading,
})
// forge项目详情
const ProjectDetail = Loadable({
loader: () => import("./forge/Main/DetailAdaptor"),
loading: Loading,
});
//forge安全设置
const Security = Loadable({
loader: () => import('./forge/SecuritySetting/Index'),
loading: Loading,
})
//forge项目-devOps详情
const OpsDetail = Loadable({
loader: () => import('./forge/DevOps/opsDetail'),
@ -83,27 +74,6 @@ const EducoderLogin = Loadable({
loader: () => import('./modules/login/EducoderLogin'),
loading: Loading,
})
const Search = Loadable({
loader: () => import('./modules/search/'),
loading: Loading,
})
const WikiPreview = Loadable({
loader: () => import('./forge/Wiki/Preview'),
loading: Loading,
})
const ProjectIndex = Loadable({
loader: () => import("./forge/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"];
class App extends Component {
constructor(props) {
@ -114,51 +84,6 @@ class App extends Component {
mydisplay: false,
occupation: 0,
mygetHelmetapi: null,
pathType: null,
pathName: null,
}
}
UNSAFE_componentWillMount() {
initAxiosInterceptors(this.props);
let pathname = window.location.pathname ? window.location.pathname.split('/')[1] : '';
pathname && this.getPathnameType(pathname);
// 添加路由监听,决定组织还是个人
this.unlisten = this.props.history.listen((location) => {
let newPathname = location.pathname.split('/')[1];
if (this.state.pathName !== newPathname) {
// this.setState({ pathType: '' });
newPathname && this.getPathnameType(newPathname);
}
});
}
shouldComponentUpdate(nextProps, nextState) {
// (!keyWord.includes(this.props.location.pathname.split('/')[1])) &&
if (nextProps.location.pathname.split('/')[1] !== this.props.location.pathname.split('/')[1] && nextState.pathType === this.state.pathType) {
return false;
} else {
return true;
}
}
getPathnameType = (pathname) => {
if (!keyWord.includes(pathname)) {
let url = `/owners/${pathname}.json`;
axios.get(url).then((response) => {
if (response && response.status === 200) {
this.setState({
pathType: response.data.type || '404',
pathName: pathname,
})
}
});
}else{
this.setState({
pathType: pathname,
pathName: pathname,
});
}
}
@ -175,22 +100,43 @@ class App extends Component {
Addcoursestypes: false
})
};
ModalCancelsy = () => {
this.setState({
mydisplay: false,
})
window.location.href = "/";
};
ModalshowCancelsy = () => {
this.setState({
mydisplay: true,
})
};
disableVideoContextMenu = () => {
window.$("body").on("mousedown", "video", function (event) {
if (event.which === 3) {
window.$('video').bind('contextmenu', function () { return false; });
} else {
window.$('video').unbind('contextmenu');
}
});
}
componentDidMount() {
document.title = "loading...";
this.disableVideoContextMenu();
history.listen(() => {
this.forceUpdate()
const $ = window.$
$("html").animate({ scrollTop: $('html').scrollTop() - 0 })
});
initAxiosInterceptors(this.props);
this.getAppdata();
window.addEventListener('error', (event) => {
const msg = `${event.type}: ${event.message}`;
});
}
componentWillUnmount() {
this.unlisten && this.unlisten(); // 执行解绑
}
//修改登录方法
Modifyloginvalue = () => {
this.setState({
@ -261,48 +207,31 @@ class App extends Component {
};
render() {
const { mygetHelmetapi, pathType} = this.state;
let personal = mygetHelmetapi && mygetHelmetapi.personal;
return (
<Provider store={store}>
<ConfigProvider locale={zhCN}>
<MuiThemeProvider theme={theme}>
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
<SiderBar />
{/* <Router> */}
<Router>
<Switch>
{/* wiki预览 */}
<Route path="/:owner/:projectsId/wiki/preview/:projectName/:projectId" render={
(props) => {
return (<WikiPreview {...this.props} {...props} {...this.state} />)
}
} />
{/* 项目PR */}
<Route path="/:owner/:projectsId/compare"
render={
(props) => (<ProjectDetail {...this.props} {...props} {...this.state} />)
}
></Route>
{/*项目*/}
<Route
path={"/:owner/:projectId/devops/:opsId/detail"}
path={"/projects/:owner/:projectId/devops/:opsId/detail"}
render={
(props) => {
return (<OpsDetail {...this.props} {...props} {...this.state} />)
}
}>
</Route>
{/*项目*/}
<Route
path={"/settings"}
path={"/projects"}
render={
(props) => {
return (<Security {...this.props} {...props} {...this.state} />)
return (<Projects {...this.props} {...props} {...this.state} />)
}
}>
</Route>
<Route
path="/register"
render={
@ -315,23 +244,6 @@ class App extends Component {
<Route path="/403" component={Shixunauthority} />
<Route path="/500" component={http500} />
{/*404*/}
<Route path="/nopage" component={Shixunnopage} />
{/* 查询 */}
<Route path="/search" component={Search} />
<Route exact path="/explore"
render={
(props) => (
<ProjectIndex {...this.props} {...props} />
)
}
/>
{/* 组织 */}
<Route path={"/organize"}
render={
(props) => {
@ -339,61 +251,25 @@ class App extends Component {
}
}>
</Route>
{/*新建项目等*/}
<Route
path={"/projects"}
render={
(props) => {
return (<Projects {...this.props} {...props} {...this.state} />)
}
}>
</Route>
{/* 判断为用户/组织,并进入对应页面 */}
{
pathType === 'User' ?
<Route exact path="/:username"
render={
(props) => {
return (<InfosIndex {...this.props} {...this.state} />)
}
}
/> : pathType === 'Organization' ? <Route path={"/:OIdentifier"}
render={
(props) => {
return (<OrganizeIndex {...props} {...this.props} {...this.state} />)
}
}>
</Route> : pathType === '404' ? <Route component={Shixunnopage} />:
<Route exact path="/"
render={
(props) => (
personal && personal.length > 0 ?
<InfosIndex {...this.props} {...props} />
:
<ProjectIndex {...this.props} {...props} />
)
}
/>
// <Route path="/" component={Loading} />
// <Route path="/" component={Shixunnopage} />
}
{/*404*/}
<Route path="/nopage" component={Shixunnopage} />
{/* 个人主页 */}
<Route path="/:username"
<Route path="/users/:username"
render={
(props) => {
return (<InfosIndex {...this.props} {...this.state} />)
}
}></Route>
<Route exact path="/"
render={
(props) => (
<Projects {...this.props} {...props} {...this.state}></Projects>
)
}
/>
<Route component={Shixunnopage} />
</Switch>
{/* </Router> */}
</Router>
</MuiThemeProvider>
</ConfigProvider>
</Provider>

View File

@ -85,11 +85,8 @@ export function initAxiosInterceptors(props) {
}
if (response.data.status === 404) {
let responseURL = response.request ? response.request.responseURL:'';
if (responseURL.indexOf('/api/users/') === -1 && responseURL.indexOf('/api/organizations/') === -1 ) {
locationurl('/nopage');
}
}
if (response.data.status === 500) {
locationurl('/500');

View File

@ -9,7 +9,20 @@ class Loading extends Component {
}
render() {
return ""
return (
<div className="App" style={{ minHeight: '800px', width: "100%" }}>
<style>
{
`
.margintop{
margin-top:20%;
}
`
}
</style>
<Spin size="large" className={"margintop"} />
</div>
);
}
}

View File

@ -195,7 +195,7 @@ class College extends Component {
align: 'center',
className: "edu-txt-center font-14 maxnamewidth105",
render: (text, record) => (
<a href={`/${record.login}`} title={record.name} target="_blank" className="task-hide maxnamewidth105" style={{
<a href={`/users/${record.login}`} title={record.name} target="_blank" className="task-hide maxnamewidth105" style={{
color:'#007bff',
}}> {

View File

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

View File

@ -1,5 +1,4 @@
import moment from "moment";
import { number } from "prop-types";
// 处理整点 半点
// 取传入时间往后的第一个半点
@ -98,41 +97,3 @@ export function formatDuring(mss){
}
return days + "天" + hours + "小时" + minutes + "分";
}
/*
返回多久以前
backDate以前的某个日期
*/
export function timeAgo(backDate) {
try {
moment(backDate);
} catch (e) {
return '刚刚';
}
if(typeof backDate ==='number'){
backDate=backDate*1000
}else{
backDate= moment(backDate);
}
let time = new Date() - backDate;
var days = Math.floor(time / (1000 * 60 * 60 * 24));
var hours = Math.floor((time % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
var minutes = Math.floor((time % (1000 * 60 * 60)) / (1000 * 60));
var seconds = Math.floor((time % (1000 * 60 * 60)) / 1000);
if (time <= 0) {
return "刚刚";
}
if (days) {
return days + "天前";
}
if (hours) {
return hours + "小时前";
}
if (minutes) {
return minutes + "分前";
}
if (seconds) {
return seconds + "秒前";
}
return "刚刚";
}

View File

@ -69,7 +69,7 @@ export function appendFileSizeToUploadFile(item) {
}
export function appendFileSizeToUploadFileAll(fileList) {
return fileList.map(item => {
if (item.name.indexOf(uploadNameSizeSeperator) === -1) {
if (item.name.indexOf(uploadNameSizeSeperator) == -1) {
return Object.assign({}, item, { name: `${item.name}${uploadNameSizeSeperator}${bytesToSize(item.size)}` })
}
return item

View File

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

View File

@ -3,7 +3,7 @@
// export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil';
export {
getUploadLogoActionUrl as getUploadLogoActionUrl,numFormat as numFormat,
getUploadLogoActionUrl as getUploadLogoActionUrl,
getImageUrl as getImageUrl,getImage as getImage, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode, getupload_git_file as getupload_git_file, getcdnImageUrl as getcdnImageUrl
@ -27,7 +27,7 @@ export {
markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension,
downloadFile, sortDirections, validateLength, mdJSONParse, exportMdtoHtml
} from './TextUtil'
export { handleDateString, getNextHalfHourOfMoment, formatDuring, formatSeconds ,timeAgo} from './DateUtil'
export { handleDateString, getNextHalfHourOfMoment, formatDuring, formatSeconds } from './DateUtil'
export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil'

View File

@ -46,18 +46,18 @@ export default ({
let id = decodeURIComponent(u.split("#")[1]);
let ele = document.getElementById(id);
if(ele){
window.scrollTo(0, ele.offsetTop + 120);
window.scrollTo(0, ele.offsetTop + 220);
}
}
}
},[url,html])
},[url])
const el = useRef();
function onAncherHandler(e) {
let target = e.target;
let target = e.target
if (target.tagName.toUpperCase() === 'A') {
let ancher = target.getAttribute('href');
if (ancher && ancher.startsWith('#')) {
let ancher = target.getAttribute('href')
if (ancher.startsWith('#')) {
e.preventDefault()
let viewEl = document.getElementById(ancher.replace('#', ''))
if (viewEl) {

View File

@ -435,11 +435,11 @@ class TPIContextProvider extends Component {
image_url: "avatars/User/1"
login: "innov"
name: "Coder"
user_url: "/innov"
user_url: "/users/innov"
*/
let user = resData.user;
user.username = resData.user.name;
user.user_url = `/${resData.user.login}`;
user.user_url = `/users/${resData.user.login}`;
// user.image_url = resData.image_url;
user.is_teacher = resData.is_teacher;
resData.user = user;

View File

@ -1,7 +1,7 @@
import React , { Component } from 'react';
import { Dropdown , Menu , Icon , Pagination , Spin } from 'antd';
import '../css/index.scss';
import '../Branch/branch.scss';
import '../Branch/branch.css';
import './activity.css';
import NoneData from '../Nodata';
@ -10,10 +10,6 @@ import ActivityItem from './ActivityItem';
import axios from 'axios';
const LIMIT = 15;
const ARRAY = [
{
id:"",
name:'全部'
},
{
id:1,
name:'1天'
@ -36,15 +32,10 @@ class Activity extends Component{
constructor(props){
super(props);
this.state={
time:undefined,
time:'30',
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,
@ -72,15 +63,8 @@ class Activity extends Component{
this.setState({
data:result.data,
project_trends:result.data.project_trends,
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,
isSpin:false
})
window.scrollTo(0,0);
}
}).catch(error=>{
console.log(error);
@ -90,19 +74,19 @@ class Activity extends Component{
// 切换周期
changeTime=(e)=>{
this.setState({
time:e.key ==="item_0"?undefined:e.key,
time:e.key,
isSpin:true
})
const { type,status,page } = this.state;
this.getInfo(e.key ==="item_0"?undefined:e.key,type,status,page);
this.getInfo(e.key,type,status,page);
}
//筛选
changeTrends=(type,status)=>{
this.setState({
type,status,page:1
type,status
})
const {time}=this.state;
this.getInfo(time,type,status,1);
const {time,page}=this.state;
this.getInfo(time,type,status,page);
}
// 分页
ChangePage=(page)=>{
@ -124,14 +108,12 @@ class Activity extends Component{
</Menu>
)
render(){
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:"全部"}];
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%";
const { time , data , page , project_trends , isSpin } = this.state;
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)+'%';
return(
<div className="main">
@ -140,7 +122,7 @@ class Activity extends Component{
<div className="orderInfo">
<div>
<div className="percentLine prPercent">
<p className="percent_purple" style={{width:first_per}}></p>
<p className="percent_purple" style={{width:'100%'}}></p>
<p className="percent_green resetStyle" style={{width:`${second_per}`}}></p>
</div>
<span>{data && data.pr_all_count}合并请求</span>
@ -150,25 +132,25 @@ class Activity extends Component{
<p className="percent_red" style={{width:`${third_per}`}}></p>
<p className="percent_green" style={{width:`${fourth_per}`}}></p>
</div>
<span>{data && data.issues_count}易修</span>
<span>{data && data.issues_count}任务</span>
</div>
</div>
<ul className="percentBox">
<li>
<span className="purple">{data && data.pr_count}</span>
<span className="change" onClick={()=>this.changeTrends("PullRequest","delay")}>已处理的合并请求</span>
<span className="change" onClick={()=>this.changeTrends("PullRequest","close")}>已处理的合并请求</span>
</li>
<li>
<span className="green">{data && data.new_pr_count}</span>
<span className="change" onClick={()=>this.changeTrends("PullRequest","not_delay")}>未处理的合并请求</span>
<span className="change" onClick={()=>this.changeTrends("PullRequest","create")}>未处理的合并请求</span>
</li>
<li>
<span className="red">{data && data.close_issues_count}</span>
<span className="change" onClick={()=>this.changeTrends("Issue","delay")}>已关闭的易修</span>
<span className="change" onClick={()=>this.changeTrends("Issue","close")}>已关闭的任务</span>
</li>
<li>
<span className="green">{data && data.open_issues_count}</span>
<span className="change" onClick={()=>this.changeTrends("Issue","not_delay")}>未处理的易修</span>
<span className="change" onClick={()=>this.changeTrends("Issue","create")}>未处理的任务</span>
</li>
</ul>
</div>

View File

@ -14,25 +14,25 @@ class ActivityItem extends Component {
{/* 如果是版本发布 */}
{item.trend_type === "VersionRelease" ?
<p className="itemLine">
<Link to={`/${owner}/${projectsId}/releases`} className="color-blue font-16">{item.name}</Link>
<Link to={`/projects/${owner}/${projectsId}/version`} className="color-blue font-16">{item.name}</Link>
<span className="activity_type">{item.trend_type}</span>
</p >
:
// 如果是任务
item.trend_type === "Issue" ?
<p className="itemLine">
<Link to={`/${owner}/${projectsId}/issues/${item.trend_id}`} className="color-blue font-16">{item.name}</Link>
<Link to={`/projects/${owner}/${projectsId}/issues/${item.trend_id}/detail`} className="color-blue font-16">{item.name}</Link>
<span className="activity_type">{item.trend_type}</span>
</p >
:
// 如果是合并请求
<p className="itemLine">
<Link to={`/${owner}/${projectsId}/pulls/${item.trend_id}`} className="color-blue font-16">{item.name}</Link>
<Link to={`/projects/${owner}/${projectsId}/pulls/${item.trend_id}/Messagecount`} className="color-blue font-16">{item.name}</Link>
<span className="activity_type">{item.trend_type}</span>
</p >
}
<p className="itemLine mt10">
<Link to={`/${item && item.user_login}`} className="show-user-link">
<Link to={`/users/${item && item.user_login}`} className="show-user-link">
<img alt="" src={getImageUrl(`/${item.user_avatar}`)} className="createImage" />
<span className="mr20">{item.user_name}</span>
</Link>

View File

@ -1,27 +1,39 @@
import React, { useState } from 'react';
import { Menu } from 'antd';
import "./branch.scss";
import CopyTool from '../Component/CopyTool';
import React, { Component } from 'react';
import { Dropdown, Icon, Tooltip } from 'antd';
import "./branch.css";
function CloneAddress({http_url , ssh_url , zip_url , tar_url}) {
const [ key , setKey ] = useState("HTTP");
class CloneAddress extends Component {
// 点击按钮复制功能
jsCopy = () => {
var e = document.getElementById("copy_rep_content");
e.select();
document.execCommand("Copy");
}
render() {
const { http_url, downloadUrl } = this.props;
return (
<div className="downMenu">
<div style={{borderBottom:"1px solid #eee"}}>
<Menu className="urlMenu" selectedKeys={[key]} mode={"horizontal"}>
<Menu.Item key="HTTP" onClick={(e)=>{setKey(e.key)}}>HTTP</Menu.Item>
<Menu.Item key="SSH" onClick={(e)=>{setKey(e.key)}}>SSH</Menu.Item>
</Menu>
<div className="gitAddressClone">
<input type="text" id="copy_rep_content" value={key==="HTTP" ? http_url:ssh_url} />
<CopyTool inputId="copy_rep_content" className="copytool"/>
</div>
</div>
<Menu className="edu-txt-center">
<Menu.Item><a href={zip_url}>下载 ZIP</a></Menu.Item>
<Menu.Item><a href={tar_url}>下载 TAR.GZ</a></Menu.Item>
</Menu>
{/* <p className="addressTips"><span>版本库地址已变更,请基于新地址提交代码</span></p> */}
{
http_url && <span>HTTP</span>
}
<input type="text" id="copy_rep_content" value={http_url} />
<Tooltip title="复制链接">
<span className="color-blue" onClick={() => this.jsCopy()}><i className="iconfont icon-fuzhi"></i></span>
</Tooltip>
{
downloadUrl &&
<span>
<Dropdown overlay={downloadUrl} trigger={['click']} placement="bottomRight">
<a className="ant-dropdown-link">
<Icon type="cloud-download" className="font-18 fl color-blue" />
</a>
</Dropdown>
</span>
}
</div>
)
}
}
export default CloneAddress;

View File

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

View File

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

View File

@ -0,0 +1,84 @@
.branchDropdown{
border:1px solid #eee;
border-radius: 4px;
display: flex;
justify-content: center;
height: 40px;
line-height: 40px;
min-width: 220px;
}
.branchDropdown .ant-dropdown-trigger{
width: 100%;
padding:0px 15px;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
}
.branchOptions{
width: 220px;
box-shadow: 0px 0px 3px 1px rgba(134, 134, 134, 0.4);
border-radius: 3px;
background: #fff;
max-height: 300px;
}
.OptionsUl{
max-height: 220px;
overflow-y: auto;
}
.OptionsUl li{
height: 35px;
line-height: 35px;
cursor: pointer;
padding:0px 10px;
}
.OptionsUl li:hover{
background-color: #F0F0F0;
}
.OptionsUl li a{
display: block;
}
.OptionsInput{
height: 32px;
padding-left: 4px;
line-height: 32px;
width: 100%;
}
.branch-tagBox{
border:1px solid #eee;
border-radius: 3px;
height: 40px;
display: flex;
align-items: center;
cursor: pointer;
min-width: 140px;
}
.branch-tagBox-list .ant-popover-arrow{
display: none;
}
.branch-tagBox-list.ant-popover.ant-popover-placement-bottom{
padding-top:0px;
}
.branch-tagBox .ant-dropdown-link{
display: block;
flex:1;
}
.branch-tagBox-list .ant-popover-inner-content{
padding:0px;
}
.navUl{
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 5px;
}
.navUl li{
cursor: pointer;
}
.navUl li.active{
color:#5091FF;
}
.listTips{
padding:20px 0px;
text-align: center;
}

View File

@ -1,129 +0,0 @@
.branchDropdown{
border:1px solid #eee;
border-radius: 4px;
display: flex;
justify-content: center;
height: 40px;
line-height: 40px;
min-width: 220px;
}
.branchDropdown .ant-dropdown-trigger{
width: 100%;
padding:0px 15px;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
}
.branchOptions{
width: 220px;
box-shadow: 0px 0px 3px 1px rgba(134, 134, 134, 0.4);
border-radius: 3px;
background: #fff;
max-height: 300px;
}
.OptionsUl{
min-height: 50px;
max-height: 220px;
overflow-y: auto;
}
.OptionsUl li{
height: 30px;
line-height: 30px;
cursor: pointer;
padding:0px 20px;
margin:5px 0px;
}
.OptionsUl li:hover{
background-color: #F0F0F0;
}
.OptionsUl li a{
display: block;
}
.OptionsInput{
height: 32px;
padding-left: 4px;
line-height: 32px;
width: 100%;
}
.branch-tagBox{
border:1px solid #D0D0D0;
border-radius: 3px;
height: 32px;
display: flex;
align-items: center;
cursor: pointer;
min-width: 104px;
}
.branch-tagBox:hover{
background-color: #F3F4F6;
}
.branch-tagBox-list{
background: #FFFFFF;
box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5);
border-radius: 4px;
.ant-popover-arrow{
display: none;
}
&.ant-popover.ant-popover-placement-bottom{
padding-top:0px;
}
.branch-tagBox .ant-dropdown-link{
display: block;
flex:1;
max-width: 105px;
}
.ant-popover-inner-content{
padding:0px;
}
}
.overlayBranch{
width: 325px;
.navUl{
margin-top: 8px;
height: 30px;
line-height: 30px;
li{
height: 30px;
line-height: 30px;
padding:0px 5px;
margin-left: 20px!important;
&.ant-menu-item-selected{
border-color:#466aff!important;
color:#466aff!important;
}
&.ant-menu-item-active{
border-color:transparent ;
}
}
}
}
.listTips{
padding:20px 0px;
text-align: center;
}
.urlMenu{
line-height: 30px;
margin-bottom: 10px;
padding:15px 20px 0px 20px;
border-bottom: none;
li.ant-menu-item{
height: 30px;
line-height: 30px;
padding:0px 5px;
margin-right: 20px!important;
&.ant-menu-item-selected,&.ant-menu-item-active{
color: #333;
}
&.ant-menu-item-selected{
border-color:#466aff!important;
}
&.ant-menu-item-active{
border-color:transparent ;
}
}
}
.copytool{
margin:0px 10px;
}

View File

@ -55,7 +55,6 @@ function AddGroup({organizeId,getGroupID}){
function addCollaborator(){
getGroupID && getGroupID(id);
setID(undefined);
}
return(

View File

@ -4,7 +4,7 @@ import axios from 'axios';
import { getImageUrl } from 'educoder';
const { Option } = AutoComplete;
function AddMember({getID,login,showNotification}){
function AddMember({getID,login}){
const [ id , setID ] = useState(undefined);
const [ source , setSource ] = useState(undefined);
const [ searchKey , setSearchKey ] = useState(undefined);
@ -45,7 +45,7 @@ function AddMember({getID,login,showNotification}){
src={getImageUrl(`/${item && item.image_url}`)}
alt=""
/>
<span className="ml10" style={{ verticalAlign: "middle" }}>
<span className="ml10" style={{ "vertical-align": "middle" }}>
{item.username}
<span className="color-grey ml10">({item.login})</span>
</span>
@ -66,12 +66,7 @@ function AddMember({getID,login,showNotification}){
};
function addCollaborator(){
if(source && source.length>0){
getID && getID(id);
setSearchKey(undefined);
}else{
showNotification("请选择存在的用户!");
}
}
return(

View File

@ -113,14 +113,7 @@ li.ant-menu-item{
z-index: 10000;
}
.laterest{
background-color: #EF3131;
color: #fff;
font-size: 12px;
margin-left: 10px;
padding:0px 5px;
border-radius: 2px;
height: 18px;
line-height: 18px;
color: #05690d;
}
@media screen and (max-width: 1800px){
@ -162,280 +155,41 @@ li.ant-menu-item{
margin:0px 20px!important;
}
}
.hoverA{
display:flex;
align-items: center;
max-width: 78px;
&:hover a{
color:#2A61FF !important ;
}
}
.menuPanels{
width: 295px;
.leftline{
position: relative;
color: #666;
height: 16px;
margin-left: 14px;
font-size: 12px;
&::before{
position: absolute;
left: -7px;
top:3px;
height: 12px;
width: 1px;
background-color: #999;
content: "";
}
}
.ant-btn{
height: 36px;
line-height: 34px;
width: 83px;
text-align: center;
padding:0px ;
font-weight: 500;
font-size: 14px;
&.currentBtn{
cursor: default;
color: #333;
&:hover{
color: #333;
border-color: #d0d0d0;
}
}
}
.ant-btn-default{
color: #333;
border-color: #d0d0d0;
&:hover{
background: #F3F4F6;
}
}
.ant-btn{
width: 102px;
height: 32px;
line-height: 30px;
}
.ant-btn-primary{
color: #fff;
background-color: #466AFF;
border:none;
&:hover{
background-color: rgba(70,106,255,0.85);
}
}
.focusPanelHeadInfo{
padding:14px 16px;
border-bottom: 1px solid #eee;
}
width: 240px;
height: 180px;
.ant-popover-content,.ant-popover-inner{
height: 100%;
width: 100%;
}
.ant-popover-inner-content{
padding:0px;
}
}
.halfs{
margin-top: 24px;
padding:24px 0px 0px 0px;
border-top: 1px solid #e8e8e8;
.attrPerson{
padding-bottom: 24px;
}
.aboutSubTitle{
display: flex;
align-items: center;
}
.menuMaininfos{
padding:10px 16px 14px;
border-bottom: 1px solid #eee;
}
.menuinfos{
padding:10px 20px 16px;
padding:15px 0px;
&>a{
display: flex;
flex-direction: column;
align-items: center;
border-right: 1px solid #eee;
flex: 1;
& >span:first-child{
font-size: 16px;
font-weight: 500;
font-size: 18px;
font-weight: 400;
color: #333;
line-height: 22px;
}
& >span:last-child{
color: #666;
font-weight: 400;
line-height: 20px;
margin-top: 6px;
}
&:last-child{
border-right: none;
}
}
}
/*-------------------个人主页:右侧提示区域--------------------------*/
.-task-sidebar {
position: fixed;
width: 40px;
right: 0;
bottom: 80px;
z-index: 10;
}
@media screen and (max-width: 1920px){
.-task-sidebar{
right:220px;
}
}
@media screen and (max-width: 1750px){
.-task-sidebar{
right:160px;
}
}
@media screen and (max-width: 1650px){
.-task-sidebar{
right:115px;
}
}
@media screen and (max-width: 1550px){
.-task-sidebar{
right:90px;
}
}
@media screen and (max-width: 1450px){
.-task-sidebar{
right:45px;
}
}
@media screen and (max-width: 1200px){
.-task-sidebar{
right:0px;
display: none;
}
}
.-task-sidebar>div {
height: 40px;
line-height: 40px;
box-sizing: border-box;
width: 40px;
color: #999;
font-size: 20px;
text-align: center;
margin-bottom: 20px;
border-radius: 50%;
background: #FFFFFF;
box-shadow: 0px 0px 10px 1px #F1F1F1;
}
.-task-sidebar>div i {
color: #999;
}
.-task-sidebar>div:hover i {
color: #fff !important;
}
.-task-sidebar>div:hover{
background: #1890FF;
box-shadow: 0px 0px 10px 2px #B6D0FC;
}
.helpBox{
width: 260px;
z-index: 103;
&.shareContent{
width: 200px;
}
.ant-popover-inner-content{
padding:0px;
}
p.titlecontent{
font-size: 18px;
color: #333;
line-height: 20px;
padding:15px 20px;
}
.faqUl{
padding:0px 20px 10px;
max-height: 230px;
overflow-y: auto;
li{
background: #F5F5F5;
border-radius: 20px;
padding:0px 20px;
color: #333;
height: 34px;
line-height: 34px;
margin-bottom: 10px;
a{
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
&:hover{
background-color: #D1E9FF;
a{
color: #333!important;
}
}
}
}
.shareUl{
padding:10px 0px;
display: flex;
align-items: center;
.titlecontent{
margin-right: 20px;
}
li > i{
font-size: 32px!important;
}
}
}
.-task-desc {
background: #494949;
width: 90px;
line-height: 36px;
text-align: center;
position: absolute;
color: #fff;
font-size: 13px;
z-index: 999999;
opacity: 0;
}
.-task-desc div {
position: absolute;
top: 10px;
right: -7px;
height: 13px;
}
.-task-desc div img {
float: left
}
.-task-sidebar .scan_ewm {
position: absolute !important;
right: 45px !important;
bottom: 0px !important;
background-color: #494949 !important;
-webkit-box-sizing: border-box !important;
box-sizing: border-box !important;
font-size: 14px !important;
line-height: 16px !important;
display: none;
height: 213px !important;
}
.trangle_right {
position: absolute;
right: -5px;
bottom: 15px;
width: 0;
height: 0px;
border-top: 6px solid transparent;
border-left: 5px solid #494949;
border-bottom: 6px solid transparent
}

View File

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

View File

@ -1,51 +0,0 @@
import React, { useState, useCallback, memo } from 'react';
import { Tooltip } from 'antd';
CopyTool.defaultProps = {
beforeText: '复制链接', //
afterText: '复制成功', //
className: '', //svgclass
inputId: 'copyText', //ID
timeOut:true, //beforeText
};
function CopyTool({ beforeText, afterText, className , inputId , timeOut }) {
const [title, setTitle] = useState(() => {
return beforeText;
});
//
const copyUrl = useCallback(() => {
const copyEle = document.querySelector(`#${inputId}`); //
if (!copyEle) {
console.error("您的CopyTool未设置正确的inputId");
return;
}
copyEle.select(); //
if (document.execCommand('copy')) {
document.execCommand('copy');
}
document.getSelection().removeAllRanges();
setTitle(afterText);
if(timeOut){
setTimeout(function(){
setTitle(beforeText);
},1500)
}
}, []);
return (
<Tooltip
placement="top"
title={title}
onVisibleChange={() => { setTitle(beforeText) }}
>
<i className={`iconfont icon-fuzhiicon ${className}`} style={{ color: '#466aff' }} onClick={copyUrl}></i>
</Tooltip>
);
}
export default memo(CopyTool);

View File

@ -1,33 +0,0 @@
import React from 'react';
import { AlignCenter } from '../layout';
import { Button } from 'antd';
import Modals from '../PublicModal/Index';
function DeleteBox({
visible ,
onCancel ,
onSuccess ,
title ,
subTitle,
content
}) {
return(
<Modals
title={title}
btn={
<div>
<Button size={'large'} onClick={onCancel}>取消</Button>
<Button type={"danger"} size={"large"} onClick={onSuccess}>确认删除</Button>
</div>
}
onCancel={onCancel}
visible={visible}
>
<div className="desc">
<AlignCenter className="descMain"><i className="iconfont icon-shanchu_tc_icon mr10"></i>{content}</AlignCenter>
<p>{subTitle}</p>
</div>
</Modals>
)
}
export default DeleteBox;

View File

@ -4,12 +4,6 @@ import './Component.scss';
import axios from 'axios';
const { TreeNode , DirectoryTree } = Tree;
function turnbar(str){
if(str && str.length>0 && str.indexOf("/")>-1){
return str.replaceAll('/','%2F');
}
return str;
}
function DrawerPanel({visible,onClose,branch,owner,projectsId,history, name , list}){
const [ treeData , setTreeData ] = useState(undefined);
const [ isSpin , setIsSpin ] = useState(true);
@ -77,8 +71,7 @@ function DrawerPanel({visible,onClose,branch,owner,projectsId,history, name , li
let dataref = event.node.props.dataRef;
if(dataref.type==="file"){
onClose();
let value = turnbar(branch);
history.push(`/${owner}/${projectsId}/tree/${value}/${dataref.path}`);
history.push(`/projects/${owner}/${projectsId}/tree/${branch}/${dataref.path}`);
}
}

View File

@ -1,6 +1,9 @@
.ant-modal-mask{
z-index: 1031;
z-index: 1001;
}
.ant-modal-wrap{
z-index: 1032;
z-index: 1002;
.ant-form-explain{
position: absolute;
}
}

View File

@ -1,41 +0,0 @@
import React, { useState } from "react";
import { Input ,notification} from "antd";
const { Search } = Input;
export default ({history}) => {
const [openSearch, setOpenSearch] = useState(false);
function onGlobalSearch(value) {
history.push('/search?value=' + value);
// window.location.href = `search?value=` + value;
// history.push({
// pathname:'/search',
// state:value
// })
}
return (
<React.Fragment>
{
openSearch ?
<div
onBlur={() => {
setTimeout(() => {
setOpenSearch(false)
}, 500)
}}
>
<Search placeholder="请输入搜索关键字"
className={`search-input mr20`}
onSearch={onGlobalSearch}
autoFocus={true}
style={{width:'260px'}}
/>
</div>
:
<i className="iconfont icon-sousuo font-18 color-grey-6 ml30" onClick={() => {
setOpenSearch(true)
}} />
}
</React.Fragment>
)
};

View File

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

View File

@ -45,15 +45,15 @@ const Div = styled.div`{
export default (({ user , img, name, time, focusStatus, is_current_user, login , successFunc }) => {
return (
<Div>
<Link to={`/${user && user.login}`}><Img src={getImageUrl(`/${img}`)} /></Link>
<Link to={`/users/${user && user.login}`}><Img src={getImageUrl(`/${img}`)} /></Link>
<div className="m-infos">
<Link to={`/${user && user.login}`}><Name>{name}</Name></Link>
<Link to={`/users/${user && user.login}`}><Name>{name}</Name></Link>
<Time><I className="iconfont icon-shijian"></I>加入时间:{time}</Time>
{
is_current_user ?
<Button type="default">当前用户</Button>
:
<FocusButton is_watch={focusStatus} id={login} successFunc={successFunc} notReset={true}/>
<FocusButton is_watch={focusStatus} id={login} successFunc={successFunc}/>
}
</div>
</Div>

View File

@ -1,125 +0,0 @@
/* eslint-disable react/jsx-no-duplicate-props */
import React, { useState } from 'react';
import * as ReactDOM from 'react-dom';
import { Modal, Button } from 'antd';
import './index.scss';
//
InitModal.defaultProps = {
okText: '确认', //
cancelText: '取消', //
className: '', //
inputId: 'copyText', //ID
onCancel:()=>{}, //
onOk:()=>{}, //
title:'提示', //
contentTitle:'', //
content:'', //
afterClose:()=>{}, //
};
// 使
export default function DelModal(props) {
renderModal({ ...props, type: 'delete' })
}
// 使
export function Confirm(props) {
renderModal({ ...props, type: 'confirm' })
}
function renderModal(props) {
const { type, afterClose } = props;
const div = document.createElement('div');
document.body.appendChild(div);
function destroy() {
afterClose && afterClose();
const unmountResult = ReactDOM.unmountComponentAtNode(div);
if (unmountResult && div.parentNode) {
div.parentNode.removeChild(div);
}
}
function modalType(type) {
if (type === 'delete') {
return <InitModal
title="删除"
contentTitle="确定要删除吗?"
okText="确认删除"
{...props}
afterClose={destroy}
contentTitle={<React.Fragment>
<i className="red-circle iconfont icon-shanchu_tc_icon mr3"></i>
{props.contentTitle}
</React.Fragment>}
/>
} else if (type === 'confirm') {
return <InitModal title="选择" afterClose={destroy} {...props} />
} else {
return <InitModal title="选择" afterClose={destroy} {...props} />
}
}
function render() {
setTimeout(() => {
ReactDOM.render(
modalType(type),
div,
);
});
}
render();
}
//
function InitModal({
onCancel,
onOk,
title,
contentTitle,
content,
okText,
cancelText,
afterClose,
className,
}) {
const [visible, setVisible] = useState(true);
function onCancelModal() {
setVisible(false);
onCancel && onCancel()
}
function onSuccess() {
setVisible(false);
onOk && onOk();
}
return (
<Modal
visible={visible}
onCancel={onCancelModal}
afterClose={afterClose}
title={title}
className={`myself-modal ${className}`}
centered
footer={[
<Button type="default" key="back" onClick={onCancelModal}>
{cancelText}
</Button>,
<Button className="foot-submit" key="submit" onClick={onSuccess}>
{okText}
</Button>,
]}
>
<div>
{contentTitle && <p className="content-title">{contentTitle}</p>}
<p className="content-descibe">{content}</p>
</div>
</Modal>
)
}

View File

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

View File

@ -1,62 +0,0 @@
import React, {useEffect, useRef, useState} from 'react';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
import './Component.scss';
function Monaco(props) {
const {
style = { // dom
height: '400px',
},
value = '', //
onChange = () => { //
},
fontSize = 14, //
monacoOptions = {
scrollBeyondLastLine: false,
lineNumbers: "off",
wordWrap: true,
overviewRulerBorder: true,
lineHeight: 24,
readOnly:true
}, // monaco
language = 'html', // js ts sql css json html
} = props;
const editOrRef = useRef();
const ThisEditor = useRef();
useEffect(() => {
ThisEditor.current = monaco.editor.create(editOrRef.current, {
value: value || '',
language,
theme: "vs-grey",
fontSize: fontSize + 'px',
minimap: { //
enabled: false,
},
...monacoOptions,
});
ThisEditor.current.onDidChangeModelContent((e) => {
let newValue = ThisEditor.current.getValue();
onChange(newValue);
});
return () => {
ThisEditor.current.dispose();
ThisEditor.current = undefined; //
}
}, []);
useEffect(() => {
if (ThisEditor.current) {
ThisEditor.current.updateOptions({
fontSize: fontSize + 'px',
})
}
}, [fontSize]);
return (
<div style={style} ref={editOrRef}>
</div>
);
}
export default Monaco;

View File

@ -1,90 +0,0 @@
.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;
}
}
}
}

View File

@ -1,76 +0,0 @@
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 (
<Modal
visible = {visible}
width="1000px"
footer={false}
title={false}
centered={true}
closable={false}
wrapClassName={'systemBox'}
>
<div className="sysBox">
<div className="sysnoticeBox">
<p className="ntitle">{system_notification && system_notification.subject}</p>
<p className="nSubtitle">{system_notification && system_notification.sub_subject}</p>
{/* <div className="nContent">
<div className="nMaindesc">
为了给用户提供更加稳定优质的服务我们即将对平台门户首页平台名称平台域名进行一次全面升级与变更原平台名称Trustie中文名确实将于2021年10月xx日统一更改为Gitlink中文名确实开源届时平台域名将统一进行更换更换规则如下
</div>
<div className="realmName">
<ul>
<li>原域名</li>
<li>官网顶级域名https://www.trustie.net</li>
<li>版本库子域名https://forgeplus.trustie.net</li>
<li>论坛子域名https://forum.trustie.net/forums</li>
</ul>
<ul>
<li>更换后域名</li>
<li>官网顶级域名https://www.gitlink.org.cn</li>
<li>版本库子域名https://www.git.gitlink.org.cn</li>
<li>论坛子域名https://forum.gitlink.org.cn</li>
</ul>
</div>
<div className="nSubdesc">
自2021年10月xx日起旧域名将停止访问因平台名称与域名变更给您带来的不便我们深表歉意!非常感谢您一直以来对本平台的信任与支持我们将一如既往地为您提供优质的服务 特此通知!
</div>
<div className="nInfo">
<p>Gitlink运营团队</p>
<p>2021年10月xx日</p>
</div>
</div> */}
<RenderHtml className="break_word_comments imageLayerParent" value={system_notification && system_notification.content} url={history.location}/>
<div className="nBtn">
<Button type="primary" className="btnblue" onClick={sureContinue}>确认并继续</Button>
</div>
</div>
</div>
</Modal>
)
}
export default SystemNotice;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

View File

@ -1,72 +0,0 @@
import React , { useEffect , useState } from 'react';
import Modals from '../PublicModal/Index';
import { Button } from 'antd';
import axios from 'axios';
import ProfileImg from './images/profile.png';
import './Index.scss';
function ProfileModal({visible,onCancel,history}) {
const [ modalVis , setModalVis ] = useState(visible);
const [ addMemberCheck , setAddMemberCheck ] = useState(false);
useEffect(()=>{
axios.interceptors.response.use((response) => {
if (response && (response.data.status === 411 || response.data.status === 412)) {
setModalVis(true);
if(response.data.status === 412){
setAddMemberCheck(true);
}
}
return response;
}, (error) => {
});
},[])
useEffect(()=>{
setModalVis(visible);
},[visible])
function onOk(){
onCancel();
setModalVis(false);
setTimeout(function(){
window.open(`/settings/profile`,"_blank");
},200)
}
function onNo() {
onCancel();
setModalVis(false);
}
return(
<Modals
title="完善资料"
onCancel={onNo}
visible={modalVis}
btn={
addMemberCheck?
<div>
<Button type={'primary'} size={"large"} onClick={onNo}>好的</Button>
</div>
:
<div>
<Button size={"large"} onClick={onNo}>暂不补充</Button>
<Button type={'primary'} size={"large"} onClick={onOk}>好的</Button>
</div>
}
>
<div className="contents">
<img src={ProfileImg} alt=""/>
{
addMemberCheck ?
<p>目标用户个人资料不完整需提醒目标用户补充资料后以进行后续操作</p>
:
<p>您目前的个人资料不完整需要补充资料以进行后续操作是否前往补充个人信息</p>
}
</div>
</Modals>
)
}
export default ProfileModal;

View File

@ -1,18 +0,0 @@
.contents{
display: flex;
align-items: center;
justify-content: center;
margin:10px auto 0px;
img{
margin-right: 13px;
width: 44px;
}
p{
line-height: 29px;
max-width: 327px;
font-size: 16px!important;
}
}
.font-44{
font-size: 44px!important;
}

View File

@ -1,17 +0,0 @@
import React from 'react';
function Profile({children,sureFunc,showCompeleteDialog , completeProfile, className}) {
function checkProfile() {
if(!completeProfile){
showCompeleteDialog && showCompeleteDialog();
}else{
sureFunc();
}
}
return(
<a className={className} onClick={checkProfile}>{children}</a>
)
}
export default Profile;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -1,20 +0,0 @@
import React from 'react';
import { Modal } from 'antd';
import './Index.scss';
function Modals({title,children,btn,onCancel,visible}) {
return(
<Modal
visible={visible}
onCancel={onCancel}
title={title}
width={"520px"}
footer={btn}
centered={true}
wrapClassName={"deleteBox"}
>
{children}
</Modal>
)
}
export default Modals;

View File

@ -1,75 +0,0 @@
.deleteBox{
z-index: 1033;
.ant-modal-close-x{
font-size: 17px!important;
}
.ant-modal-header{
background-color: #f8f8f8;
padding:10px 30px;
.ant-modal-title{
text-align: left;
font-size: 16px;
font-weight: bold;
}
}
.ant-modal-close{
top:0px !important;
font-size: 24px !important;
}
.ant-modal-body{
padding:30px 50px;
p{
font-size: 14px;
line-height: 26px;
color:#666;
word-break: break-all;
}
.desc{
.descMain{
align-items: center;
justify-content: center;
font-size: 20px;
margin-bottom: 10px;
i.red{
color:#DF0002;
}
}
}
}
.ant-modal-footer{
border-top: none;
text-align: center;
padding-bottom: 40px;
button,a{
width: 96px;
height: 32px;
margin:0px 20px;
font-weight: 400;
font-size: 14px;
&.ant-btn{
border-color: #D0D0D0;
color: #666;
&:hover,&:active,&:focus{
background: #f3f4f6;
}
}
&.ant-btn-danger{
background-color: #fff;
color: #DF0002;
border-color: #D0D0D0;
&:hover,&:active,&:focus{
border-color: #DF0002;
background-color: #fff;
}
}
&.ant-btn.ant-btn-primary{
background-color: #466AFF;
color: #fff;
border-color: #466AFF;
&:hover,&:focus,&:active{
background-color: rgba(70,106,255,0.85);
}
}
}
}
}

View File

@ -1,35 +1,38 @@
import React from 'react';
import { AlignTop } from '../Component/layout';
import { AlignCenter , AlignTop , FlexAJ } from '../Component/layout';
import { Link } from 'react-router-dom';
function Releases({ owner, projectsId, releaseVersions, distribution }) {
function Releases({owner,projectsId,releaseVersions}){
return(
<div>
<Link to={`/${owner}/${projectsId}/releases`} className="font-16 color-ooo hoverA">
<span>发行版</span>
<FlexAJ>
<AlignCenter><span className="font-16 color-grey-6">发行版</span>
{ releaseVersions && releaseVersions.total_count > 0 && <span className="infoCount">{releaseVersions.total_count}</span>}
</Link>
</AlignCenter>
{ releaseVersions && releaseVersions.total_count > 0 ?
<Link className="font-12 color-grey-9" to={`/projects/${owner}/${projectsId}/releases`}>全部</Link>
:
<Link className="font-12 color-blue" to={`/projects/${owner}/${projectsId}/releases/new`}>新建</Link>
}
</FlexAJ>
{
releaseVersions && releaseVersions.total_count>0 ?
releaseVersions.list.map((item,key)=>{
return(
key === 0 &&<AlignTop className="mt10">
<i className="iconfont icon-biaoqian3 color-grey-6 font-18 mr10"></i>
<div>
<p className="font-16 color-grey-6" style={{display:'flex',alignItems:'center'}}>
{/* 如果是点击最新则发行版列表页只展示最新的一个 */}
<Link to={{pathname:`/${owner}/${projectsId}/releases`,query:{turnFromNew:true}}} style={{maxWidth:'200px',overflow: 'hidden',whiteSpace: 'nowrap',textOverflow:'ellipsis'}}>{item.name}</Link>
<p className="font-16 color-grey-6">
<Link to={`/projects/${owner}/${projectsId}/releases`}>{item.name}</Link>
<span className="font-12 laterest ml5">最新</span>
</p>
<p className="color-grey-3 font-12">{item.created_at}</p>
<p className="color-grey-9 font-13">{item.created_at}</p>
</div>
</AlignTop>
)
})
:
<div className="mt8">
您暂未发布任何版本
{distribution && <Link className="color-blue ml20" to={{pathname:`/${owner}/${projectsId}/releases/new`,state:{stable:true}}}>创建新版本</Link>}
</div>
:""
}
</div>

View File

@ -1,91 +0,0 @@
import React, { useEffect, useState } from 'react';
import { Popover , Tooltip } from 'antd';
import './Component.scss';
import axios from 'axios';
import ShareModal from './SiderBarShareModal';
const $ = window.$;
$(window).scroll(function () {
if ($(".gotop").length > 0) {
if ($(document).scrollTop() > 0) {
$(".-task-sidebar .gotop").show();
$(".gotop").click(function () {
$("html,body").scrollTop(0);
});
}
if ($(document).scrollTop() === 0) {
$(".-task-sidebar .gotop").hide();
}
}
});
function SiderBar() {
const [ data , setData ] = useState([]);
const [ visible , setVisible ] = useState(false);
useEffect(()=>{
getFAQ();
},[])
function getFAQ(){
const url = `/faqs.json`;
axios.get(url).then(result=>{
if(result && result.data){
setData(result.data);
}
}).catch(error=>{})
}
function content(list){
return <div>
<p className="titlecontent">帮助</p>
<ul className="faqUl">
{
list && list.map((i,k)=>{
return(
<li key={i.question+k}><a href={`${i.url}`} title={i.question} target="_blank">{i.question}</a></li>
)
})
}
</ul>
</div>
}
function shareContent(){
return <div>
<ul className="shareUl">
<p className="titlecontent">分享到</p>
<li onClick={()=>setVisible(true)}><i className="iconfont icon-weixin2" style={{color:"#62b900"}}></i></li>
</ul>
</div>
}
return (
<div className={"-task-sidebar"} >
<ShareModal visible={visible} urlValue={window.location.href} onCancel={()=>setVisible(false)}/>
{
data && data.length > 0 && (data[0] && data[0].question) ?
<Popover content={content(data)} overlayClassName="helpBox" placement={"left"}>
<div className="feedback">
<i className="iconfont icon-bangzhu font-22"></i>
</div>
</Popover>
:""
}
{/* <div className="scan pr" title="">
<span className="inline erweima"><i className="iconfont icon-erweima color-white font-22 fl"></i></span>
</div>*/}
<Popover content={shareContent()} overlayClassName="helpBox shareContent" placement={"left"}>
<div className="consult">
<i className="iconfont icon-fenxiang1"></i>
</div>
</Popover>
<div className="gotop">
<Tooltip title="返回顶部" placement={"right"}>
<a><i className="iconfont icon-huidaodingbu1"></i></a>
</Tooltip>
</div>
</div>
)
}
export default SiderBar;

View File

@ -1,27 +0,0 @@
import React from 'react';
import { Modal } from 'antd';
import QRCode from 'qrcode.react';
function SiderBarShareModal({visible,urlValue,onCancel}) {
return(
<Modal
title={"分享到微信"}
visible={visible}
width="500px"
closable={true}
footer={false}
onCancel={onCancel}
>
<div style={{textAlign:"center"}}>
{urlValue &&<QRCode
value={urlValue}
size={200}
fgColor="#000000"
style={{margin:"20px"}}
/>}
<p>打开微信扫一扫,点击右上角菜单即可将网页分享至朋友圈</p>
</div>
</Modal>
)
}
export default SiderBarShareModal;

View File

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

View File

@ -5,7 +5,6 @@ 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{
@ -21,7 +20,7 @@ export default ({ url , name , column , id , login })=>{
`;
return(
id?
<Link to={`/${login}`}>
<Link to={`/users/${login}`}>
<Img>
{ url && <img src={url} alt=""/> }
<span>{name}</span>

View File

@ -28,11 +28,6 @@ export const AlignTop = styled.div`{
display:flex;
align-items: flex-start;
}`
export const AlignAJBottom = styled.div`{
display:flex;
justify-content: space-between;
align-items: flex-end;
}`
//
export const Box = styled.div`{
display:flex;

View File

@ -149,7 +149,7 @@ function About(props, ref) {
axios.post(url).then(result=>{
setIsSpining(false);
if(result && result.data.status === 0){
props.history.push(`/${owner}/${projectsId}/devops`);
props.history.push(`/projects/${owner}/${projectsId}/devops/dispose`);
// open_devops
let { changeOpenDevops } = props;
changeOpenDevops && changeOpenDevops(true);

View File

@ -96,7 +96,7 @@ function Dispose(props){
setVisible(false);
if(result && result.data){
props.showNotification("流水线新增成功,请进行工作流配置!");
props.history.push(`/${owner}/${projectsId}/devops/${result.data.id}`);
props.history.push(`/projects/${owner}/${projectsId}/devops/dispose/${result.data.id}`);
}else{
props.showNotification("流水线新增失败,请稍后再试!");
}
@ -134,12 +134,12 @@ function Dispose(props){
//
function toModalManage(){
props.history.push(`/${owner}/${projectsId}/devops/mould`);
props.history.push(`/projects/${owner}/${projectsId}/devops/mould`);
}
//
function toparameter(){
props.history.push(`/${owner}/${projectsId}/devops/params`);
props.history.push(`/projects/${owner}/${projectsId}/devops/params`);
}
const operate = current_user && (permission && permission !== "Reporter");

View File

@ -10,12 +10,6 @@ import { Link } from 'react-router-dom';
// killed:"",
// pending:""
// }
function turnbar(str){
if(str && str.length>0 && str.indexOf("/")>-1){
return str.replaceAll('/','%2F');
}
return str;
}
function renderTableStatus(status) {
switch (status) {
case "running":
@ -71,9 +65,8 @@ function List({ list, operate , projectsId , owner , showModal , deleteFunc }){
width:"15%",
ellipsis:true,
render:(value,item)=>{
let v = turnbar(item.branch);
return(
<Link to={`/${owner}/${projectsId}/tree/${v}/${value}`} className="color-blue">{value}</Link>
<Link to={`/projects/${owner}/${projectsId}/tree/${item.branch}/${value}`} className="color-blue">{value}</Link>
)
}
},
@ -117,7 +110,7 @@ function List({ list, operate , projectsId , owner , showModal , deleteFunc }){
return(
<span>
{ operate ?
<Link to={`/${owner}/${projectsId}/devops/${item.id}`} className="mr10 color-grey-6">
<Link to={`/projects/${owner}/${projectsId}/devops/dispose/${item.id}`} className="mr10 color-grey-6">
<i className="iconfont icon-zaibianji font-13 mr3"></i>编辑</Link> :""
}
{ operate ?
@ -125,7 +118,7 @@ function List({ list, operate , projectsId , owner , showModal , deleteFunc }){
<a className="mr10 color-grey-6"><i className="iconfont icon-lajitong font-13 mr3"></i>删除</a>
</Popconfirm>:""
}
<Link to={`/${owner}/${projectsId}/devops/list/${item.branch}`} className="color-grey-6"><i className="iconfont icon-yunhang font-13 mr3"></i>查看运行记录</Link>
<Link to={`/projects/${owner}/${projectsId}/devops/list/${item.branch}`} className="color-grey-6"><i className="iconfont icon-yunhang font-13 mr3"></i>查看运行记录</Link>
</span>
)
}

View File

@ -42,7 +42,7 @@ function PipelineName({visible,onCancel,onOk,value ,branchList}){
</div>
<div className="choosenList mt20">
<span>触发条件:</span>
<Select value={branchValue} style={{width:"150px"}} dropdownClassName="chooseCon" onChange={(e)=>setBranchValue(e)}>
<Select value={branchValue} style={{width:"150px"}} onChange={(e)=>setBranchValue(e)}>
{
branchList && branchList.length>0 && branchList.map((item,key)=>{
return(
@ -51,7 +51,7 @@ function PipelineName({visible,onCancel,onOk,value ,branchList}){
})
}
</Select>
<Select mode="multiple" allowClear value={eventValue} dropdownClassName="chooseCon" style={{width:"180px",marginLeft:"10px"}} onChange={(e)=>{setEventValue(e)}}>
<Select mode="multiple" allowClear value={eventValue} style={{width:"180px",marginLeft:"10px"}} onChange={(e)=>{console.log(e);setEventValue(e)}}>
{
EVENT.map((item,key)=>{
return(

View File

@ -36,37 +36,39 @@ export default ((props)=>{
return(
<WhiteBack className="opsPanel">
<Switch {...props}>
<Route path="/:owner/:projectsId/devops/params"
<Route path="/projects/:owner/:projectsId/devops/dispose/:disposeId"
render={
(p) => (<New {...props} {...p}/>)
}
></Route>
<Route path="/projects/:owner/:projectsId/devops/params"
render={
(p) => (<Params {...props} {...p}/>)
}
></Route>
<Route path="/:owner/:projectsId/devops/mould"
<Route path="/projects/:owner/:projectsId/devops/mould"
render={
(p) => (<Mould {...props} {...p}/>)
}
></Route>
<Route path="/:owner/:projectsId/devops/new"
<Route path="/projects/:owner/:projectsId/devops/dispose/new"
render={
(p) => (<New {...props} {...p}/>)
}
></Route>
<Route path="/:owner/:projectsId/devops/list/:branch"
<Route path="/projects/:owner/:projectsId/devops/dispose"
render={
(p) => (<Dispose {...props} {...p}/>)
}
></Route>
<Route path="/projects/:owner/:projectsId/devops/list/:branch"
render={
(p) => (<Stucture {...props} {...p}/>)
}
></Route>
<Route path="/:owner/:projectsId/devops/:disposeId"
<Route path="/projects/:owner/:projectsId/devops"
render={
(p) => (<New {...props} {...p}/>)
}
></Route>
{/* 原本的两种合为一个 */}
<Route path="/:owner/:projectsId/devops"
render={
(p) =>{return( p.location.state.open_devops?<Dispose {...props} {...p}/>:<About {...props} {...p}/>)}
(p) => (<About {...props} {...p}/>)
}
></Route>
</Switch>

View File

@ -26,7 +26,7 @@ export default ((props)=>{
return(
<div className="disposePanel">
<Banner>
{ permission !=="Reporter" && <Link to={`/${owner}/${props.match.params.projectsId}/devops`}>工作流配置</Link>}
{ permission !=="Reporter" && <Link to={`/projects/${owner}/${props.match.params.projectsId}/devops/dispose`}>工作流配置</Link>}
</Banner>
<Div>
<Dispost {...props}/>

View File

@ -104,7 +104,7 @@ function Params(props){
<Banner>
<FlexAJ>
<span className="font-18">工作流 - 参数管理</span>
<Link to={`/${owner}/${projectsId}/devops`} className="font-14 color-grey-9 ml20">返回</Link>
<Link to={`/projects/${owner}/${projectsId}/devops/dispose`} className="font-14 color-grey-9 ml20">返回</Link>
</FlexAJ>
</Banner>
<Div className="disposeList">

View File

@ -126,7 +126,7 @@ function Mould(props){
<div>
<New wrappedComponentRef={(f) => childRef.current = f} ref={childRef} visible={visible} onCancel={()=>setVisible(false)} onOk={onOk}></New>
<Banner>
<FlexAJ><span>工作流 - 模板管理</span><Link to={`/${owner}/${projectsId}/devops`} className="font-14 color-grey-9">返回</Link></FlexAJ>
<FlexAJ><span>工作流 - 模板管理</span><Link to={`/projects/${owner}/${projectsId}/devops/dispose`} className="font-14 color-grey-9">返回</Link></FlexAJ>
</Banner>
<Div className="disposeList">
<FlexAJ>

View File

@ -2,7 +2,7 @@ import React, { useState, useEffect , useImperativeHandle ,forwardRef } from "re
import { FlexAJ, AlignCenter , Banner } from "../Component/layout";
import { Table, Pagination, Popconfirm } from "antd";
import { truncateCommitId } from "../common/util";
import { getImageUrl } from 'educoder';
import {getUrl} from 'educoder';
import axios from "axios";
import { Link } from 'react-router-dom';
@ -198,7 +198,7 @@ function Structure(props,ref){
}
function clickRows(event,e){
props.history.push(`/${owner}/${projectsId}/devops/${e.number}/detail`);
props.history.push(`/projects/${owner}/${projectsId}/devops/${e.number}/detail`);
}
const column = [
{
@ -245,7 +245,7 @@ function Structure(props,ref){
{meg.sha && <span className="color-orange">{meg.sha}</span>}
</div>
<AlignCenter>
<img style={{borderRadius:"50%",marginRight:"10px",width:"25px",height:"25px"}} alt="" src={`${item.image_url && getImageUrl(`/${item.image_url}`)}`} />
<img style={{borderRadius:"50%",marginRight:"10px",width:"25px",height:"25px"}} alt="" src={`${item.image_url && getUrl(`/images/${item.image_url}`)}`} />
<div className="task-hide ml5" style={{ maxWidth: "300px" }}>
{meg.message}
</div>
@ -290,7 +290,7 @@ function Structure(props,ref){
<Banner>
<FlexAJ>
<span>构建列表</span>
<Link to={`/${owner}/${projectsId}/devops`} className="font-15 color-grey-9">返回</Link>
<Link to={`/projects/${owner}/${projectsId}/devops/dispose`} className="font-15 color-grey-9">返回</Link>
</FlexAJ>
</Banner>
<Div>

View File

@ -275,7 +275,7 @@ function disposePipeline(props){
...params
}).then(result=>{
if(result){
props.history.push(`/${owner}/${projectsId}/devops`);
props.history.push(`/projects/${owner}/${projectsId}/devops/dispose`);
}
setLoading(false);
}).catch(error=>{

View File

@ -391,9 +391,6 @@
}
}
}
.chooseCon.ant-select-dropdown{
z-index: 100001;
}
.choosenList{
display: flex;

View File

@ -48,7 +48,7 @@ export default (props) => {
axios.post(url).then((result) => {
if (result && result.data) {
props.showNotification("工作流正在重新构建!");
props.history.push(`/${owner}/${projectId}/devops/${result.data.number}/detail`);
props.history.push(`/projects/${owner}/${projectId}/devops/${result.data.number}/detail`);
}
})
.catch((error) => {
@ -87,7 +87,7 @@ export default (props) => {
</AlignCenter>
<Link
style={{ color: "#ddd" }}
to={`/${owner}/${projectId}/devops`}
to={`/projects/${owner}/${projectId}/devops/dispose`}
>
<i className="iconfont icon-yiguanbi font-15 mr5"></i>退出
</Link>

View File

@ -24,6 +24,7 @@ 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,
@ -138,10 +139,12 @@ 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);
};

View File

@ -41,15 +41,14 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
//
function onOk(){
validateFields((error,values)=>{
console.log(...values);
if(!error){
const url = `/${owner}/${repo}/applied_transfer_projects.json`;
Axios.post(url,{
...values
}).then(result=>{
if(result && result.data.id){
if(result){
onSuccess(result.data && result.data.owner);
}else{
onSuccess();
}
}).catch(error=>{})
}
@ -105,7 +104,7 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
</ul>
:
<ul className="descUl">
<li>仓库仅可以转移到您具有管理权限的组织中</li>
<li>仓库仅可以转移到您已经加入的组织中不可以转移到未加入的组织中</li>
<li>涉及到仓库改名操作请提前做好仓库备份并且在转移后对本地仓库的remote进行修改</li>
<li>转移仓库到组织后你和组织创建者/管理员同时拥有对该仓库的管理操作</li>
</ul>
@ -153,21 +152,20 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
</Form.Item>
}
<Form.Item label="仓库标识:" style={{marginBottom:"0px"}}>
<Form.Item label="仓库名称:">
{getFieldDecorator("identifier",
{
rules:[
{required:true,message:"请输入仓库标识!"},
{required:true,message:"请输入仓库名称"},
{
validator:checkIdentifier
}
]
}
)(
<Input placeholder="请输入仓库标识" autoComplete={"off"}/>
<Input placeholder="请输入仓库名称" autoComplete={"off"}/>
)}
</Form.Item>
<span className="color-grey-9" style={{marginLeft:"120px"}}>请输入当前项目的标识<span className="ml5 mr5 color-grey-3">{repo}</span>进行确认</span>
</Form>
</div>
</Modal>

View File

@ -1,85 +0,0 @@
import React, { useState , forwardRef, useEffect } from 'react';
import { Form , Modal , Input , Radio } from 'antd';
import Axios from 'axios';
import CheckProfile from '../Component/ProfileModal/Profile';
export default Form.create()(
forwardRef((props)=>{
const { getFieldDecorator, validateFields , setFieldsValue } = props && props.form;
const [ visible , setVisible ] = useState(false);
useEffect(()=>{
if(!visible){
setFieldsValue({
code:undefined,
role:"developer"
})
}
},[visible])
function onOk() {
validateFields((error,values)=>{
if(!error){
const url = `/applied_projects.json`;
Axios.post(url,{
applied_project:{
...values
}
}).then(result=>{
if(result && result.data){
setVisible(false);
props.showNotification("申请加入项目成功,等待审核!");
}
}).catch(error=>{})
}
})
}
function checkValue(rule, value, callback){
if(!value){
callback();
}
if(value.length < 6 || value.length > 6){
callback("请输入6位数的邀请码");
}
callback();
}
return(
<React.Fragment>
<Modal
title="加入项目"
width="480px"
visible={visible}
centered={true}
onOk={onOk}
onCancel={()=>setVisible(false)}
>
<Form layout={'inline'} className="inviteForm">
<Form.Item label="项目邀请码">
{getFieldDecorator("code",{
rules:[
{required:true,message:"请输入6位项目邀请码"},
{validator:checkValue}
]
})(
<Input placeholder="请输入6位项目邀请码" autoComplete={"off"} maxLength="6" style={{width:"300px"}}/>
)}
</Form.Item>
<Form.Item label="选择角色">
{getFieldDecorator("role",{
rules:[{required:true,message:"请选择角色"}]
})(
<Radio.Group defaultValue={"developer"}>
<Radio value="manager">管理员</Radio>
<Radio value="developer">开发者</Radio>
<Radio value="reporter">报告者</Radio>
</Radio.Group>
)}
</Form.Item>
</Form>
</Modal>
<CheckProfile {...props} sureFunc={()=>setVisible(true)}>加入项目</CheckProfile>
</React.Fragment>
)
})
)

View File

@ -1,108 +0,0 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Icon } from 'antd';
import _ from 'lodash';
import Nodata from '../Nodata';
class PullRefresh extends Component {
constructor(props) {
super(props);
this.state = {
}
this.pullRef = {};
//
this.onScrollList = _.throttle(this.handleScroll, 200, {
leading: false,
trailing: true,
});
}
componentDidMount() {
let dom = document.querySelector('.pull-refresh-wrap');
dom && dom.addEventListener('scroll', this.onScrollList);
}
componentWillUnmount() {
let dom = document.querySelector('.pull-refresh-wrap');
dom && dom.removeEventListener('scroll', this.onScrollList)
}
handleScroll = () => {
if (this.props.count < this.props.pageSize) return;
if (this.props.type === 1 || this.props.type === 2) return;
const wrap = this.pullRef;
const currentScroll = wrap.scrollTop + wrap.clientHeight
//
if (currentScroll >= (wrap.scrollHeight - 200)) {
this.loadData()
}
}
handleLoadClick = () => {
this.loadData();
}
loadData = () => {
this.props.onPullRefresh()
}
renderLoading() {
switch (this.props.type) {
case 0: //
return <div className='text-center' onClick={this.handleLoadClick}>显示更多</div>
case 1: //
return (
<div className='text-center'>
<Icon type="loading" />
<span className='text-center'>加载中...</span>
</div>
)
case 2: //
return <div className='text-center'>没有更多了</div>
default:
return <div className='text-center'>没有更多了</div>
}
}
render() {
const { className, count, children } = this.props;
return (
<div
className={`pull-refresh-wrap ${className}`}
ref={dom => { this.pullRef = dom }}
>
{children}
{
count < 1 && <Nodata _html="暂无未读消息"/>
}
{/* 大于分页数据才显示loading */}
{/* {this.props.count >= this.props.pageSize ? this.renderLoading() : null} */}
</div>
)
}
}
PullRefresh.propTypes = {
className: PropTypes.string,
children: PropTypes.any,
onPullRefresh: PropTypes.func.isRequired,
type: PropTypes.oneOf([0, 1, 2]),
count: PropTypes.number.isRequired,
pageSize: PropTypes.number.isRequired,
}
export default PullRefresh

View File

@ -19,7 +19,7 @@ function Footer(){
return(
<div>
<div style={{height:"543px"}}></div>
<div style={{height:"483px"}}></div>
<div className="newFooter edu-txt-center">
{value && showhtml(value)}
{/* <div className="footerInfos">

View File

@ -2,18 +2,15 @@ import React, { Component } from 'react';
import AccountProfile from "../../modules/user/AccountProfile";
import { getImageUrl } from 'educoder'
import axios from 'axios';
import { Input , notification , Dropdown ,Popover, Menu,Badge, Button } from 'antd';
import { Link } from 'react-router-dom';
import { Modal, Input, message, notification , Dropdown , Menu } from 'antd';
import LoginDialog from '../../modules/login/LoginDialog';
import HeadSearch from '../Component/HeadSearch';
import GotoQQgroup from '../../modal/GotoQQgroup'
import AddProjectModal from './AddProjectModal';
import '../../modules/tpm/TPMIndex.css';
import CheckProfile from '../Component/ProfileModal/Profile';
import logo from '../../modules/tpm/images/logo.png';
import './header.scss';
import NoticeContent from './NoticeContent';
const $ = window.$
// TODO 这部分脚本从公共脚本中直接调用
const { Search } = Input;
@ -36,9 +33,11 @@ class NewHeader extends Component {
Checkboxteachertype: false,
Checkboxteachingtype: false,
code_notice: false,
checked_notice: false,
RadioGroupvalue: undefined,
submitapplications: false,
isRender: false,
showSearchOpentype: false,
showTrial: false,
setevaluatinghides: false,
occupation: 0,
@ -46,12 +45,13 @@ class NewHeader extends Component {
headtypesonClickbool: false,
headtypess: "/",
settings: null,
goshowqqgtounp: false,
visiblemyss: false,
openSearch:false,
visible:false, //浮动消息框展示控制
}
}
componentDidMount() {
// this.getAppdata();
this.geturlsdata();
window._header_componentHandler = this;
@ -82,6 +82,36 @@ class NewHeader extends Component {
} catch (e) {}
}
SearchInput = (open,item)=>{
if(open){
return(
<div
onBlur={() => {
setTimeout(() => {
this.setState({
openSearch:false
})
}, 300)
}}
>
<Search placeholder="实践课程/教学课堂/实践项目/交流问答"
className={`search-input mr20`}
onSearch={(value)=>this.onGlobalSearch(value,item)}
autoFocus={true}
/>
</div>
)
}else{
return <i className="iconfont icon-sousuo font-18 color-grey-6 ml30" onClick={() => {
this.setState({openSearch:true})
}} />
}
}
onGlobalSearch=(value,item)=>{
window.location.href=`${item}?value=` + value;
}
openNotification = (messge) => {
notification.open({
message: "提示",
@ -90,12 +120,168 @@ class NewHeader extends Component {
});
};
componentWillReceiveProps(newProps, oldProps) {
this.setState({
user: newProps.user
})
if (newProps.Headertop !== undefined) {
old_url = newProps.Headertop.old_url
}
}
getCookie = (key) => {
var arr, reg = RegExp('(^| )' + key + '=([^;]+)(;|$)');
if (arr === document.cookie.match(reg))
return decodeURIComponent(arr[2]);
else
return null;
}
delCookie = (name) => {
var exp = new Date();
exp.setTime(exp.getTime() - 1);
var cval = this.getCookie(name);
if (cval != null) {
document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString();
}
}
onLogout = () => {
const url = `/accounts/logout.json`
this.delCookie("autologin_trustie")
axios.get(url, {
}).then((response) => {
if (response.data.status === 1) {
this.setState({
user: undefined
})
window.location.href = "/login"
message.success('退出成功');
}
});
}
tojoinclass = () => {
let { user } = this.state;
if (user === undefined) {
this.setState({
isRender: true
})
return
}
if (user && user.login === "") {
this.setState({
isRender: true
})
return;
}
if (user && user.profile_completed === false) {
this.setState({
AccountProfiletype: true
})
return;
}
this.setState({
Addcoursestypes: true,
})
}
tojoinitem = () => {
if (this.props.user && this.props.user.email === undefined || this.props.user && this.props.user.email === null || this.props.user && this.props.user.email === "") {
this.openNotification("请先绑定邮箱,谢谢");
return
}
let { user } = this.state;
if (user === undefined) {
this.setState({
isRender: true
})
return
}
if (user && user.login === "") {
this.setState({
isRender: true
})
return;
}
if (user && user.profile_completed === false) {
this.setState({
AccountProfiletype: true
})
return;
}
this.setState({
tojoinitemtype: true
})
}
submitstatevalue = (sum, value, data) => {
this.setState({
Addcoursestypes: false,
tojoinitemtype: false,
tojoinclasstitle: undefined,
rolearr: ["", ""],
Checkboxteacherchecked: false,
Checkboxstudentchecked: false,
Checkboxteachingchecked: false,
Checkboxteachertype: false,
Checkboxteachingtype: false,
code_notice: false,
checked_notice: false,
submitapplicationssum: sum,
submitapplications: true,
submitapplicationsvalue: value,
submitapplicationsvaluedata: data,
RadioGroupvalue: undefined
})
}
onChangeRadioGroup = (e) => {
this.setState({
RadioGroupvalue: e.target.value,
});
}
submitsubmitapplications = () => {
let {
submitapplicationssum,
submitapplicationsvaluedata
} = this.state;
this.setState({
submitapplications: false,
RadioGroupvalue: undefined
})
if (submitapplicationssum === 0) {
if (submitapplicationsvaluedata !== undefined) {
window.location.href = "/courses/" + submitapplicationsvaluedata;
}
} else if (submitapplicationssum === 1) {
if (submitapplicationsvaluedata !== undefined) {
window.location.href = "/projects/" + submitapplicationsvaluedata;
}
}
}
hidesubmitapplications = () => {
this.setState({
Addcoursestypes: false,
tojoinitemtype: false,
tojoinclasstitle: undefined,
rolearr: ["", ""],
Checkboxteacherchecked: false,
Checkboxstudentchecked: false,
Checkboxteachingchecked: false,
Checkboxteachertype: false,
Checkboxteachingtype: false,
code_notice: false,
checked_notice: false,
submitapplications: false,
RadioGroupvalue: undefined
})
}
educoderlogin = () => {
//登录账号
this.setState({
@ -120,6 +306,7 @@ class NewHeader extends Component {
})
};
HideAddcoursestypess = (i) => {
console.log("调用了");
this.setState({
Addcoursestypes: false,
mydisplay: true,
@ -132,11 +319,30 @@ class NewHeader extends Component {
})
};
hidetojoinclass = () => {
this.setState({
tojoinclasstype: false,
tojoinitemtype: false,
tojoinclasstitle: undefined,
rolearr: ["", ""],
Checkboxteacherchecked: false,
Checkboxstudentchecked: false,
Checkboxteachingchecked: false,
Checkboxteachertype: false,
Checkboxteachingtype: false,
code_notice: false,
checked_notice: false,
RadioGroupvalue: undefined
})
}
// 关闭
cancelModulationModels = () => {
this.setState({ isRenders: false })
}
setevaluatinghides = () => {
this.setState({
setevaluatinghides: true
@ -196,13 +402,39 @@ class NewHeader extends Component {
})
}
getAppdata = () => {
try {
var chromesettingArray = JSON.parse(localStorage.getItem('chromesetting'));
var chromesettingresponseArray = JSON.parse(localStorage.getItem('chromesettingresponse'));
this.setState({
settings: chromesettingArray
});
if (chromesettingArray.tab_logo_url) {
this.gettablogourldata(chromesettingresponseArray);
} else {
this.gettablogourlnull();
}
} catch (e) {
this.geturlsdata();
}
};
geturlsdata = () => {
let url = "/setting.json";
axios.get(url).then((response) => {
if (response && response.data) {
this.setState({ settings: response.data.setting });
localStorage.setItem('chromesetting', JSON.stringify(response.data.setting));
localStorage.setItem('chromesettingresponse', JSON.stringify(response));
// localStorage.setItem('chromesetting', JSON.stringify(response.data.setting));
// localStorage.setItem('chromesettingresponse', JSON.stringify(response));
try {
if (response.data.setting.tab_logo_url) {
this.gettablogourldata(response);
} else {
this.gettablogourlnull();
}
} catch (e) {
this.gettablogourlnull();
}
} else {
this.gettablogourlnull();
}
@ -222,13 +454,12 @@ class NewHeader extends Component {
}
}
checkProfile=(url)=>{
const { showCompeleteDialog , completeProfile } = this.props;
if(!completeProfile){
showCompeleteDialog && showCompeleteDialog();
}else{
window.location.href(url);
}
// 处理弹框
setgoshowqqgtounp = (bool) => {
this.setState({
goshowqqgtounp: bool
})
}
addMenu=(list)=>{
@ -239,56 +470,34 @@ class NewHeader extends Component {
{
list.map((item,key)=>{
return(
(item.name !=="加入课堂" && item.name !=="加入开发项目") &&
<Menu.Item key={item.name+key}>
<CheckProfile {...this.props} sureFunc={()=>{window.location.href=item.url}}>{item.name}</CheckProfile>
</Menu.Item>
(item.name !=="加入课堂" && item.name !=="加入开发项目") && <Menu.Item><a href={item.url}>{item.name}</a></Menu.Item>
)
})
}
<Menu.Item>
<AddProjectModal {...this.props} showNotification={this.props.showNotification}/>
</Menu.Item>
</Menu>
</div>
)
}
renderMenu=(personal)=>{
const { current_user } = this.props;
return(
<Menu className="currentMenu">
<Menu.Item>
<span className="currentName" title={current_user && current_user.username}>{current_user && current_user.username}</span>
</Menu.Item>
{
personal && personal.length > 0 && personal.map((item,key)=>{
return(
<li key={key}><a href={item.url} target="_blank">{item.name}</a></li>
)
})
}
{/* <li><Link to={`/settings/profile`}>设置</Link></li> */}
<Menu.Item><a onClick={() => this.educoderloginysl()}>退出</a></Menu.Item>
</Menu>
)
}
handleVisibleChange = visible => {
this.setState({ visible });
};
render() {
const { match ,resetUserInfo ,showNotification} = this.props;
const { match} = this.props;
let current_user = this.props.user;
let {
let { Addcoursestypes,
tojoinitemtype,
tojoinclasstitle,
code_notice,
checked_notice,
AccountProfiletype,
submitapplications,
submitapplicationsvalue,
user,
isRender,
showSearchOpentype,
headtypesonClickbool,
headtypess,
settings,
visible,
goshowqqgtounp,
openSearch,
} = this.state;
/*用户名称 用户头像url*/
let activeIndex = false;
@ -346,7 +555,7 @@ class NewHeader extends Component {
let shixun = "/shixuns";
let paths = "/paths";
let courses = "/courses";
this.props.mygetHelmetapi && this.props.mygetHelmetapi.navbar && this.props.mygetHelmetapi.navbar.map((item, key) => {
this.props.mygetHelmetapi.navbar.map((item, key) => {
var reg = RegExp(item.link);
if (shixun.match(reg)) {
if (item.hidden === true) {
@ -367,6 +576,7 @@ class NewHeader extends Component {
}
let search_url = settings && settings.common && settings.common.search;
let notice_url = settings && settings.common && settings.common.notice;
return (
<div className="newHeaders" id="nHeader">
<div className="headerContent">
@ -384,13 +594,18 @@ class NewHeader extends Component {
{...this.state}
/> : ""}
{
settings && settings.nav_logo_url ?
<a href={settings && settings.new_course.default_url} className={"fl mr50"} style={{minWidth:"45px"}}>
<img alt="可控开源社区" className="logoimg" style={{ heigth: "40px" }} src={getImageUrl(`/${settings.nav_logo_url}`)}></img>
</a>
:
""
goshowqqgtounp === true ?
<GotoQQgroup {...this.state} {...this.props} setgoshowqqgtounp={(bool) => this.setgoshowqqgtounp(bool)}></GotoQQgroup>
:""
}
<a href={settings && settings.new_course.default_url} className={"fl mr30"} style={{minWidth:"45px"}}>
{
settings && settings.nav_logo_url ?
<img alt="可控开源社区" className="logoimg" style={{ heigth: "40px" }} src={getImageUrl(`/${settings.nav_logo_url}`)}></img>
:
<img alt="可控开源社区" className="logoimg" style={{ heigth: "40px" }} src={logo}></img>
}
</a>
<div className="head-nav pr" id={"head-navpre1"}>
{
settings && settings.navbar && settings.navbar.length > 0 ?
@ -398,21 +613,21 @@ class NewHeader extends Component {
{
settings.navbar && settings.navbar.map((item, key) => {
var new_link = item.link;
var user_login = current_user && current_user.login;
var user_login = this.props.user && this.props.user.login;
var is_hidden = item.hidden
if (new_link && (new_link.indexOf("courses") > -1 || new_link.indexOf("contests") > -1)) {
if (user_login) {
if (new_link.indexOf("courses") > -1) {
new_link = new_link.replace(/courses/g, user_login + "/courses")
new_link = new_link.replace(/courses/g, "users/" + user_login + "/courses")
} else if (new_link.indexOf("contests") > -1) {
new_link = new_link.replace(/contests/g, user_login + "/contests")
new_link = new_link.replace(/contests/g, "users/" + user_login + "/contests")
}
} else {
is_hidden = true
}
}
if (user_login && (new_link && new_link.indexOf("homes") > -1)) {
new_link = new_link.replace(/homes/g, user_login + "/user_activities")
new_link = new_link.replace(/homes/g, "users/" + user_login + "/user_activities")
}
var waiLian = (new_link && str.filter(item=>new_link.indexOf(item)>-1) );
@ -429,31 +644,51 @@ class NewHeader extends Component {
}
</div>
<div className="head-right">
{ search_url && <HeadSearch {...this.props}/>}
{search_url ? this.SearchInput(openSearch,search_url):""}
{
current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)?
<Dropdown overlay={this.addMenu(settings && settings.add)} placement="bottomRight">
<i className="iconfont icon-tianjiafangda color-grey-6 ml30 mr15"></i>
<i className="iconfont icon-tianjiafangda color-grey-6 ml30"></i>
</Dropdown>:""
}
{ (settings && settings.common && settings.common.notice) && (current_user && current_user.login)?
<Popover
overlayClassName="notice-popover"
placement={`bottomRight`}
content={<NoticeContent visible={visible} current_user={current_user} showNotification={showNotification} resetUserInfo={resetUserInfo}/>}
visible={visible}
onVisibleChange={this.handleVisibleChange}
destroyTooltipOnHide
>
<Link to={"/settings/notice"} className="message-icon">
{current_user && <Badge count={current_user.message_unread_total}>
<i className="iconfont icon-xiaoxilingdang color-grey-6 ml15 mr15"></i>
</Badge>}
</Link>
</Popover>
: ""
{this.props.user && this.props.user.login && notice_url ?
<div className="ml30 edu-menu-panel">
{user && user.login &&
<a href={`${notice_url}`} style={{ position: 'relative' }}>
<i className="iconfont icon-xiaoxilingdang color-grey-6"></i>
<span className="newslight" style={{ display: this.props.Headertop === undefined ? "none" : this.props.Headertop.new_message === true ? "block" : "none" }}>
</span>
</a>
}
</div>:""
}
<Modal
keyboard={false}
title="提示"
visible={submitapplications}
closable={false}
footer={null}
>
<div className="task_popup_con ml30">
<div className="mr15">
<ul>
<div className="task-popup-content">
<p className="task-popup-text-center font-16">
{submitapplicationsvalue}
</p>
</div>
<li className="clearfix mt10 edu-txt-center">
<a className="task-btn mr10"
onClick={this.hidesubmitapplications}>取消</a>
<a
className="task-btn task-btn-orange ml20"
onClick={this.submitsubmitapplications}>确定</a>
</li>
</ul>
</div>
</div>
</Modal>
</div>
{!user || (user && !user.login) ?
<span className="font-15 ml30">
@ -464,11 +699,25 @@ class NewHeader extends Component {
}
</span>
:
<Dropdown placement={`bottomRight`} overlay={this.renderMenu(settings && settings.personal)}>
<a href={`/${this.props.current_user && this.props.current_user.login}`}>
<img alt="头像" src={getImageUrl(`/${user.image_url}`)} className="currentImg"></img>
<div className="ml30 edu-menu-panel" style={{ height: "70px", lineHeight: "70px" }}>
<a href={`/users/${this.props.current_user === undefined ? "" : this.props.current_user.login}/courses`}>
<img alt="头像" className="radius" height="34" id="nh_user_logo" name="avatar_image" src={getImageUrl(`/${user.image_url}`)} width="34">
</img>
</a>
</Dropdown>
<ul className="edu-menu-list" style={{ top: '60px', textAlign: 'center' }}>
<li className="bor-bottom-greyE" style={{cursor:"default",background:"#fff"}}>{this.props.current_user.username}</li>
{
settings && settings.personal && settings.personal.length > 0 && settings.personal.map((item,key)=>{
return(
<li key={key}><a href={item.url} target="_blank">{item.name}</a></li>
)
})
}
<li className="bor-top-greyE">
<a onClick={() => this.educoderloginysl()}>退出</a>
</li>
</ul>
</div>
}
</div>
</div>

View File

@ -1,262 +0,0 @@
import React, { useEffect, useState } from 'react';
import { Badge, Menu } from 'antd';
import { Link } from 'react-router-dom';
import axios from 'axios';
import AppPullRefresh from './AppPullRefresh';
import { noticeSourceType } from '../common/static';
import './header.scss';
import '../SecuritySetting/notice/manager/Index.scss';
import '../SecuritySetting/Index.scss';
import '../SecuritySetting/notice/myNotice/Index.scss';
function NoticeContent({ visible, showNotification, resetUserInfo, current_user: { login } }) {
const [initialize, setInitialize] = useState(true);
const [noticeType, setNoticeType] = useState("notification");
const [letterUnreadCount, setLetterUnreadCount] = useState(0);//
const [noticeUnreadCount, setNoticeUnreadCount] = useState(0);//
const [noticePage, setNoticePage] = useState(0);
const [noticeUnreadList, setNoticeUnreadList] = useState([]);//
const [atUnreadCount, setAtUnreadCount] = useState();//@
const [atPage, setAtPage] = useState(0);
const [atUnreadList, setAtUnreadList] = useState([]);//@
useEffect(() => {
resetUserInfo();
}, [noticeUnreadCount,atUnreadCount]);
useEffect(()=>{
setNoticePage(0);
setAtPage(0);
},[visible])
useEffect(() => {
const params = {
type: noticeType,
limit: 10,
page: noticeType === "notification" ? noticePage : noticeType === "atme" ? atPage : "",
status: 1,
}
getMessageList(params);
}, [noticePage, atPage]);
useEffect(() => {
const params = {
type: noticeType,
limit: 10,
page: 0,
status: 1,
};
if (initialize) {
params.type = "atme"
}
visible && getMessageList(params);
}, [visible]);
function getMessageList(params) {
axios.get(`/users/${login}/messages.json`, {
params: params,
}).then((response) => {
if (response && response.data) {
setNoticeUnreadCount(response.data.unread_notification);
setAtUnreadCount(response.data.unread_atme);
if (params.type === "notification") {
let list = response.data.messages;
if (params.page !== 0) {
list = [...noticeUnreadList, ...list];
}
setNoticeUnreadList(list);
if (initialize) {
// tab
setInitialize(false);
if (response.data.unread_notification === 0 && response.data.unread_atme !== 0) {
setNoticeType("atme");
}
}
} else if (params.type === "atme") {
let list = response.data.messages;
if (params.page !== 0) {
list = [...atUnreadList, ...list];
}
setAtUnreadList(list);
}
}
})
}
function readAll() {
axios.post(`/users/${login}/messages/read.json`, {
type: noticeType,
ids: [-1]
}).then((response) => {
let data = response.data;
if (!data) return;
if (data.status === 0) {
changeReadMarkAll(noticeType);
} else {
showNotification(data.message);
}
});
}
function changeReadMarkAll(noticeType) {
if (noticeType === "notification") {
let list = noticeUnreadList.slice();
list.forEach(item => {
item.status = 2;
})
setNoticeUnreadList(list);
setNoticeUnreadCount(0);
} else if (noticeType === "atme") {
let list = atUnreadList.slice();
list.forEach(item => {
item.status = 2;
})
setAtUnreadList(list);
setAtUnreadCount(0);
}
}
// const [letter_unread_list, setLetter_unread_list] = useState([
// {
// id: 122,
// read: 0, //01
// send_name: "", //
// send_login: "jiangYuHang", //login
// content: "", //
// create_time: "2019-03-04 18:08", //
// },
// ]);
function readItem(item) {
axios.post(`/users/${login}/messages/read.json`, {
type: noticeType,
ids: [item.id]
}).then((response) => {
let data = response.data;
if (!data) return;
if (data.status === 0) {
changeReadMark(item);
item.notification_url && window.open(item.notification_url);
} else {
showNotification(data.message);
}
});
}
function changeReadMark(item) {
if (item.type === "notification") {
let list = noticeUnreadList.slice();
let index = noticeUnreadList.indexOf(item);
list[index].status = 2;
setNoticeUnreadList(list);
if (noticeUnreadCount > 0) {
setNoticeUnreadCount(noticeUnreadCount - 1);
}
} else if (item.type === "atme") {
let list = atUnreadList.slice();
let index = atUnreadList.indexOf(item);
list[index].status = 2;
setAtUnreadList(list);
if (atUnreadCount > 0) {
setAtUnreadCount(atUnreadCount - 1);
}
}
}
return (
<div className="messageHoverDiv notice01">
<div className="sshHead hoverNotice-head">
<Menu mode="horizontal" selectedKeys={noticeType} onClick={(e) => setNoticeType(e.key)}>
<Menu.Item key="notification"><Badge count={noticeUnreadCount}>系统通知</Badge></Menu.Item>
{/* <Menu.Item key="1" id="item-private"><Badge count={letterUnreadCount}>私信</Badge></Menu.Item> */}
<Menu.Item key="atme"><Badge count={atUnreadCount}>@</Badge></Menu.Item>
</Menu>
</div>
{/* 系统通知 */}
{noticeType === "notification" && <AppPullRefresh
className='hoverNotice-body' // className
onPullRefresh={() => { setNoticePage(noticePage + 1); }} //ajaxfunction
// type={2} //
count={noticeUnreadList.length} //
pageSize={10} //
>
{
noticeUnreadList.map(item => {
return (
<div key={item.id + Math.random()} className="noticeCont-back" onClick={() => { readItem(item) }}>
<div className={`noticeCont ${item.notification_url?'pointer':''}`}>
<span style={{ visibility: item.status === 1 ? 'visible' : 'hidden' }}>
<Badge color="#FA2020" />
</span>
<i className={"iconfont " + noticeSourceType[item.source]}></i>
<div className="noticeCont-text">
<span className="content-span notice-cont-span" dangerouslySetInnerHTML={{ __html: item.content }}></span>
<span className="timeSpan">{item.time_ago}</span>
</div>
</div>
</div>
)
})
}
</AppPullRefresh>
}
{/* @我 */}
{noticeType === "atme" && <AppPullRefresh
className='hoverNotice-body' // className
onPullRefresh={() => { setAtPage(atPage + 1); }} //ajaxfunction
// type={1} //
count={atUnreadList.length} //
pageSize={10} //
>
{atUnreadList.map(item => {
return (
<div key={item.id + Math.random()} className="noticeCont-back" onClick={() => { readItem(item) }}>
<div className="noticeCont">
<span style={{ visibility: item.status === 1 ? 'visible' : 'hidden' }}>
<Badge color="#FA2020" />
</span>
<div className="noticeCont-text">
<span className="content-span atme-cont-span" dangerouslySetInnerHTML={{ __html: "<b>" + (item.sender ? item.sender.name : '') + "</b>&nbsp;&nbsp;&nbsp;" + item.content + " 中@我" }}></span>
<span className="timeSpan">{item.time_ago}</span>
</div>
</div>
</div>
)
})
}
</AppPullRefresh>
}
{/* 私信 */}
{/* {noticeType === "1" ? letter_unread_list.length > 0 ? letter_unread_list.map(item => {
return (
<div className="noticeCont-back">
<div className="noticeCont" style={{ height: item.content.length >= 30 && item.content.length <= 34 ? '65px' : "" }}>
<Badge color="#FA2020" />
<div className="noticeCont-text">
<span>{item.send_name}</span>
<span className="boldSpan" dangerouslySetInnerHTML={{ __html: item.content.length >= 50 ? item.content.substr(0, 50) + "..." : item.content }}></span>
<span className="timeSpan">{item.create_time ? timeAgo(item.create_time) : "刚刚"}</span>
</div>
</div>
</div>
)
}) : "暂无数据" : ""} */}
<div className="hoverNotice-buttom">
<Link to={{pathname:"/settings/notice",query:{noticeType:noticeType}}}>全部消息</Link>
{noticeUnreadCount > 0 && noticeType === "notification" && <a onClick={readAll}>所有系统消息一键已读</a>}
{atUnreadCount > 0 && noticeType === "atme" && <a onClick={readAll}>所有@我一键已读</a>}
</div>
</div>
)
}
export default NoticeContent;

View File

@ -1,6 +1,7 @@
.dropdownFlex{
display:flex;
padding:5px;
background:#fff;
border-radius: 3px;
.ant-menu-vertical > .ant-menu-item{
@ -8,65 +9,11 @@
height: 35px;
line-height: 35px;
margin:0px;
&.ant-menu-item-selected{
background-color: #fff;
a{color: rgba(0, 0, 0, 0.65)!important;}
}
&.ant-menu-item-active{
a{color: #4cacff!important;}
}
}
.ant-menu-vertical{
border:none;
}
}
.currentImg{
width: 34px;
height: 34px;
border-radius: 50%;
margin-left: 15px;
}
.currentMenu{
width: 120px;
text-align: center;
padding:0px;
.currentName{
padding:0px 8px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: block;
}
li{
height: 40px;
line-height: 40px;
padding:0px!important;
cursor: default;
&:hover{
background-color: #fff;
}
&:first-child{
border-bottom: 1px solid #eee;
}
&:last-child{
border-top: 1px solid #eee;
a{
border-radius: 0px 0px 4px 4px;
}
}
a{
padding:0px;
margin:0px;
display: block;
color: #666;
&:hover{
color: #fff;
background: #4CACFF;
}
}
}
}
.newFooter {
position: absolute;
@ -119,147 +66,3 @@
}
}
}
.inviteForm{
.ant-form-item{
margin-right: 0px;
}
.ant-form-item-label{
width: 110px;
text-align: right;
}
}
// 右上角小铃铛单独样式
.notice-popover{
//popover小尖尖
.ant-popover-arrow{
display: none;
}
//popover框
.ant-popover-inner-content {
width: 386px;
height: 446px;
box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5);
border-radius: 4px;
margin-top: -10px;
padding: 12px 1px 12px 0;
}
}
.messageHoverDiv .ant-menu-item{
margin-right: 24px !important;
}
.hoverNotice-head{
margin-left: 18px;
& .ant-badge{
font-size: 14px !important;
}
&>.ant-menu-horizontal {
border-bottom: 1px solid #e8e8e8 !important;
}
}
.hoverNotice-body{
height: 342px;
overflow-y: scroll;
& b{
font-weight: 400;
text-shadow: 0.5px 0 0 #333;
}
.none_panels{
height: 100%;
}
}
.message-icon{
position: relative;
.ant-scroll-number{
right:12px;
padding: 0 0px;
}
}
.hoverNotice-buttom{
display: flex;
justify-content: space-between;
padding: 12px 18px;
a{
color: #466AFF;
&:hover{
opacity:0.85;
}
}
}
.noticeCont-back{
.pointer{
cursor: pointer;
}
&:hover{
background: #F3F4F6;
}
}
.noticeCont{
display: flex;
margin: 0 16px 0 18px;
padding: 12px 0 10px 0;
line-height: 24px;
border-bottom: 1px solid #EEEEEE;
cursor: default;
i{
font-size: 14px !important;
margin-right: 6px;
color: #333333;
}
.boldSpan{
font-weight: 400;
text-shadow: 0.5px 0 0 #333;
}
.noticeCont-text{
display: flex;
color:#333333;
flex:auto;
justify-content: space-between;
& .content-span{
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
& .atme-cont-span{
width: 272px;
}
& .notice-cont-span{
width: 255px;
}
.timeSpan{
font-size: 12px;
color: #666666;
}
.at-name{
margin-right: 12px;
}
}
}
.text-center{
text-align: center;
}

View File

@ -12,7 +12,6 @@ import Loadable from "react-loadable";
import Loading from "../Loading";
import { ImageLayerOfCommentHOC } from "../modules/page/layers/ImageLayerOfCommentHOC";
const ProjectNew = Loadable({
loader: () => import("./New/Index"),
loading: Loading,
@ -22,23 +21,17 @@ const ProjectIndex = Loadable({
loading: Loading,
});
// 项目详情放在用户和组织下作为二级菜单存在
// const ProjectDetail = Loadable({
// loader: () => import("./Main/Detail"),
// loading: Loading,
// });
const ProjectDetail = Loadable({
loader: () => import("./Main/Detail"),
loading: Loading,
});
const Infos = Loadable({
loader: () => import("./users/Infos"),
loading: Loading,
});
class Index extends Component {
componentDidUpdate = () => {
this.props.history.listen(() => {
if (document.body.scrollTop || document.documentElement.scrollTop > 0) {
window.scrollTo(0, 0)
}
})
}
render() {
return (
<div className="newMain clearfix">
<Switch {...this.props}>
@ -55,27 +48,30 @@ class Index extends Component {
)}
></Route>
<Route
path="/projects/mirror/new"
path="/projects/new"
render={(props) => (
<ProjectNew {...this.props} {...props} />
)}
></Route>
{/* <Route
path="/:owner/:projectsId"
<Route
path="/projects/:owner/:projectsId"
render={(props) => (
<ProjectDetail {...this.props} {...props} />
)}
></Route> */}
></Route>
<Route
path="/explore"
path="/projects"
render={(props) => (
<ProjectIndex {...this.props} {...props} />
)}
></Route>
<Route
exact
path="/"
render={(props) => (
this.props.current_user && this.props.current_user.login ?
<Infos {...this.props} {...props} />
:
<ProjectIndex {...this.props} {...props} />
)}
></Route>
@ -90,10 +86,3 @@ export default withRouter(
parentSelector: ".newMain",
})(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(Index))))
);
// export default withRouter(
// ImageLayerOfCommentHOC({
// imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget",
// parentSelector: ".newMain",
// })(Index)
// );

View File

@ -1,9 +1,8 @@
import React , { useEffect , useState } from 'react';
import { WhiteBack , Box , LongWidth , ShortWidth , Gap , AlignCenter , FlexAJ } from '../Component/layout';
import { Dropdown , Menu , Divider , Spin, Button , Typography } from 'antd';
import { Dropdown , Menu , Divider , Spin, Button } from 'antd';
import { getImageUrl } from "educoder";
import { Link } from 'react-router-dom';
import { truncateCommitId } from "../common/util";
import CloneAddress from '../Branch/CloneAddress';
import SelectBranch from '../Branch/Select';
@ -20,30 +19,12 @@ import LanguagePower from '../Component/LanguagePower';
import DrawerPanel from '../Component/DrawerPanel';
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';
import Badge from "./sub/Badge";
/**
* projectDetail.type:0是托管项目1是镜像项目2是同步镜像项目(为2时不支持在线创建在线上传在线修改在线删除创建合并请求等功能)
*/
const { Paragraph } = Typography;
function turnbar(str){
if(str && str.length>0 && str.indexOf("/")>-1){
return str.replaceAll('/','%2F');
}
return str;
}
function returnbar(str){
if(str && str.length>0 && str.indexOf("%2F")>-1){
return str.replaceAll('%2F','/');
}
return str;
}
function CoderDepot(props){
const [ projectDetail , setProjectDetail ]= useState(undefined);
const [ inviteCode , setInviteCode ] = useState(undefined);
const [ treeValue , setTreeValue ] = useState(undefined);
const [ treeValuePath , setTreeValuePath ] = useState(undefined);
const [ lastCommit,setLastCommit ] = useState(undefined);
@ -64,53 +45,19 @@ function CoderDepot(props){
const [ desc , setDesc ] = useState(undefined);
const [ website , setWebsite ] = useState(undefined);
const [ lesson_url , setLessonUrl ] = useState(undefined);
const [ readme , setReadme ] = useState(undefined);
const [ defaultBranch , setDefaultBranch ] = useState(undefined);
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;
let branchName = props.match.params.branchName;
branchName = returnbar(branchName);
const details = props.projectDetail;
const branchName = props.match.params.branchName;
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;
// test data
const badges = {badge:[{ "login": "many_stars", "image_url": "https://www.gitlink.org.cn/system/lets/letter_avatars/2/J/236_194_58/120.png", "description": "test description1"}, {"login": "many_stars", "image_url": "https://www.gitlink.org.cn/system/lets/letter_avatars/2/X/181_166_38/120.png", "description": "test description2"}], total_count: 3}
console.log(badges.badge)
console.log(badges.total_count)
useEffect(()=>{
if(bannerList && bannerList.length>0){
let a = bannerList.filter(i=>i.menu_name === "pulls");
let i = bannerList.filter(i=>i.menu_name === "issues");
if(a && a.length === 0){
setPullsFlag(false);
if(props.projectDetail){
setProjectDetail(props.projectDetail);
setDesc(props.projectDetail.description);
setWebsite(props.projectDetail.website);
setLessonUrl(props.projectDetail.lesson_url);
}
if(i && i.length === 0){
setIssuesFlag(false);
}
}
},[bannerList])
useEffect(()=>{
if(details){
setProjectDetail(details);
setDesc(details.description);
setWebsite(details.website);
setLessonUrl(details.lesson_url);
setDefaultBranch(details.default_branch);
setInviteCode(details.invite_code);
}
},[details])
},[props])
useEffect(()=>{
if(treeValue){
@ -120,61 +67,23 @@ function CoderDepot(props){
}
},[treeValue])
useEffect(()=>{
if (projectsId && owner && defaultBranch){
let b = turnbar(branchName) ;
if(pathname.indexOf(`/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${b}/`) > -1) {
let url = pathname.split(`/tree/${b}/`)[1];
if (pathname && projectDetail){
if(pathname.indexOf(`/projects/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${branchName}/`) > -1) {
let url = pathname.split(`/tree/${branchName}/`)[1];
setTreeValue(url);
getFileInfo(url,branchName);
setType("file");
// getReadmeInfo(url,branchName);
// setReadme(undefined);
}else{
setTreeValue(undefined);
getDirInfo(branchName || defaultBranch);
setType("dir");
// getReadmeInfo('', branchName || defaultBranch);
getDirInfo(branchName ||projectDetail.default_branch);
}
}
},[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);
}
})
}
},[pathname,projectDetail])
//
function getDirInfo(branch){
setIsSpin(true);
const url = `/${owner}/${projectsId}/entries.json`;
axios.get(url, {
params: { ref: branch }
}).then((result) => {
@ -189,10 +98,6 @@ function CoderDepot(props){
setLastCommitAuthor(c && c.committer);
setMainFlag(true);
setReadOnly(true);
// setReadme(result.data.readme);
setEditReadme(false);
setHide(true);
getReadmeInfo('', branchName || defaultBranch);
}
setTimeout(function(){setIsSpin(false);},500);
}).catch(error=>{setIsSpin(false);})
@ -204,7 +109,7 @@ function CoderDepot(props){
let ele = document.getElementById("ptxt");
if(ele){
let h = ele.offsetHeight;
if( h > 35 ) setHideBtn(true);
if( h > 18 ) setHideBtn(true)
}
}
},[projectDetail,lastCommit])
@ -225,20 +130,16 @@ 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);
}
setTimeout(function(){setIsSpin(false);},500)
}).catch(error=>{setIsSpin(false);})
@ -246,26 +147,17 @@ function CoderDepot(props){
//
function changeBranch(value){
let checkvalue = turnbar(value);
let url = `/${owner}/${projectsId}${value && `/tree/${checkvalue}`}${treeValue ? `/${treeValue}`:""}`;
let url = `/projects/${owner}/${projectsId}${value && `/tree/${value}`}${treeValue ? `/${treeValue}`:""}`;
props.history.push(url);
}
//
function fileMenu(){
let b = branchName || defaultBranch;
let checkvalue = turnbar(b);
return (
<Menu className="fileMenu">
<Menu.Item>
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件</CheckProfile>
</Menu.Item>
<Menu.Item>
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件</CheckProfile>
</Menu.Item>
const fileMenu =(
<Menu>
<Menu.Item><a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/${branchName || (projectDetail && projectDetail.default_branch)}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件</a></Menu.Item>
<Menu.Item><a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/${branchName || (projectDetail && projectDetail.default_branch)}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件</a></Menu.Item>
</Menu>
)
}
function getPathUrl(array,index){
if(array && array.length>0 && index){
@ -279,36 +171,27 @@ function CoderDepot(props){
//
function returnMain(){
setTreeValue(undefined);
let branch = branchName || defaultBranch;
let checkvalue = turnbar(branch);
props.history.push(`/${owner}/${projectsId}/tree/${checkvalue}`);
let branch = branchName || (projectDetail && projectDetail.default_branch);
props.history.push(`/projects/${owner}/${projectsId}/tree/${branch}`);
};
//
function returnUlr(url){
let enBranch = turnbar(branchName);
props.history.push(`/${owner}/${projectsId}/tree${enBranch?`/${enBranch}`:""}/${url}`);
props.history.push(`/projects/${owner}/${projectsId}/tree${branchName?`/${branchName}`:""}/${url}`);
}
//
function goToSubRoot(path,type,filename){
if(type!=="submodule"){
let enBranch = branchName || defaultBranch;
let checkvalue = turnbar(enBranch);
setType(type);
props.history.push(`/${owner}/${projectsId}${`/tree/${checkvalue}`}${path?`/${path}`:""}`);
}
props.history.push(`/projects/${owner}/${projectsId}${`/tree/${branchName || (projectDetail && projectDetail.default_branch)}`}${path?`/${path}`:""}`);
}
function onEdit(readOnly){
setReadOnly(readOnly);
setEditReadme(false);
}
function ChangeFile(path, readOnly){
//
let enBranch = branchName || defaultBranch;
let checkvalue = turnbar(enBranch);
props.history.push(`/${owner}/${projectsId}/tree/${checkvalue}/${path}`);
props.history.push(`/projects/${owner}/${projectsId}/tree/${branchName || (projectDetail && projectDetail.default_branch)}/${path}`);
setType("file");
setEditReadme(true);
setReadOnly(readOnly);
};
function changeHide(hide){
@ -324,12 +207,17 @@ function CoderDepot(props){
}
const downloadMenu = (
<div className="downMenu">
<div style={{padding:"20px",borderBottom:"1px solid #eee"}}>
<CloneAddress
http_url={projectDetail && projectDetail.clone_url}
ssh_url = {projectDetail && projectDetail.ssh_url}
zip_url={zip_url}
tar_url={tar_url}
showNotification={props.showNotification}/>
</div>
<Menu className="edu-txt-center">
<Menu.Item><a href={zip_url}>下载 ZIP</a></Menu.Item>
<Menu.Item><a href={tar_url}>下载 TAR.GZ</a></Menu.Item>
</Menu>
</div>
)
// website
function okUpdate(d,w,l){
@ -344,16 +232,11 @@ function CoderDepot(props){
}
})
}
let n = fileInfo && fileInfo.name;
const mdFlag = n && n.substring(n.length-3,n.length) === ".md";
const { current_user } = props;
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(
<WhiteBack>
<UpdateDescModal desc={desc} website={website} lesson_url={lesson_url} visible={openModal} onCancel={()=>setOpenModal(false)} onOk={okUpdate}/>
<Spin spinning={isSpin}>
@ -365,44 +248,90 @@ function CoderDepot(props){
owner={owner}
projectsId={projectsId}
name={projectDetail && projectDetail.name}
branch={branchName || defaultBranch}
branch={branchName || (projectDetail && projectDetail.default_branch)}
visible={visible}
onClose={()=>setVisible(false)}
list = {mainFlag ? dirInfo : undefined}
/>
<div className="drawerBtn" onClick={()=>setVisible(true)}>
<i className="iconfont icon-zuohuaicon font-14"></i>
<i className="iconfont icon-youjiantou font-16"></i>
<span>目录</span>
</div>
</React.Fragment>
}
<div style={{minHeight:"500px"}}>
{
projectDetail &&
<Box className="Panels">
<LongWidth>
<div className="panelmenu">
<FlexAJ>
<AlignCenter>
<div className="mr30">
<div className="mr20">
{
props && props.platform ?
<SelectBranch
repo_id={projectDetail && projectDetail.repo_id}
projectsId={projectsId}
branch={branchName || defaultBranch}
branch={branchName || (projectDetail && projectDetail.default_branch)}
changeBranch={changeBranch}
owner={owner}
history={props.history}
branchList={projectDetail && projectDetail.branches && projectDetail.branches.list}
></SelectBranch>
:
<span>分支<span className="color-grey-6">{branchName || defaultBranch}</span></span>
<span>分支<span className="color-grey-6">{branchName || (projectDetail && projectDetail.default_branch)}</span></span>
}
</div>
<AlignCenter className="mr20">
<Link to={`/projects/${owner}/${projectsId}/branchs`} className="color-grey-9">
<i className="iconfont icon-fenzhi2 font-18 color-grey-9 mr3"></i>
<span className="color-grey-6 mr3">{projectDetail && projectDetail.branches && projectDetail.branches.total_count}</span>分支
</Link>
</AlignCenter>
<AlignCenter className="mr20">
<Link to={`/projects/${owner}/${projectsId}/tag`} className="color-grey-9">
<i className="iconfont icon-biaoqian3 font-16 color-grey-9 mr3"></i>
<span className="color-grey-6 mr3">{projectDetail && projectDetail.tags && projectDetail.tags.total_count}</span>标签
</Link>
</AlignCenter>
</AlignCenter>
<AlignCenter>
<div className="mr20 addOptionBtn">
{
treeValuePath && treeValuePath.length > 0 ?
projectDetail.type !== 2 &&
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/pulls/new`)} >+ 合并请求</a>
}
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/issues/new`)} >+ 任务</a>
</div>
{ type === "dir" && projectDetail.type !== 2 &&
<Dropdown overlay={fileMenu} className="mr20" trigger={['click']}>
<Button type="default">文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-9"></i></Button>
</Dropdown>
}
<Dropdown overlay={downloadMenu} placement="bottomRight" trigger={['click']}>
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white"></i></Button>
</Dropdown>
</AlignCenter>
</FlexAJ>
{
dirInfo || fileInfo ?
<div className="listtable">
{
lastCommit &&
<div className="listtablehead">
<User url={getImageUrl(`/${lastCommitAuthor && lastCommitAuthor.image_url}`)} name={lastCommitAuthor && lastCommitAuthor.name} id={lastCommitAuthor && lastCommitAuthor.id} login={lastCommitAuthor && lastCommitAuthor.login}/>
<div className={hideBtn && hide ? "ellipsistxt hide" :"ellipsistxt"}><pre id="ptxt">{lastCommit && lastCommit.message}</pre></div>
{ hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> }
<span className="ml12 color-grey-9 mt3">{lastCommit && lastCommit.time_from_now}</span>
{ commitCount ? <Link to={`/projects/${owner}/${projectsId}/commits`} className="ml12 color-grey-9"><i className="iconfont icon-tijiao mr3 font-17 color-grey-9"></i>{commitCount}次提交</Link>:"" }
</div>
}
<ul className="listtablebody">
{
treeValuePath && treeValuePath.length > 0 &&
<Path
identifier={projectDetail && projectDetail.identifier}
treeValuePath={treeValuePath}
@ -410,77 +339,7 @@ function CoderDepot(props){
returnMain={returnMain}
getPathUrl={getPathUrl}
/>
:
<React.Fragment>
<AlignCenter className="mr20">
<Link to={`/${owner}/${projectsId}/branches`} className="iconBtn">
<i className="iconfont icon-master_icon font-16"></i>
<span>分支</span>
<span>{projectDetail && projectDetail.branches_count}</span>
</Link>
</AlignCenter>
<AlignCenter className="mr20">
<Link to={`/${owner}/${projectsId}/tags`} className="iconBtn">
<i className="iconfont icon-biaoqianicon font-16"></i>
<span>标签</span>
<span>{projectDetail && projectDetail.tags_count}</span>
</Link>
</AlignCenter>
</React.Fragment>
}
</AlignCenter>
<AlignCenter className="depotBtn">
{
(baseOperate || baseOper) &&
<div className="addOptionBtn">
{
baseOperate &&
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/compare/master...${branchName || defaultBranch}`)} >+ 合并请求</CheckProfile>
}
{
baseOper &&
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/issues/new`)} >+ 易修</CheckProfile>
}
</div>
}
{ fileOperate &&
<Dropdown
overlay={fileMenu()}
className="mr10"
trigger={['click']}
getPopupContainer={document.parentNode}
>
<a>文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-6 mr-5"></i></a>
</Dropdown>
}
<Dropdown overlay={downloadMenu} placement="bottomRight" trigger={['click']}>
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white mr-3"></i></Button>
</Dropdown>
</AlignCenter>
</FlexAJ>
{
(dirInfo && dirInfo.length>0) || fileInfo ?
<div className="listtable">
{
lastCommit &&
<div className="listtablehead">
<User url={getImageUrl(`/${lastCommitAuthor && lastCommitAuthor.image_url}`)} name={lastCommitAuthor && lastCommitAuthor.name} id={lastCommitAuthor && lastCommitAuthor.id} login={lastCommitAuthor && lastCommitAuthor.login}/>
<div className={hideBtn && hide ? "ellipsistxt hidetxt" :"ellipsistxt"}>
<pre id="ptxt"><Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(lastCommit.sha)}`}><RenderHtml value={lastCommit.message}/></Link></pre>
</div>
{ hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> }
<span className="ml20 color-grey-6 font-12 mt3">{lastCommit.time_from_now}</span>
{
commitCount ?
<Link to={`/${owner}/${projectsId}/commits/branch/${turnbar(branchName || defaultBranch)}`} className="ml20 color-grey-3"style={{height:"28px",lineHeight:"28px"}}>
<i className="iconfont icon-tijiaoicon mr3 font-16"></i><span style={{fontWeight:"500"}}>{commitCount}次提交</span>
</Link>:""
}
</div>
}
<ul className="listtablebody">
{
dirInfo && dirInfo.length > 0 &&
dirInfo.map((item,key)=>{
@ -502,7 +361,7 @@ function CoderDepot(props){
readOnly={readOnly}
md={mdFlag}
onEdit={onEdit}
currentBranch={branchName || defaultBranch}
currentBranch={branchName || (projectDetail && projectDetail.default_branch)}
type={projectDetail.type}
></CoderRootFileDetail>
}
@ -511,93 +370,64 @@ function CoderDepot(props){
: ""
}
{
(dirInfo && dirInfo.length === 0) && !fileInfo ? <Nodata _html="暂未发现文件"/> :""
(dirInfo && dirInfo.length === 0) && (fileInfo && fileInfo.length === 0) ? <Nodata _html="暂未发现文件"/> :""
}
{/* readme文件显示(显示文件详情时不显示readme文件) */}
{ (readme && readme.content) ? <ReadMe ChangeFile={ChangeFile} readme={readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
{ dirInfo && (projectDetail && projectDetail.readme) ? <ReadMe ChangeFile={ChangeFile} readme={projectDetail && projectDetail.readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
</div>
</LongWidth>
{
(!(treeValuePath && treeValuePath.length > 0) && !fileInfo) &&
!fileInfo &&
<ShortWidth>
<Gap style={{paddingLeft:"30px"}}>
<div className="panelmenu">
<FlexAJ className="font-18 color-ooo mb20" style={{lineHeight:"28px"}}>关于
{
projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner" || projectDetail.permission==="Manager") &&
<i onClick={()=>setOpenModal(true)} className="iconfont icon-a-shezhi color-grey-9 font-15"></i>
}
<FlexAJ className="font-18 color-grey-6 mb20" style={{lineHeight:"28px"}}>简介
{projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner") && <i onClick={()=>setOpenModal(true)} className="iconfont icon-anquanshezhi color-grey-9 font-15"></i>}
</FlexAJ>
{desc && <p className="font-14 color-grey-3 mb15 task-hide-2" style={{lineHeight:"24px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}}>{desc}</p>}
{desc && <p className="font-14 color-grey-9 mb15 task-hide-2" style={{lineHeight:"22px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}}>{desc}</p>}
{
website &&
<div className="color-grey-6 df pinfos mb5">
<i className="iconfont icon-lianjie2 font-15 mr10"></i>
<p className="color-grey-6 df">
<i className="iconfont icon-lianjie2 font-15 mr10 color-grey-9"></i>
<a href={website} target="_blank" style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px",textDecoration:"underline"}}>{website}</a>
</div>
</p>
}
<div className="pinfos mb5">
<i className="iconfont icon-zishuwenjian_icon font-15 mr10"></i>
<a href="#readme">README.md</a>
</div>
<div className="color-grey-6 mb5">
<i className="iconfont icon-neicunicon font-15 mr10"></i>
<p>
<i className="iconfont icon-wenjian4 font-15 mr10 color-grey-9"></i>
<a href="#readme" className="color-grey-6">README.md</a>
</p>
<p className="color-grey-6">
<i className="iconfont icon-dataBase font-15 mr10 color-grey-9"></i>
<span>{projectDetail && projectDetail.size}</span>
</div>
</p>
{
projectDetail && projectDetail.license_name &&
<div className="pinfos">
<i className="iconfont icon-xieyiicon font-16 mr10"></i>
<Link to={`/${owner}/${projectsId}/tree/${branchName || defaultBranch}/LICENSE`} className="color-grey-6">{projectDetail.license_name}</Link>
</div>
<p className="color-grey-6">
<i className="iconfont icon-tianping font-16 mr10 color-grey-9"></i>
<span>{projectDetail.license_name}</span>
</p>
}
</div>
{
inviteCode &&
<div>
<Divider />
<Invite code={inviteCode}/>
</div>
}
{/*{*/}
{/* inviteCode &&*/}
{/* <div>*/}
{/* <Badge code={inviteCode}/>*/}
{/* </div>*/}
{/*}*/}
{/* 徽章 */}
{
badges && badges.total_count >0 &&
<Badge badges={badges} owner={owner} />
}
{
lesson_url &&
<div>
<Divider />
<p className="font-16 color-ooo">实践课程</p>
<a href={lesson_url} target="_blank" className="color-grey-6" style={{textDecoration:"underline",wordBreak:"break-all"}}>{lesson_url}</a>
<p className="font-16 color-grey-6">实践课程</p>
<a href={lesson_url} target="_blank" className="color-grey-6" style={{textDecoration:"underline"}}>{lesson_url}</a>
</div>
}
{/* 发布 */}
{
releaseVersions &&
projectDetail && projectDetail.release_versions &&
<React.Fragment>
<Divider />
<Releases
owner={owner}
projectsId={projectsId}
releaseVersions={releaseVersions}
history={props.history}
distribution={distribution}
/>
<Releases owner={owner} projectsId={projectsId} releaseVersions={projectDetail.release_versions} history={props.history}/>
</React.Fragment>
}
{/* 贡献者 */}
{
projectDetail && projectDetail.contributors && projectDetail.contributors.total_count >0 &&
<Contributors contributors={projectDetail.contributors} owner={owner} projectsId={projectsId} />
projectDetail && projectDetail.contributors &&
<Contributors contributors={projectDetail && projectDetail.contributors} owner={owner} projectsId={projectsId} />
}
{/* 语言 */}
{ projectDetail && projectDetail.languages &&

View File

@ -2,26 +2,20 @@ import React from 'react';
import { Link } from 'react-router-dom';
import { truncateCommitId } from '../common/util';
const typeIco = {
"submodule":"icon-file-submodule font-17",
"file":'icon-wenjian6 font-15 color-blue-file',
"dir":"icon-wenjianjia4 font-15 color-blue_4C"
}
function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
return(
<li>
<span>
<a onClick={()=>goToSubRoot(item.path,item.type,item.name)} className={item.type === "submodule" && "submoduleStyle"}>
<i className={`iconfont ${typeIco[`${item.type}`]} mr8`}></i>{item.name}
<a onClick={()=>goToSubRoot(item.path,item.type,item.name)}>
<i className={item.type === 'dir' ? "iconfont icon-wenjianjia1 color-green-file font-15 mr5":"iconfont icon-wenjia color-green-file font-15 mr5"}></i>{item.name}
</a>
</span>
<span title="init project">
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.commit && item.commit.sha}`)}`} title={item.commit && item.commit.message}>
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.commit && item.commit.sha}`)}`} title={item.commit && item.commit.message}>
{item.commit && item.commit.message}
</Link>
</span>
<span title={item.commit && item.commit.created_at}>{item.commit && item.commit.time_from_now}</span>
<span>{item.commit && item.commit.time_from_now}</span>
</li>
)
}

View File

@ -1,4 +1,3 @@
import { result } from 'lodash';
import React from 'react';

View File

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

View File

@ -4,20 +4,14 @@ 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';
import './list.css';
function turnbar(str){
if(str && str.length>0 && str.indexOf("/")>-1){
return str.replaceAll('/','%2F');
}
return str;
}
export default ((props)=>{
const [ data , setData ] =useState(undefined);
const [ isSpin , setIsSpin ] =useState(true);
const { projectsId , owner } = props.match.params;
const { isManager , isDeveloper , projectDetail } = props;
useEffect(()=>{
getBranchs(projectsId, owner);
},[projectsId])
@ -38,18 +32,15 @@ export default ((props)=>{
return(
<li key={key}>
<div>
<Link to={`/${owner}/${projectsId}/tree/${turnbar(item.name)}`} className="color-blue font-15" style={{"maxWidth":"100px"}}>{item.name}</Link>
<Link to={`/projects/${owner}/${projectsId}/tree/${item.name}`} className="color-blue font-15" style={{"maxWidth":"100px"}}>{item.name}</Link>
<p className="f-wrap-alignCenter mt15">
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.last_commit.sha}`)}`} className="mr5 commitKey" style={{marginLeft:0}}>{item.last_commit && truncateCommitId(item.last_commit.sha)}</Link>
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.last_commit.sha}`)}`} className="mr5 commitKey" style={{marginLeft:0}}>{item.last_commit && truncateCommitId(item.last_commit.sha)}</Link>
<span className="color-grey-3 hide-1 messages leftPoint">{item.last_commit && item.last_commit.message}</span>
<span className="color-grey-8 ml30">最后更新于{item.last_commit && item.last_commit.time_from_now}</span>
</p>
</div>
<span>
{
(isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) &&
<Link to={`/${owner}/${projectsId}/pulls/new/${item.name}`} className="mr20 color-blue mr30">创建合并请求</Link>
}
<Link to={`/projects/${owner}/${projectsId}/pulls/new`} className="mr20 color-blue mr30">创建合并请求</Link>
<Dropdown overlay={menu(item.zip_url,item.tar_url)} trigger={['click']} placement="bottomRight" className="color-green-file">
<a className="ant-dropdown-link">
<Tooltip title={`下载分支${item.name}`}><Icon type="cloud-download" className="font-18"/></Tooltip>
@ -73,7 +64,6 @@ export default ((props)=>{
<Menu.Item key={'1'}><a href={tar_url}>TAR.GZ</a></Menu.Item>
</Menu>
)
return(
<React.Fragment>
<div className="main">

View File

@ -1,35 +1,20 @@
import React , { Component } from 'react';
import { Spin , Pagination, Timeline } from 'antd';
import { Spin , Pagination } from 'antd';
import { getImageUrl } from 'educoder';
import { truncateCommitId ,timeFormat } from '../common/util';
import { AlignTop } from '../Component/layout';
import { truncateCommitId } from '../common/util';
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){
return str.replaceAll('%2F','/');
}
return str;
}
//代码库--提交页面
class CoderRootCommit extends Component{
constructor(props){
super(props);
super(props)
this.state={
commitDatas:undefined,
dataCount:undefined,
limit:10,
limit:20,
page:1,
isSpining:false,
branchList:undefined
@ -58,28 +43,13 @@ class CoderRootCommit extends Component{
this.Init();
}
}
UrlParamHash(url){
const params = {};
let h;
let hash = url.slice(url.indexOf('?')+1).split('&');
for(let i = 0; i<hash.length;i++){
h = hash[i].split('=');
params[h[0]] = h[1];
}
return params;
}
Init =()=>{
const { branchName } = this.props.match.params;
const { limit } = this.state;
const {search} = this.props.location;
const realPage = (search && this.UrlParamHash(search).page) ? parseInt(this.UrlParamHash(search).page) : 1;
const { page , limit } = this.state;
this.setState({
isSpining:true,
page:realPage
isSpining:true
})
this.getCommitList( branchName , realPage , limit );
this.getCommitList( branchName , page , limit );
}
getCommitList=(branch , page , limit)=>{
@ -90,7 +60,7 @@ class CoderRootCommit extends Component{
const url = `/${owner}/${projectsId}/commits.json`;
axios.get(url,{
params:{
sha:returnbar(branch),
sha:branch,
page,
limit
}
@ -108,8 +78,7 @@ 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,
timestamp:item.timestamp
message:item.message
})
})
this.setState({
@ -124,18 +93,19 @@ class CoderRootCommit extends Component{
// 切换分支 search:tag为根据标签搜索
changeBranch=(value)=>{
const { projectsId , owner } = this.props.match.params;
this.props.history.push(`/${owner}/${projectsId}/commits/branch/${value}`);
this.props.history.push(`/projects/${owner}/${projectsId}/commits/branch/${value}`);
}
ChangePage=(page)=>{
this.props.history.push({pathname: this.props.history.location.pathname,search: `page=${page}`})
const { branchName } = this.props.match.params;
const { limit } = this.state;
this.getCommitList(branchName , page , limit);
}
render(){
const { commitDatas , dataCount , limit , page , isSpining , branchList } = this.state;
const { projectDetail, commit_class , defaultBranch } = this.props;
const { projectsId , owner , branchName } = this.props.match.params;
let branch = returnbar(branchName || defaultBranch);
let branch = branchName || defaultBranch;
return(
<React.Fragment>
<div className={"main"}style={{padding:"0px",border:"none"}}>
@ -151,50 +121,46 @@ class CoderRootCommit extends Component{
></SelectBranch>
</div>
<Spin spinning={isSpining}>
<Timeline className="commitList">
<div className="commonBox">
<div className="commonBox-title">
<div className="f-wrap-between" style={{alignItems:"center"}}>
<span className="font-16">{dataCount}次提交代码({branch})</span>
</div>
</div>
<div className="commitList">
{
commitDatas && commitDatas.length > 0 && commitDatas.map((item,k)=>{
return(
<Timeline.Item key={k} dot={page ===1 && k===0 ?<span className="new-conmmit">最新</span>:<i className="iconfont icon-a-yuanquan2x"></i>}>
<div className="commitList-item f-wrap-between">
<div>
<AlignTop>
<div className="commitDesc"><Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="font-14 color-grey-3 font-bd"><RenderHtml value={item.message}/></Link></div>
</AlignTop>
<p className="f-wrap-alignCenter mt15 pb5">
<User
id={item.id}
url={(item.image_url && getImageUrl(`/${item.image_url}`)) || "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"}
name={item.name}
login={item.login}
/>
{item.timestamp && <label className="font-14 color-grey-3 ml3">提交于 {timeFormat(item.timestamp)}</label>}
<div key={k}>
<p className="f-wrap-alignCenter">
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="commitKey" style={{marginLeft:0}}>{truncateCommitId(`${item.sha}`)}</Link>
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="flex1 ml20 font-16 color-grey-3">{item.message}</Link>
</p>
<p className="f-wrap-alignCenter mt15">
{
item.id ?
<Link to={`/users/${item.login}`} className="show-user-link">
{item.image_url?<img src={getImageUrl(`/${item.image_url}`)} alt="" width="28px" height="28px" className="mr15 radius"/>:""}
<label className="font-14 color-grey-6" style={{verticalAlign:'middle'}}>{item.name ?`${item.name}:`:""}提交于 {item.time_from_now}</label>
</Link>:
<span className="show-user-link">
{item.image_url?<img src={getImageUrl(`/${item.image_url}`)} alt="" width="28px" height="28px" className="mr15 radius"/>:""}
<label className="font-14 color-grey-6" style={{verticalAlign:'middle'}}>{item.name ?`${item.name}:`:""}提交于 {item.time_from_now}</label>
</span>
}
</p>
</div>
<div>
<div className="treecopy">
<div>
<span className="treecopy-cont shadow">
<img src={Tree} alt="sha" width={"16px"}/>
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`}>{truncateCommitId(`${item.sha}`)}</Link>
<input type="text" id={`value${k}`} value={`${truncateCommitId(`${item.sha}`)}`}/>
</span>
<CopyTool beforeText="复制commit id" afterText="复制成功" inputId={`value${k}`}/>
</div>
<button className="btn-83" onClick={()=>{window.location.href=`/${owner}/${projectsId}/tree/${truncateCommitId(item.sha)}`}}>浏览文件</button>
</div>
</div>
</div>
</Timeline.Item>
)
})
}
{commitDatas && commitDatas.length === 0 && <Nodata _html="暂无数据"/>}
</Timeline>
</div>
</div>
{
dataCount > limit ?
<div className="edu-txt-center pt30 mb30">
<Pagination simple current={page} total={dataCount} pageSize={limit} onChange={this.ChangePage}></Pagination>
<Pagination simple defaultCurrent={page} total={dataCount} pageSize={limit} onChange={this.ChangePage}></Pagination>
</div>
:""
}

View File

@ -1,12 +1,10 @@
import React, { Component } from "react";
import { Popconfirm , Select , Dropdown , Spin , Anchor } from "antd";
import "./list.scss";
import { Popconfirm , Select } from "antd";
import "./list.css";
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,
@ -21,13 +19,11 @@ class CoderRootFileDetail extends Component {
value: undefined,
language: undefined,
languages: undefined,
description: props.detail.content,
menuList:undefined
description: props.detail.content
};
}
componentDidMount = () => {
window.scrollTo(0, 0);
const { detail , mdFlag } = this.props;
this.setState({
value: detail.content,
@ -153,7 +149,7 @@ class CoderRootFileDetail extends Component {
.then((result) => {
if (result) {
this.props.showNotification("删除成功!");
this.props.history.push(`/${owner}/${projectsId}`);
this.props.history.push(`/projects/${owner}/${projectsId}`);
}
})
.catch((error) => {
@ -173,31 +169,6 @@ class CoderRootFileDetail extends Component {
});
};
renderMenulist=()=>{
const { description } = this.state;
if(description){
const items = $.map($("#files-md").find("h1,h2,h3,h4,h5,h6"), function (el, _) {
const anchor = el.id;
const level = el.tagName.replace("H", "");
const href = `#${anchor}`;
return { href:`${href}`,text:el.textContent , level:level }
});
return items;
}
return [];
}
menu=()=>{
const menuList = this.renderMenulist();
if(menuList && menuList.length > 0){
return(
<ReadmeCatelogue menuList={menuList} hash={this.props.history.location.hash}/>
)
}else{
return <Spin />
}
}
render() {
const {
readOnly,
@ -215,18 +186,9 @@ class CoderRootFileDetail extends Component {
const Option = Select.Option;
return (
<React.Fragment>
<Anchor className="griditemAnchor" offsetTop={70}>
<div className="griditemCate">
{
md && readOnly &&
<Dropdown overlay={this.menu()} trigger={['hover']} overlayClassName="menuslist">
<span className="catelogue mr20">
<i className="iconfont icon-muluicon font-12 mr5"></i>
<span>目录</span>
</span>
</Dropdown>
}
<span className="color-grey-6 font-16">
<div className="grid-item branchTitle">
<div className="grid-item">
<span className="ml20 color-grey-6 font-16">
{bytesToSize(detail && detail.size)}
</span>
</div>
@ -296,7 +258,7 @@ class CoderRootFileDetail extends Component {
</div>
)}
</p>
</Anchor>
</div>
<div>
{detail.image_type ? (
<div className="edu-txt-center pt20 pb20">
@ -310,7 +272,7 @@ class CoderRootFileDetail extends Component {
</div>
) : (
md && readOnly ?
<div className="files-md" id="files-md">
<div className="files-md">
<RenderHtml className="file-md imageLayerParent" value={description} url={this.props.history.location}/>
</div>
:
@ -323,7 +285,6 @@ class CoderRootFileDetail extends Component {
readOnly={readOnly}
editorType="update"
currentBranch={currentBranch}
descName={detail && `Update ${detail.name}`}
></Meditor>
)}
</div>

View File

@ -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 './Index.scss';
import axios from 'axios';
const FileNew = Loadable({
loader: () => import('../Newfile/Index'),
@ -18,25 +18,25 @@ const CoderRootCommit = Loadable({
loading: Loading,
})
const CoderRootBranch = Loadable({
loader: () => import('./tree/Index'),
loader: () => import('./CoderRootBranch'),
loading: Loading,
})
const CoderRootTag = Loadable({
loader: () => import('./tag/Index'),
loader: () => import('./CoderRootTag'),
loading: Loading,
})
const CoderRootVersion = Loadable({
loader: () => import('./version/Index'),
loader: () => import('../Version/version'),
loading: Loading,
})
const CoderRootVersionNew = Loadable({
loader: () => import('../Version/New'),
loading: Loading,
})
const CoderRootVersionUpdate = Loadable({
loader: () => import('../Version/New'),
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,94 +50,89 @@ 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);
}
// 获取<Top />组件里要显示的数据
// 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(
<div className="coderSubPage">
{/* <Top {...this.props} {...this.state}/> */}
<div>
<Top {...this.props} {...this.state}/>
<Switch {...this.props}>
{/* 新建文件 */}
<Route path="/:owner/:projectsId/:branch/newfile/:path"
<Route path="/projects/:owner/:projectsId/:branch/newfile/:path"
render={
(props) => (<FileNew {...this.props} {...props} {...this.state} />)
}
></Route>
<Route path="/:owner/:projectsId/:branch/uploadfile"
<Route path="/projects/:owner/:projectsId/:branch/uploadfile"
render={
(props) => (<UploadFile {...this.props} {...props} {...this.state} />)
}
></Route>
<Route path="/:owner/:projectsId/:branch/newfile"
<Route path="/projects/:owner/:projectsId/:branch/newfile"
render={
(props) => (<FileNew {...this.props} {...props} {...this.state} />)
(props) => (<FileNew {...this.props} {...props} {...this.state} getTopCount={this.getTopCount} />)
}
></Route>
<Route path="/:owner/:projectsId/commits/branch/:branchName"
render={
() => (<CoderRootCommit {...this.props} {...this.state} commit_class="main" />)
}
></Route>
<Route path="/:owner/:projectsId/commits/:sha"
<Route path="/projects/:owner/:projectsId/commits/:sha"
render={
(props) => (<Diff {...this.props} {...props} {...this.state}/>)
}
></Route>
<Route path="/:owner/:projectsId/commits"
<Route path="/projects/:owner/:projectsId/commits"
render={
() => (<CoderRootCommit {...this.props} {...this.state} commit_class="main" />)
() => (<CoderRootCommit {...this.props} {...this.state} commit_class="main" getTopCount={this.getTopCount} />)
}
></Route>
{/* <Route path="/:owner/:projectsId/releases/:versionId/update"
<Route path="/projects/:owner/:projectsId/releases/:versionId/update"
render={
(props) => (<CoderRootVersionUpdate {...this.props} {...this.state} {...props} />)
}
></Route>
<Route path="/:owner/:projectsId/releases/new"
<Route path="/projects/:owner/:projectsId/releases/new"
render={
() => (<CoderRootVersionNew {...this.props} {...this.state} />)
}
></Route> */}
<Route path="/:owner/:projectsId/releases"
></Route>
<Route path="/projects/:owner/:projectsId/releases"
render={
() => (<CoderRootVersion {...this.props} {...this.state} />)
}
></Route>
<Route path="/:owner/:projectsId/tags"
<Route path="/projects/:owner/:projectsId/tag"
render={
() => (<CoderRootTag {...this.props} {...this.state} />)
}
></Route>
<Route path="/:owner/:projectsId/branches"
<Route path="/projects/:owner/:projectsId/branchs"
render={
() => (<CoderRootBranch {...this.props} {...this.state} />)
}

View File

@ -26,7 +26,7 @@ export default (( props, { projectDetail }) => {
}, [owner, projectsId]);
return (
<div className="main" style={{padding:"0px",border:"none"}}>
<div className="main">
<Spin spinning={isSpin}>
<div style={{minHeight:"400px"}}>
{
@ -34,7 +34,7 @@ export default (( props, { projectDetail }) => {
<div className="div_table">
<ul className="ul_thead">
<li>
<span className="flex1"></span>
<span className="flex1"></span>
<span>提交信息</span>
<span className="ul_tbody_forth">下载</span>
</li>
@ -49,7 +49,7 @@ export default (( props, { projectDetail }) => {
<span className="font-16">{item.name}</span>
</span>
<span className="ul_tbody_third">
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.id}`)}`} className="commitKey" style={{ "marginLeft": 0 }}>{truncateCommitId(`${item.id}`)}</Link>
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.id}`)}`} className="commitKey" style={{ "marginLeft": 0 }}>{truncateCommitId(`${item.id}`)}</Link>
</span>
<span className="ul_tbody_forth">
<a href={item.tarball_url} style={{ color: "#4CC1DA" }} className="mr30"><i className="iconfont icon-TAR font-18 mr5"></i>TAR</a>

View File

@ -1,14 +1,10 @@
import React, { Component } from 'react';
import { Spin, Tooltip } from 'antd';
import { Link, Route, Switch } from 'react-router-dom';
import { Content, AlignTop } from '../Component/layout';
import { Content } from '../Component/layout';
import DetailBanner from './sub/DetailBanner';
import { numFormat } from 'educoder';
import '../css/index.scss'
import './list.scss';
import { ImageLayerOfCommentHOC } from "../../modules/page/layers/ImageLayerOfCommentHOC";
import './list.css';
import Loadable from 'react-loadable';
import Loading from '../../Loading';
@ -71,7 +67,7 @@ const MergeIndexDetail = Loadable({
})
const CreateMerge = Loadable({
loader: () => import('../Merge/CreateMerge'),
loader: () => import('../Merge/NewMerge'),
loading: Loading,
})
@ -131,42 +127,30 @@ const Source = Loadable({
const DevIndex = Loadable({
loader: () => import('../DevOps/Index'),
loading: Loading,
});
const Wiki = Loadable({
loader: () => import('../Wiki/Index'),
loading: Loading,
});
const WikiEdit = Loadable({
loader: () => import('../Wiki/EditWiki'),
loading: Loading,
});
})
/**
* permissionManager:管理员Reporter报告人员(只有读取权限)Developer开发人员除不能设置仓库信息外
*/
function checkPathname(projectsId,owner,pathname){
let name = "";
if (pathname && pathname !== `/${owner}/${projectsId}`) {
let url = pathname.split(`/${owner}/${projectsId}`)[1] || "";
if(pathname && pathname !== `/projects/${owner}/${projectsId}`){
let url = pathname.split(`/projects/${owner}/${projectsId}`)[1];
if(url.indexOf("/about")>-1){
name="about"
}else if(url.indexOf("/issues")>-1 ||url.indexOf("Milepost") > 0){
name = "issues";
} else if (url.indexOf("/pulls") > -1 || url.indexOf("/compare") > -1) {
// /pulls合并请求除新建合并请求外
// /compare新建合并请求
}else if(url.indexOf("/pulls")>-1){
name="pulls"
}else if(url.indexOf("/milestones")>-1){
name="milestones"
}else if(url.indexOf("/activity")>-1){
name="activity"
} else if (url.indexOf("/settings") > -1) {
name = "settings"
}else if(url.indexOf("/setting")>-1){
name="setting"
}else if(url.indexOf(`/devops`)>-1){
name="devops"
}else if(url.indexOf(`/source`)>-1){
name="source"
} else if (url.indexOf(`/wiki`) > -1) {
name = "wiki"
}
}
return name;
@ -192,7 +176,6 @@ class Detail extends Component {
firstSync:false,
secondSync:false,
open_devops:false,
forkSpin: false,
// 默认分支
defaultBranch:undefined,
@ -231,7 +214,7 @@ class Detail extends Component {
if(num){
this.setState({
secondSync:true,
firstSync: false
firsrtSync:false
})
}else{
this.setState({
@ -239,12 +222,10 @@ class Detail extends Component {
secondSync:false
})
}
} else if (result.data.mirror_status === 2) {
this.deleteProjectBack();
}else{
this.getDetail();
this.setState({
firstSync: false,
firsrtSync:false,
secondSync:false
})
}
@ -258,18 +239,14 @@ class Detail extends Component {
open_devops:flag
})
}
/**
*
* @param {*} deleteFlag 同步镜像需要提示成功且未成功的情况下不需要删除项目
*/
canvasChannel = (deleteFlag) => {
canvasChannel = () => {
const name = window.location.hostname === "localhost" ? "testforgeplus.trustie.net" : window.location.hostname;
const actioncable = require("actioncable");
var project = this.state.project;
var cable = actioncable.createConsumer(`wss://${name}/cable`);
this.canvasChannel1 = cable.subscriptions.create({
channel: `MirrorProjectChannel`,
id: project && project.id
id: project && project.identifier
}, {
connected: () => {
console.log("###### channel connected! ######");
@ -277,53 +254,20 @@ class Detail extends Component {
disconnected: () => { },
received: data => {
console.log(`###### ---received data--- ######`);
console.log(data);
if (data) {
if(deleteFlag){
this.props.showNotification("镜像同步成功!");
window.location.reload();
}else{
if (data.project && data.project.mirror_status === 2) {
this.deleteProjectBack();
}
this.getDetail();
}
this.setState({
firstSync: false,
secondSync: false
});
cable.subscriptions.consumer.disconnect();
}
}
})
}
deleteProjectBack = () => {
const { history } = this.props;
const { projectsId, owner } = this.props.match.params;
axios.delete(`/${owner}/${projectsId}.json`).then(res => {
let hash = '/projects/mirror/new';
if (res && res.data) {
history.push({
pathname: hash,
mirror_status: 2
});
}
else {
window.location.hash = hash;
}
});
}
getDetail = () => {
const { projectsId , owner } = this.props.match.params;
this.getBanner();
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,
@ -414,24 +358,16 @@ class Detail extends Component {
forkFunc = () => {
const { platform } = this.state;
if(!platform)return;
this.setState({
forkSpin: true
})
const { current_user } = this.props
const { projectsId , owner } = this.props.match.params;
const url = `/${owner}/${projectsId}/forks.json`;
axios.post(url).then(result => {
if (result && result.data.status === 0) {
this.props.history.push(`/${current_user && current_user.login}/${result.data.identifier}`);
this.props.history.push(`/projects/${current_user && current_user.login}/${result.data.identifier}`);
this.props.showNotification(result.data.message);
}
this.setState({
forkSpin: false
})
}).catch(error => {
this.setState({
forkSpin: false
})
console.log(error);
})
}
@ -443,10 +379,8 @@ class Detail extends Component {
const url = `/${owner}/${projectsId}/sync_mirror.json`;
axios.post(url).then(result => {
if (result && result.data && result.data.status === 0) {
this.setState({
secondSync:true
})
this.canvasChannel(true);
this.props.showNotification("镜像同步成功!");
this.getProject(2);
} else {
this.props.showNotification("镜像同步失败!");
}
@ -455,33 +389,32 @@ class Detail extends Component {
})
}
textFunc = (forked_from_project_id, fork_info) => {
let type = fork_info && fork_info.fork_project_user_type;
return forked_from_project_id && fork_info ?
<div className="color-grey-9 df">
<span>复刻自</span>
<Link to={`/${fork_info.fork_project_user_login}`} className="show-user-link color-grey-6 ml5">{fork_info.fork_project_user_name}</Link>
<span> / </span>
<Link to={`/${fork_info.fork_project_user_login}/${fork_info.fork_project_identifier}`} className="color-grey-6 task-hide flex1" style={{ maxWidth: "400px" }} title={fork_info.fork_form_name}>{fork_info.fork_form_name}</Link>
</div> : ""
}
render() {
const { projectDetail, watchers_count, praises_count,
forked_count, firstSync , secondSync ,
isManager, watched, praised,
project, open_devops, platform, defaultBranch, bannerList, forkSpin } = this.state;
project , open_devops , platform , defaultBranch , bannerList } = this.state;
const url = this.props.history.location.pathname;
const urlArr = url.split("/");
const urlFlag = (urlArr.length === 3);
const { projectsId , owner } = this.props.match.params;
const { current_user } = this.props;
let pathname = checkPathname(projectsId,owner,url);
const { state } = this.props.history.location;
const text = (
projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ?
<React.Fragment>
<span>forked from </span>
<Link to={`/users/${projectDetail.fork_info.fork_project_user_login}`} className="show-user-link color-grey-ccc">{projectDetail.fork_info.fork_project_user_name}</Link>
<span> / </span>
<Link to={`/projects/${projectDetail.fork_info.fork_project_user_login}/${projectDetail.fork_info.fork_project_identifier}`} className="color-grey-ccc">{projectDetail.fork_info.fork_form_name}</Link>
</React.Fragment> : ""
);
const common = {
getDetail: this.getDetail,
changeOpenDevops:this.changeOpenDevops,
@ -491,37 +424,44 @@ class Detail extends Component {
<div>
<div className="detailHeader-wrapper">
<div className="normal">
<AlignTop style={{ padding: "18px 0px 10px", justifyContent: "space-between" }}>
<div>
<AlignTop>
<div className="projectallName">
<div className="f-wrap-between pb15" style={{ position: "relative" }}>
<p className="font-22 df flex-1 lineH2 mt15" style={{ alignItems: "center" }}>
{project && project.author &&
<Link to={`/${project.author.login}`}>{project.author.name}</Link>
<Link to={`${project.author.type ==="Organization" ? "/organize":'/users'}/${project.author.login}`} className="show-user-link">
{project.author.name}
</Link>
}
<span className="ml5 mr5">/</span>
<Link to={`/${owner}/${projectsId}`} className="projectN mt6">{projectDetail && projectDetail.name}</Link>
</div>
{projectDetail && projectDetail.private && <span className="privateTag mt6">私有</span>}
</AlignTop>
<div className="mt8">
<span className="hide-1 flex-1 df">
<Link to={`/projects/${owner}/${projectsId}`} className="font-22">{project && project.name}</Link>
{
projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ?
this.textFunc(projectDetail.forked_from_project_id, projectDetail.fork_info)
: ""
<Tooltip placement={'right'} title={text}>
<Link to={`/projects/${projectDetail.fork_info.fork_project_user_login}/${projectDetail.fork_info.fork_project_identifier}`}
className="ml10" >
<i className="iconfont icon-fork font-18 fl mt6" style={{ color: "#8D90E3" }}></i>
</Link>
</Tooltip> : ""
}
{
projectDetail && projectDetail.type && projectDetail.type !== 0 ?
<span className="color-grey-9">导入于 <a className="color-grey-6" target="_blank" href={projectDetail.mirror_url}>{projectDetail.mirror_url}</a></span>
projectDetail.type === 2 ?
<Tooltip title={"镜像自: " + projectDetail.mirror_url} className="ml5" placement={'right'}>
<i className="iconfont icon-banbenku font-18 mt6" style={{ color: "#8D90E3" }}/>
</Tooltip>
:
<Tooltip title={"镜像自: " + projectDetail.mirror_url} className="ml5" placement={'right'}>
<i className="iconfont icon-jingxiang font-18 color-green mt6" />
</Tooltip>
:""
}
</div>
</div>
<div>
</span>
</p>
{
firstSync ? "":
<span className="df">
<span className="df mt25">
{
((current_user && current_user.admin) || isManager) && (projectDetail && projectDetail.type && projectDetail.type === 2) ?
projectDetail && projectDetail.type && projectDetail.type === 2 ?
<a className="synchronism ml30" onClick={this.synchronismMirror}>同步镜像</a> : ""
}
<span className="detail_tag_btn">
@ -532,7 +472,7 @@ class Detail extends Component {
{
watchers_count > 0 ?
platform ?
<Link className="detail_tag_btn_count" style={{ color: `#666` }} to={platform ? { pathname: `/${owner}/${projectsId}/following`, state } : ""}>
<Link className="detail_tag_btn_count" style={{color:`${watched?"#2878FF":"#666"}`}} to={platform?{ pathname: `/projects/${owner}/${projectsId}/watchers`, state }:""}>
{watchers_count}
</Link>
:
@ -548,23 +488,23 @@ class Detail extends Component {
{
praises_count > 0 ?
platform ?
<Link className="detail_tag_btn_count" style={{ color: `#666` }} to={{ pathname: `/${owner}/${projectsId}/stargazers`, state }}>
<Link className="detail_tag_btn_count" style={{color:`${praised?"#2878FF":"#666"}`}} to={{ pathname: `/projects/${owner}/${projectsId}/stargazers`, state }}>
{praises_count}
</Link>:
<span className="detail_tag_btn_count">{praises_count}</span>
:""
}
</span>
<span className="detail_tag_btn" loading={forkSpin}>
<span className="detail_tag_btn">
<Tooltip title="复刻是fork的中文名即复制代码仓库" placement="bottom">
<a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={this.forkFunc}>
<i className="iconfont icon-fork color-grey-9 mr3 font-16"></i><span>(Fork)</span>
<i className="iconfont icon-fork color-grey-9 mr3"></i>
</a>
</Tooltip>
{
forked_count > 0 ?
platform ?
<Link className="detail_tag_btn_count" to={{ pathname: `/${owner}/${projectsId}/members`, state }}>
<Link className="detail_tag_btn_count" to={{ pathname: `/projects/${owner}/${projectsId}/fork_users`, state }}>
{forked_count}
</Link>
:
@ -575,19 +515,6 @@ class Detail extends Component {
</span>
}
</div>
</AlignTop>
{/* <div className="mt6" style={{minHeight:"20px"}}>
{
projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ?
this.textFunc(projectDetail.forked_from_project_id,projectDetail.fork_info)
:""
}
{
projectDetail && projectDetail.type && projectDetail.type !== 0 ?
<span className="color-grey-9">镜像自 <a className="color-blue hoverLine" target="_blank" href={projectDetail.mirror_url}>{projectDetail.mirror_url}</a></span>
:""
}
</div> */}
{
firstSync ? "" :
<DetailBanner
@ -615,202 +542,167 @@ class Detail extends Component {
<Spin spinning={secondSync} className="spinstyle" tip="正在同步镜像" size="large">
<Switch {...this.props}>
{/* 资源 */}
<Route path="/:owner/:projectsId/source"
<Route path="/projects/:owner/:projectsId/source"
render={
() => (<Source {...this.props} {...this.state} {...common} />)
}
></Route>
{/* 主页 */}
<Route path="/:owner/:projectsId/about"
<Route path="/projects/:owner/:projectsId/about"
render={
() => (<DevAbout {...this.props} {...this.state} {...common} />)
}
></Route>
{/* wiki新增文件 */}
<Route path="/:owner/:projectsId/wiki/add"
render={
() => (<WikiEdit {...this.props} {...this.state} {...common} />)
}
></Route>
{/* wiki编辑文件 */}
<Route path="/:owner/:projectsId/wiki/edit/:wikiName"
render={
() => (<WikiEdit {...this.props} {...this.state} {...common} />)
}
></Route>
{/* wiki */}
<Route path="/:owner/:projectsId/wiki"
render={
() => (<Wiki {...this.props} {...this.state} {...common} />)
}
></Route>
{/* 工作流 */}
<Route path="/:owner/:projectsId/devops"
<Route path="/projects/:owner/:projectsId/devops"
render={
() => (<DevIndex {...this.props} {...this.state} {...common} />)
}
></Route>
{/* 标签列表 */}
<Route path="/:owner/:projectsId/issues/tags"
<Route path="/projects/:owner/:projectsId/issues/tags"
render={
(props) => (<TagList {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/* 仓库设置 */}
<Route path="/:owner/:projectsId/settings"
<Route path="/projects/:owner/:projectsId/setting"
render={
(props) => (<Setting {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/* 任务详情 */}
<Route path="/projects/:owner/:projectsId/issues/:orderId/detail"
render={
(props) => (<OrderDetail {...this.props} {...this.state} {...props} {...common} />)
}
></Route>
{/*修改里程碑*/}
<Route path="/:owner/:projectsId/milestones/:meilid/edit"
<Route path="/projects/:owner/:projectsId/milestones/:meilid/edit"
render={
(props) => (<OrderupdateMilepost {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/* 新建里程碑 */}
<Route path="/:owner/:projectsId/milestones/new"
<Route path="/projects/:owner/:projectsId/milestones/new"
render={
(props) => (<OrdernewMilepost {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/*里程碑详情*/}
<Route path="/:owner/:projectsId/milestones/:meilid"
<Route path="/projects/:owner/:projectsId/milestones/:meilid"
render={
(props) => (<MilepostDetail {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/* 里程碑 */}
<Route path="/:owner/:projectsId/milestones"
<Route path="/projects/:owner/:projectsId/milestones"
render={
(props) => (<OrderMilepost {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/* 里程碑页面新建任务 */}
<Route path="/:owner/:projectsId/issues/:milepostId/new"
<Route path="/projects/:owner/:projectsId/issues/:milepostId/new"
render={
(props) => (<OrderNew {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/* 新建任务 */}
<Route path="/:owner/:projectsId/issues/new"
<Route path="/projects/:owner/:projectsId/issues/new"
render={
(props) => (<OrderNew {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/* 修改详情 updatedetail*/}
<Route path="/:owner/:projectsId/issues/:orderId/:operateName"
{/* 修改详情 */}
<Route path="/projects/:owner/:projectsId/issues/:orderId/updatedetail"
render={
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/* 复制详情 copyetail*/}
<Route path="/:owner/:projectsId/issues/:orderId/copyetail"
{/* 复制详情 */}
<Route path="/projects/:owner/:projectsId/issues/:orderId/copyetail"
render={
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/* 任务详情 */}
<Route path="/:owner/:projectsId/issues/:orderId"
render={
(props) => (<OrderDetail {...this.props} {...this.state} {...props} {...common} />)
(props) => (<OrdercopyDetail {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/* 动态 */}
<Route path="/:owner/:projectsId/activity"
<Route path="/projects/:owner/:projectsId/activity"
render={
(props) => (<TrendsIndex {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/* 代码Index */}
<Route path="/:owner/:projectsId/issues"
<Route path="/projects/:owner/:projectsId/issues"
render={
(props) => (<OrderIndex {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/* 新建合并请求 */}
{/* <Route path="/:owner/:projectsId/compare/:branch"
render={
(props) => (<CreateMerge {...this.props} {...props} {...this.state} {...common} is_fork={true} />)
}
></Route> */}
<Route path="/:owner/:projectsId/compare"
<Route path="/projects/:owner/:projectsId/pulls/new"
render={
(props) => (<CreateMerge {...this.props} {...props} {...this.state} {...common} is_fork={true} />)
}
></Route>
<Route path="/:owner/:projectsId/pulls/:mergeId/edit"
<Route path="/projects/:owner/:projectsId/pulls/:mergeId/UpdateMerge"
render={
(props) => (<UpdateMerge {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
<Route path="/:owner/:projectsId/pulls/:mergeId"
<Route path="/projects/:owner/:projectsId/pulls/:mergeId/Messagecount"
render={
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
<Route path="/:owner/:projectsId/pulls/:mergeId/commits"
render={
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
<Route path="/:owner/:projectsId/pulls/:mergeId/files"
render={
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
<Route path="/:owner/:projectsId/pulls/:mergeId/MergeSubmit"
<Route path="/projects/:owner/:projectsId/pulls/:mergeId/MergeSubmit"
render={
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
<Route path="/:owner/:projectsId/pulls"
<Route path="/projects/:owner/:projectsId/pulls"
render={
(props) => (<MergeIndexDetail {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
<Route path="/:owner/:projectsId/following"
<Route path="/projects/:owner/:projectsId/watchers"
render={
(props) => (<WatchUsers {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
<Route path="/:owner/:projectsId/stargazers"
<Route path="/projects/:owner/:projectsId/stargazers"
render={
(props) => (<PraiseUsers {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
<Route path="/:owner/:projectsId/members"
<Route path="/projects/:owner/:projectsId/fork_users"
render={
(props) => (<ForkUsers {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
{/* 贡献者列表 */}
<Route path="/:owner/:projectsId/contribute"
<Route path="/projects/:owner/:projectsId/contribute"
render={
() => (<Contribute {...this.props} {...this.state} {...common} />)
}
></Route>
{/* 代码库----详情页面 */}
<Route path="/:owner/:projectsId/commits/branch/:branchName"
<Route path="/projects/:owner/:projectsId/commits/branch/:branchName"
render={
(props) => (<CoderRootCommit {...this.props} {...props} {...this.state} {...common}/>)
}
></Route>
<Route path="/:owner/:projectsId/tree/:branchName"
<Route path="/projects/:owner/:projectsId/tree/:branchName"
render={
(props) => (<CoderDepot {...this.props} {...props} {...this.state} {...common}/>)
}
></Route>
<Route path="/:owner/:projectsId/:subIndex"
<Route path="/projects/:owner/:projectsId/:subIndex"
render={
(props) => (<CoderRootIndex {...this.props} {...props} {...this.state} {...common}/>)
}
></Route>
<Route path="/:owner/:projectsId"
<Route path="/projects/:owner/:projectsId"
render={
(props) => (<CoderDepot {...this.props} {...props} {...this.state} {...common}/>)
}
@ -823,7 +715,4 @@ class Detail extends Component {
}
}
export default ImageLayerOfCommentHOC({
imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget",
parentSelector: ".newContainer",
})(Detail);
export default Detail;

Some files were not shown because too many files have changed in this diff Show More