diff --git a/README.md b/README.md new file mode 100644 index 00000000..cc5d75f8 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +
1、 安装node v6.9.x;此安装包含了node和npm。
+2、 安装cnpm(命令行): npm install -g cnpm --registry=https://registry.npm.taobao.org
+3、 安装依赖的js库(public/react目录下<即项目package.json所在目录>,开启命令行): cnpm install
+4、 如果你的ruby服务使用的是3000端口,则需要在package.json中修改"port"参数的值
+5、 启动服务(命令行-目录同3): npm start
+6、 build初始化 npm run build
+ + +相关代码提交到对应分支,能上线的代码先提交到develop分支上测试版,测试通过后合并提交到master分支上线正式版
+master:开发环境(正式环境)
+develop:测试环境
+dev_local:本地版本
+dev_chain:含有区块链相关内容的分支
+PS:新增加的需求功能先新建新分支开发,在测试版测试没问题后再分别合并到develop和master分支
\ No newline at end of file diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js index 838da647..a7b2c9f4 100644 --- a/config/webpack.config.prod.js +++ b/config/webpack.config.prod.js @@ -17,16 +17,7 @@ const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); const paths = require("./paths"); const getClientEnvironment = require("./env"); -// Some apps do not use client-side routing with pushState. -// For these, "homepage" can be set to "." to enable relative asset paths. let publicPath = "/react/build/"; -// let nodeEnv = process.env.NODE_ENV -// if (nodeEnv === 'testBuild') { -// publicPath = 'https://testforgeplus.trustie.net/react/build/'; -// } -// if (nodeEnv === 'production') { -// publicPath = 'https://forgeplus.trustie.net/react/build/'; -// } const publicUrl = publicPath.slice(0, -1); const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false"; const env = getClientEnvironment(publicPath); @@ -141,7 +132,6 @@ module.exports = { name: "static/media/[name].[hash:8].[ext]", }, }, - // Process JS with Babel. { test: /\.(js|jsx|mjs)$/, include: paths.appSrc, @@ -161,10 +151,8 @@ module.exports = { ], }, }, - { test: /\.css$/, - use: [ { loader: MiniCssExtractPlugin.loader, diff --git a/package-lock.json b/package-lock.json index 0c961a83..471fc99c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,21 +1,21 @@ { - "name": "educoder", - "version": "0.1.0", + "name": "forge", + "version": "3.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@ant-design/colors": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-3.2.2.tgz", - "integrity": "sha512-YKgNbG2dlzqMhA9NtI3/pbY16m3Yl/EeWBRa+lB1X1YaYxHrxNexiQYCLTWO/uDvAjLFMEDU+zR901waBtMtjQ==", + "resolved": "https://registry.npm.taobao.org/@ant-design/colors/download/@ant-design/colors-3.2.2.tgz?cache=0&sync_timestamp=1612935637470&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40ant-design%2Fcolors%2Fdownload%2F%40ant-design%2Fcolors-3.2.2.tgz", + "integrity": "sha1-WtQ9YZ6RHzSI66wwPWBuZqhCOQM=", "requires": { "tinycolor2": "^1.4.1" } }, "@ant-design/create-react-context": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@ant-design/create-react-context/-/create-react-context-0.2.5.tgz", - "integrity": "sha512-1rMAa4qgP2lfl/QBH9i78+Gjxtj9FTMpMyDGZsEBW5Kih72EuUo9958mV8PgpRkh4uwPSQ7vVZWXeyNZXVAFDg==", + "resolved": "https://registry.npm.taobao.org/@ant-design/create-react-context/download/@ant-design/create-react-context-0.2.5.tgz", + "integrity": "sha1-9fWpFjtHcgl3EoNzl60w4i55+Fg=", "requires": { "gud": "^1.0.0", "warning": "^4.0.3" @@ -23,18 +23,18 @@ }, "@ant-design/css-animation": { "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@ant-design/css-animation/-/css-animation-1.7.3.tgz", - "integrity": "sha512-LrX0OGZtW+W6iLnTAqnTaoIsRelYeuLZWsrmBJFUXDALQphPsN8cE5DCsmoSlL0QYb94BQxINiuS70Ar/8BNgA==" + "resolved": "https://registry.npm.taobao.org/@ant-design/css-animation/download/@ant-design/css-animation-1.7.3.tgz?cache=0&sync_timestamp=1596106749762&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40ant-design%2Fcss-animation%2Fdownload%2F%40ant-design%2Fcss-animation-1.7.3.tgz", + "integrity": "sha1-YKHJcAFOhrKPlAUQ1p5QPkKPETY=" }, "@ant-design/icons": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-2.1.1.tgz", - "integrity": "sha512-jCH+k2Vjlno4YWl6g535nHR09PwCEmTBKAG6VqF+rhkrSPRLfgpU2maagwbZPLjaHuU5Jd1DFQ2KJpQuI6uG8w==" + "resolved": "https://registry.npm.taobao.org/@ant-design/icons/download/@ant-design/icons-2.1.1.tgz", + "integrity": "sha1-e5wI3/1PXUHbZn2dvl4BB9C9mko=" }, "@ant-design/icons-react": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@ant-design/icons-react/-/icons-react-2.0.1.tgz", - "integrity": "sha512-r1QfoltMuruJZqdiKcbPim3d8LNsVPB733U0gZEUSxBLuqilwsW28K2rCTWSMTjmFX7Mfpf+v/wdiFe/XCqThw==", + "resolved": "https://registry.npm.taobao.org/@ant-design/icons-react/download/@ant-design/icons-react-2.0.1.tgz", + "integrity": "sha1-F6JRNXGrMXrKKSfljOol3THlNvs=", "requires": { "@ant-design/colors": "^3.1.0", "babel-runtime": "^6.26.0" @@ -450,8 +450,8 @@ }, "@types/react-slick": { "version": "0.23.4", - "resolved": "https://registry.npmjs.org/@types/react-slick/-/react-slick-0.23.4.tgz", - "integrity": "sha512-vXoIy4GUfB7/YgqubR4H7RALo+pRdMYCeLgWwV3MPwl5pggTlEkFBTF19R7u+LJc85uMqC7RfsbkqPLMQ4ab+A==", + "resolved": "https://registry.npm.taobao.org/@types/react-slick/download/@types/react-slick-0.23.4.tgz", + "integrity": "sha1-yX4qnn49GTPGhZO46CdS+rHozlM=", "requires": { "@types/react": "*" } @@ -867,9 +867,9 @@ } }, "antd": { - "version": "3.26.16", - "resolved": "https://registry.npmjs.org/antd/-/antd-3.26.16.tgz", - "integrity": "sha512-EYRwlEf8FCPCVRk5yDcgjSZOC0exu+m75SwlSQU+Mh17f9wGhLeL2/DV7/Sra1r+BZlfiahFdkgrLY7UgMMBEQ==", + "version": "3.26.20", + "resolved": "https://registry.nlark.com/antd/download/antd-3.26.20.tgz", + "integrity": "sha1-8/Vw76qllQoUSULyHrKqqgiOlAc=", "requires": { "@ant-design/create-react-context": "^0.2.4", "@ant-design/icons": "~2.1.1", @@ -929,16 +929,16 @@ "dependencies": { "raf": { "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "resolved": "https://registry.npm.taobao.org/raf/download/raf-3.4.1.tgz", + "integrity": "sha1-B0LpmkplUvRF1z4+4DKK8P8e3jk=", "requires": { "performance-now": "^2.1.0" } }, "rc-pagination": { - "version": "1.20.14", - "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-1.20.14.tgz", - "integrity": "sha512-sNKwbFrxiqATqcIIShfrFs8BT03n4UUwTAMYae+JhHTmILQmXdvimEnZbVuWcno6G02DAJcLrFpmkn1h2tmEJw==", + "version": "1.20.15", + "resolved": "https://registry.npm.taobao.org/rc-pagination/download/rc-pagination-1.20.15.tgz", + "integrity": "sha1-zLTNDpvU5H9y8p6kMsA1C/ez2Ac=", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.6", @@ -948,8 +948,8 @@ }, "rc-rate": { "version": "2.5.1", - "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.5.1.tgz", - "integrity": "sha512-3iJkNJT8xlHklPCdeZtUZmJmRVUbr6AHRlfSsztfYTXVlHrv2TcPn3XkHsH+12j812WVB7gvilS2j3+ffjUHXg==", + "resolved": "https://registry.npm.taobao.org/rc-rate/download/rc-rate-2.5.1.tgz?cache=0&sync_timestamp=1605573559401&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-rate%2Fdownload%2Frc-rate-2.5.1.tgz", + "integrity": "sha1-Vfxf0j6p3MciULmoiYA0efSEKWE=", "requires": { "classnames": "^2.2.5", "prop-types": "^15.5.8", @@ -959,8 +959,8 @@ }, "rc-select": { "version": "9.2.3", - "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-9.2.3.tgz", - "integrity": "sha512-WhswxOMWiNnkXRbxyrj0kiIvyCfo/BaRPaYbsDetSIAU2yEDwKHF798blCP5u86KLOBKBvtxWLFCkSsQw1so5w==", + "resolved": "https://registry.nlark.com/rc-select/download/rc-select-9.2.3.tgz?cache=0&sync_timestamp=1618886345948&other_urls=https%3A%2F%2Fregistry.nlark.com%2Frc-select%2Fdownload%2Frc-select-9.2.3.tgz", + "integrity": "sha1-ZDQOLW72TovDz8b0aP/ShiVYmsI=", "requires": { "babel-runtime": "^6.23.0", "classnames": "2.x", @@ -978,8 +978,8 @@ }, "rc-tree": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-2.1.4.tgz", - "integrity": "sha512-Xey794Iavgs8YldFlXcZLOhfcIhlX5Oz/yfKufknBXf2AlZCOkc7aHqSM9uTF7fBPtTGPhPxNEfOqHfY7b7xng==", + "resolved": "https://registry.npm.taobao.org/rc-tree/download/rc-tree-2.1.4.tgz?cache=0&sync_timestamp=1615350038621&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-tree%2Fdownload%2Frc-tree-2.1.4.tgz", + "integrity": "sha1-73WfPnmaIbQ8Hs+ceU6hwU5wtZs=", "requires": { "@ant-design/create-react-context": "^0.2.4", "classnames": "2.x", @@ -989,6 +989,18 @@ "react-lifecycles-compat": "^3.0.4", "warning": "^4.0.3" } + }, + "react-slick": { + "version": "0.25.2", + "resolved": "https://registry.nlark.com/react-slick/download/react-slick-0.25.2.tgz", + "integrity": "sha1-VjMbZ9R9i8/i3OtqyrHI/VvR9rw=", + "requires": { + "classnames": "^2.2.5", + "enquire.js": "^2.1.6", + "json2mq": "^0.2.0", + "lodash.debounce": "^4.0.8", + "resize-observer-polyfill": "^1.5.0" + } } } }, @@ -1087,8 +1099,8 @@ }, "array-tree-filter": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz", - "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==" + "resolved": "https://registry.npm.taobao.org/array-tree-filter/download/array-tree-filter-2.1.0.tgz", + "integrity": "sha1-hzrAD+yDdJ8lWsjdCDgUtPYykZA=" }, "array-union": { "version": "1.0.2", @@ -2053,8 +2065,8 @@ }, "babel-plugin-transform-runtime": { "version": "6.23.0", - "resolved": "https://registry.npm.taobao.org/babel-plugin-transform-runtime/download/babel-plugin-transform-runtime-6.23.0.tgz", - "integrity": "sha512-cpGMVC1vt/772y3jx1gwSaTitQVZuFDlllgreMsZ+rTYC6jlYXRyf5FQOgSnckOiA5QmzbXTyBY2A5AmZXF1fA==", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz", + "integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=", "requires": { "babel-runtime": "^6.22.0" } @@ -2072,7 +2084,6 @@ "version": "6.26.0", "resolved": "https://registry.npm.taobao.org/babel-polyfill/download/babel-polyfill-6.26.0.tgz", "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", - "dev": true, "requires": { "babel-runtime": "^6.26.0", "core-js": "^2.5.0", @@ -2082,8 +2093,7 @@ "regenerator-runtime": { "version": "0.10.5", "resolved": "https://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.10.5.tgz?cache=0&sync_timestamp=1595456367497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.10.5.tgz", - "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", - "dev": true + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" } } }, @@ -2174,8 +2184,8 @@ }, "babel-preset-react": { "version": "6.24.1", - "resolved": "https://registry.npm.taobao.org/babel-preset-react/download/babel-preset-react-6.24.1.tgz", - "integrity": "sha512-phQe3bElbgF887UM0Dhz55d22ob8czTL1kbhZFwpCE6+R/X9kHktfwmx9JZb+bBSVRGphP5tZ9oWhVhlgjrX3Q==", + "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz", + "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=", "requires": { "babel-plugin-syntax-jsx": "^6.3.13", "babel-plugin-transform-react-display-name": "^6.23.0", @@ -2372,6 +2382,12 @@ } } }, + "base16": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/base16/download/base16-1.0.0.tgz", + "integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=", + "dev": true + }, "base64-js": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", @@ -3770,8 +3786,8 @@ }, "copy-to-clipboard": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz", - "integrity": "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==", + "resolved": "https://registry.npm.taobao.org/copy-to-clipboard/download/copy-to-clipboard-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcopy-to-clipboard%2Fdownload%2Fcopy-to-clipboard-3.3.1.tgz", + "integrity": "sha1-EVqhqZmP+rYZb5MHatbaO5E2Yq4=", "requires": { "toggle-selection": "^1.0.6" } @@ -3863,6 +3879,23 @@ "warning": "^4.0.3" } }, + "cross-fetch": { + "version": "3.1.4", + "resolved": "https://registry.nlark.com/cross-fetch/download/cross-fetch-3.1.4.tgz", + "integrity": "sha1-lyPzo6JHv4uJA586OAqSROj6Lzk=", + "dev": true, + "requires": { + "node-fetch": "2.6.1" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.nlark.com/node-fetch/download/node-fetch-2.6.1.tgz?cache=0&sync_timestamp=1626684741221&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fnode-fetch%2Fdownload%2Fnode-fetch-2.6.1.tgz", + "integrity": "sha1-BFvTI2Mfdu0uK1VXM5RBa2OaAFI=", + "dev": true + } + } + }, "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -5115,6 +5148,11 @@ "domelementtype": "1" } }, + "dompurify": { + "version": "2.0.15", + "resolved": "https://registry.npm.taobao.org/dompurify/download/dompurify-2.0.15.tgz?cache=0&sync_timestamp=1607352578938&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdompurify%2Fdownload%2Fdompurify-2.0.15.tgz", + "integrity": "sha1-gOMA/D6JVHvQrxr/LrqIzhf8neo=" + }, "domutils": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", @@ -5161,8 +5199,8 @@ }, "draft-js": { "version": "0.10.5", - "resolved": "https://registry.npmjs.org/draft-js/-/draft-js-0.10.5.tgz", - "integrity": "sha512-LE6jSCV9nkPhfVX2ggcRLA4FKs6zWq9ceuO/88BpXdNCS7mjRTgs0NsV6piUCJX9YxMsB9An33wnkMmU2sD2Zg==", + "resolved": "https://registry.npm.taobao.org/draft-js/download/draft-js-0.10.5.tgz", + "integrity": "sha1-v6m+sBj+BTPbsI1mdcNxprCPp0I=", "requires": { "fbjs": "^0.8.15", "immutable": "~3.7.4", @@ -5201,13 +5239,18 @@ } }, "echarts": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/echarts/-/echarts-4.7.0.tgz", - "integrity": "sha512-NlOTdUcAsIyCCG+N4uh0ZEvXtrPW2jvcuqf03RyqYeCKzyPbiOQ4I3MdKXMhxG3lBdqQNdNXVT71SB4KTQjN0A==", + "version": "4.9.0", + "resolved": "https://registry.nlark.com/echarts/download/echarts-4.9.0.tgz", + "integrity": "sha1-qbm6oD8Doqcx5jQMVb77V6nhNH0=", "requires": { - "zrender": "4.3.0" + "zrender": "4.3.2" } }, + "echarts-wordcloud": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/echarts-wordcloud/download/echarts-wordcloud-2.0.0.tgz?cache=0&sync_timestamp=1610779172014&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fecharts-wordcloud%2Fdownload%2Fecharts-wordcloud-2.0.0.tgz", + "integrity": "sha1-Uu+BeJWAH/6emd0brKt2hrLewEo=" + }, "editor.md": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/editor.md/-/editor.md-1.5.0.tgz", @@ -6350,6 +6393,41 @@ "bser": "2.1.1" } }, + "fbemitter": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/fbemitter/download/fbemitter-3.0.0.tgz", + "integrity": "sha1-ALKhr1QRJUqrQWzXX55iib7kv/M=", + "dev": true, + "requires": { + "fbjs": "^3.0.0" + }, + "dependencies": { + "fbjs": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/fbjs/download/fbjs-3.0.0.tgz?cache=0&sync_timestamp=1602048313843&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffbjs%2Fdownload%2Ffbjs-3.0.0.tgz", + "integrity": "sha1-CQcGf7P1enj0XZXx6s/8rNYjwWU=", + "dev": true, + "requires": { + "cross-fetch": "^3.0.4", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npm.taobao.org/promise/download/promise-7.3.1.tgz", + "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", + "dev": true, + "requires": { + "asap": "~2.0.3" + } + } + } + }, "fbjs": { "version": "0.8.17", "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", @@ -6379,6 +6457,12 @@ } } }, + "fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/fbjs-css-vars/download/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha1-IWVRE2rgL+JVkyw+yHdfGOLAeLg=", + "dev": true + }, "fecha": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", @@ -6823,6 +6907,42 @@ "readable-stream": "^2.3.6" } }, + "flux": { + "version": "4.0.1", + "resolved": "https://registry.npm.taobao.org/flux/download/flux-4.0.1.tgz", + "integrity": "sha1-eENQKwKEHUqqU0rws3MDSh917lw=", + "dev": true, + "requires": { + "fbemitter": "^3.0.0", + "fbjs": "^3.0.0" + }, + "dependencies": { + "fbjs": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/fbjs/download/fbjs-3.0.0.tgz?cache=0&sync_timestamp=1602048313843&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffbjs%2Fdownload%2Ffbjs-3.0.0.tgz", + "integrity": "sha1-CQcGf7P1enj0XZXx6s/8rNYjwWU=", + "dev": true, + "requires": { + "cross-fetch": "^3.0.4", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npm.taobao.org/promise/download/promise-7.3.1.tgz", + "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", + "dev": true, + "requires": { + "asap": "~2.0.3" + } + } + } + }, "flv.js": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/flv.js/-/flv.js-1.5.0.tgz", @@ -9328,9 +9448,9 @@ } }, "is-mobile": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-2.2.1.tgz", - "integrity": "sha512-6zELsfVFr326eq2CI53yvqq6YBanOxKBybwDT+MbMS2laBnK6Ez8m5XHSuTQQbnKRfpDzCod1CMWW5q3wZYMvA==" + "version": "2.2.2", + "resolved": "https://registry.nlark.com/is-mobile/download/is-mobile-2.2.2.tgz", + "integrity": "sha1-9snF1Q7gElTOBec5vdg18e1OmVQ=" }, "is-npm": { "version": "1.0.0", @@ -10036,6 +10156,11 @@ "esprima": "^4.0.0" } }, + "js2wordcloud": { + "version": "1.1.12", + "resolved": "https://registry.npm.taobao.org/js2wordcloud/download/js2wordcloud-1.1.12.tgz", + "integrity": "sha1-8BdC2k5qyzAAsoY1dmQWjvn8o64=" + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -10458,6 +10583,12 @@ "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=" }, + "lodash.curry": { + "version": "4.1.1", + "resolved": "https://registry.npm.taobao.org/lodash.curry/download/lodash.curry-4.1.1.tgz", + "integrity": "sha1-JI42By7ekGUB11lmIAqG2riyMXA=", + "dev": true + }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -10468,6 +10599,12 @@ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" }, + "lodash.flow": { + "version": "3.5.0", + "resolved": "https://registry.npm.taobao.org/lodash.flow/download/lodash.flow-3.5.0.tgz", + "integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=", + "dev": true + }, "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", @@ -11557,8 +11694,8 @@ }, "omit.js": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/omit.js/-/omit.js-1.0.2.tgz", - "integrity": "sha512-/QPc6G2NS+8d4L/cQhbk6Yit1WTB6Us2g84A7A/1+w9d/eRGHyEqC5kkQtHVoHZ5NFWGG7tUGgrhVZwgZanKrQ==", + "resolved": "https://registry.npm.taobao.org/omit.js/download/omit.js-1.0.2.tgz", + "integrity": "sha1-kaFPDrqEBm36AVvzDkdMR/MLyFg=", "requires": { "babel-runtime": "^6.23.0" } @@ -14098,6 +14235,12 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, + "pure-color": { + "version": "1.3.0", + "resolved": "https://registry.npm.taobao.org/pure-color/download/pure-color-1.3.0.tgz", + "integrity": "sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=", + "dev": true + }, "purgecss": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-2.1.2.tgz", @@ -14172,9 +14315,9 @@ "integrity": "sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8=" }, "qrcode.react": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-1.0.0.tgz", - "integrity": "sha512-jBXleohRTwvGBe1ngV+62QvEZ/9IZqQivdwzo9pJM4LQMoCM2VnvNBnKdjvGnKyDZ/l0nCDgsPod19RzlPvm/Q==", + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/qrcode.react/download/qrcode.react-1.0.1.tgz", + "integrity": "sha1-KDS7UOXidf/lr2kG7/FTkf6eOKU=", "requires": { "loose-envify": "^1.4.0", "prop-types": "^15.6.0", @@ -14361,9 +14504,9 @@ } }, "rc-calendar": { - "version": "9.15.10", - "resolved": "https://registry.npmjs.org/rc-calendar/-/rc-calendar-9.15.10.tgz", - "integrity": "sha512-xh1A3rYejKskAvkjnd9BcHXFbBnAYsHMGHBdtoAkbwp43B6yEieNL0g0Tzz8s1gApDZV2j5vF1jJ9IIpPYFNLw==", + "version": "9.15.11", + "resolved": "https://registry.npm.taobao.org/rc-calendar/download/rc-calendar-9.15.11.tgz", + "integrity": "sha1-zh5eqOTXdDW+ZqjHfbEvHw+aNF8=", "requires": { "babel-runtime": "6.x", "classnames": "2.x", @@ -14376,8 +14519,8 @@ }, "rc-cascader": { "version": "0.17.5", - "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-0.17.5.tgz", - "integrity": "sha512-WYMVcxU0+Lj+xLr4YYH0+yXODumvNXDcVEs5i7L1mtpWwYkubPV/zbQpn+jGKFCIW/hOhjkU4J1db8/P/UKE7A==", + "resolved": "https://registry.npm.taobao.org/rc-cascader/download/rc-cascader-0.17.5.tgz?cache=0&sync_timestamp=1610107054432&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-cascader%2Fdownload%2Frc-cascader-0.17.5.tgz", + "integrity": "sha1-T96R0jt2CMQgJjw47unAaH+A99w=", "requires": { "array-tree-filter": "^2.1.0", "prop-types": "^15.5.8", @@ -14390,8 +14533,8 @@ }, "rc-checkbox": { "version": "2.1.8", - "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.1.8.tgz", - "integrity": "sha512-6qOgh0/by0nVNASx6LZnhRTy17Etcgav+IrI7kL9V9kcDZ/g7K14JFlqrtJ3NjDq/Kyn+BPI1st1XvbkhfaJeg==", + "resolved": "https://registry.npm.taobao.org/rc-checkbox/download/rc-checkbox-2.1.8.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-checkbox%2Fdownload%2Frc-checkbox-2.1.8.tgz", + "integrity": "sha1-7t2e+cLzr1s7jlzeUlSqia0aiAo=", "requires": { "babel-runtime": "^6.23.0", "classnames": "2.x", @@ -14401,8 +14544,8 @@ }, "rc-collapse": { "version": "1.11.8", - "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-1.11.8.tgz", - "integrity": "sha512-8EhfPyScTYljkbRuIoHniSwZagD5UPpZ3CToYgoNYWC85L2qCbPYF7+OaC713FOrIkp6NbfNqXsITNxmDAmxog==", + "resolved": "https://registry.npm.taobao.org/rc-collapse/download/rc-collapse-1.11.8.tgz?cache=0&sync_timestamp=1606217065785&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-collapse%2Fdownload%2Frc-collapse-1.11.8.tgz", + "integrity": "sha1-ZqQAidRpUZ6UJACasckn4hQEHYA=", "requires": { "classnames": "2.x", "css-animation": "1.x", @@ -14415,8 +14558,8 @@ }, "rc-dialog": { "version": "7.6.1", - "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-7.6.1.tgz", - "integrity": "sha512-KUKf+2eZ4YL+lnXMG3hR4ZtIhC9glfH27NtTVz3gcoDIPAf3uUvaXVRNoDCiSi+OGKLyIb/b6EoidFh6nQC5Wg==", + "resolved": "https://registry.npm.taobao.org/rc-dialog/download/rc-dialog-7.6.1.tgz?cache=0&sync_timestamp=1614949683544&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-dialog%2Fdownload%2Frc-dialog-7.6.1.tgz", + "integrity": "sha1-EVRczAuUWTT6dgeXJuDYU+UtcF8=", "requires": { "babel-runtime": "6.x", "rc-animate": "2.x", @@ -14425,8 +14568,8 @@ }, "rc-drawer": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-3.1.3.tgz", - "integrity": "sha512-2z+RdxmzXyZde/1OhVMfDR1e/GBswFeWSZ7FS3Fdd0qhgVdpV1wSzILzzxRaT481ItB5hOV+e8pZT07vdJE8kg==", + "resolved": "https://registry.npm.taobao.org/rc-drawer/download/rc-drawer-3.1.3.tgz?cache=0&sync_timestamp=1614159639291&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-drawer%2Fdownload%2Frc-drawer-3.1.3.tgz", + "integrity": "sha1-y8sE1MB/C2by7OEdhH9KG9gOoLc=", "requires": { "classnames": "^2.2.6", "rc-util": "^4.16.1", @@ -14435,8 +14578,8 @@ }, "rc-dropdown": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-2.4.1.tgz", - "integrity": "sha512-p0XYn0wrOpAZ2fUGE6YJ6U8JBNc5ASijznZ6dkojdaEfQJAeZtV9KMEewhxkVlxGSbbdXe10ptjBlTEW9vEwEg==", + "resolved": "https://registry.npm.taobao.org/rc-dropdown/download/rc-dropdown-2.4.1.tgz?cache=0&sync_timestamp=1600332782526&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-dropdown%2Fdownload%2Frc-dropdown-2.4.1.tgz", + "integrity": "sha1-qu9us6UVLN2ZgolcKnjZtfBGzew=", "requires": { "babel-runtime": "^6.26.0", "classnames": "^2.2.6", @@ -14447,8 +14590,8 @@ }, "rc-editor-core": { "version": "0.8.10", - "resolved": "https://registry.npmjs.org/rc-editor-core/-/rc-editor-core-0.8.10.tgz", - "integrity": "sha512-T3aHpeMCIYA1sdAI7ynHHjXy5fqp83uPlD68ovZ0oClTSc3tbHmyCxXlA+Ti4YgmcpCYv7avF6a+TIbAka53kw==", + "resolved": "https://registry.npm.taobao.org/rc-editor-core/download/rc-editor-core-0.8.10.tgz", + "integrity": "sha1-byFbxd+cM/+p9sWzDKc6favoq3w=", "requires": { "babel-runtime": "^6.26.0", "classnames": "^2.2.5", @@ -14461,8 +14604,8 @@ }, "rc-editor-mention": { "version": "1.1.13", - "resolved": "https://registry.npmjs.org/rc-editor-mention/-/rc-editor-mention-1.1.13.tgz", - "integrity": "sha512-3AOmGir91Fi2ogfRRaXLtqlNuIwQpvla7oUnGHS1+3eo7b+fUp5IlKcagqtwUBB5oDNofoySXkLBxzWvSYNp/Q==", + "resolved": "https://registry.npm.taobao.org/rc-editor-mention/download/rc-editor-mention-1.1.13.tgz", + "integrity": "sha1-nxyrEGX4awFSOEAyF5DCqxKsXos=", "requires": { "babel-runtime": "^6.23.0", "classnames": "^2.2.5", @@ -14490,9 +14633,9 @@ } }, "rc-hammerjs": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/rc-hammerjs/-/rc-hammerjs-0.6.9.tgz", - "integrity": "sha512-4llgWO3RgLyVbEqUdGsDfzUDqklRlQW5VEhE3x35IvhV+w//VPRG34SBavK3D2mD/UaLKaohgU41V4agiftC8g==", + "version": "0.6.10", + "resolved": "https://registry.npm.taobao.org/rc-hammerjs/download/rc-hammerjs-0.6.10.tgz", + "integrity": "sha1-GDGjvY8hmXAL/MWtayCjVjCuteA=", "requires": { "babel-runtime": "6.x", "hammerjs": "^2.0.8", @@ -14500,9 +14643,9 @@ } }, "rc-input-number": { - "version": "4.5.6", - "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-4.5.6.tgz", - "integrity": "sha512-AXbL4gtQ1mSQnu6v/JtMv3UbGRCzLvQznmf0a7U/SAtZ8+dCEAqD4JpJhkjv73Wog53eRYhw4l7ApdXflc9ymg==", + "version": "4.5.9", + "resolved": "https://registry.nlark.com/rc-input-number/download/rc-input-number-4.5.9.tgz?cache=0&sync_timestamp=1619578110950&other_urls=https%3A%2F%2Fregistry.nlark.com%2Frc-input-number%2Fdownload%2Frc-input-number-4.5.9.tgz", + "integrity": "sha1-HL9zXiT+I8TrmkMBAxcguV8qPj0=", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.0", @@ -14513,8 +14656,8 @@ }, "rc-mentions": { "version": "0.4.2", - "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-0.4.2.tgz", - "integrity": "sha512-DTZurQzacLXOfVuiHydGzqkq7cFMHXF18l2jZ9PhWUn2cqvOSY3W4osN0Pq29AOMOBpcxdZCzgc7Lb0r/bgkDw==", + "resolved": "https://registry.npm.taobao.org/rc-mentions/download/rc-mentions-0.4.2.tgz?cache=0&sync_timestamp=1610510822768&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-mentions%2Fdownload%2Frc-mentions-0.4.2.tgz", + "integrity": "sha1-wYq3Ae+55LdbOFGgwNLdaYZA4kY=", "requires": { "@ant-design/create-react-context": "^0.2.4", "classnames": "^2.2.6", @@ -14542,8 +14685,8 @@ }, "rc-notification": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-3.3.1.tgz", - "integrity": "sha512-U5+f4BmBVfMSf3OHSLyRagsJ74yKwlrQAtbbL5ijoA0F2C60BufwnOcHG18tVprd7iaIjzZt1TKMmQSYSvgrig==", + "resolved": "https://registry.npm.taobao.org/rc-notification/download/rc-notification-3.3.1.tgz?cache=0&sync_timestamp=1614675471156&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-notification%2Fdownload%2Frc-notification-3.3.1.tgz", + "integrity": "sha1-C6o+cPjUCrAVzo+njCYMSQ/HvrQ=", "requires": { "babel-runtime": "6.x", "classnames": "2.x", @@ -14564,9 +14707,9 @@ } }, "rc-progress": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-2.5.2.tgz", - "integrity": "sha512-ajI+MJkbBz9zYDuE9GQsY5gsyqPF7HFioZEDZ9Fmc+ebNZoiSeSJsTJImPFCg0dW/5WiRGUy2F69SX1aPtSJgA==", + "version": "2.5.3", + "resolved": "https://registry.npm.taobao.org/rc-progress/download/rc-progress-2.5.3.tgz", + "integrity": "sha1-APAblb2+GFbTpfgiQgUZAui3qOc=", "requires": { "babel-runtime": "6.x", "prop-types": "^15.5.8" @@ -14583,8 +14726,8 @@ }, "rc-resize-observer": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-0.1.3.tgz", - "integrity": "sha512-uzOQEwx83xdQSFOkOAM7x7GHIQKYnrDV4dWxtCxyG1BS1pkfJ4EvDeMfsvAJHSYkQXVBu+sgRHGbRtLG3qiuUg==", + "resolved": "https://registry.npm.taobao.org/rc-resize-observer/download/rc-resize-observer-0.1.3.tgz?cache=0&sync_timestamp=1608864858155&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-resize-observer%2Fdownload%2Frc-resize-observer-0.1.3.tgz", + "integrity": "sha1-CXGR+cOrGG7ZB7VTum71Zd8Rwkk=", "requires": { "classnames": "^2.2.1", "rc-util": "^4.13.0", @@ -14612,8 +14755,8 @@ }, "rc-slider": { "version": "8.7.1", - "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-8.7.1.tgz", - "integrity": "sha512-WMT5mRFUEcrLWwTxsyS8jYmlaMsTVCZIGENLikHsNv+tE8ThU2lCoPfi/xFNUfJFNFSBFP3MwPez9ZsJmNp13g==", + "resolved": "https://registry.npm.taobao.org/rc-slider/download/rc-slider-8.7.1.tgz?cache=0&sync_timestamp=1616675519253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-slider%2Fdownload%2Frc-slider-8.7.1.tgz", + "integrity": "sha1-ntBzYtyTSJo45lSyG4EirXD9PEI=", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.5", @@ -14627,8 +14770,8 @@ }, "rc-steps": { "version": "3.5.0", - "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-3.5.0.tgz", - "integrity": "sha512-2Vkkrpa7PZbg7qPsqTNzVDov4u78cmxofjjnIHiGB9+9rqKS8oTLPzbW2uiWDr3Lk+yGwh8rbpGO1E6VAgBCOg==", + "resolved": "https://registry.npm.taobao.org/rc-steps/download/rc-steps-3.5.0.tgz", + "integrity": "sha1-NrKn8fSZB7DZA2OISxhiPK+ftgA=", "requires": { "babel-runtime": "^6.23.0", "classnames": "^2.2.3", @@ -14637,9 +14780,9 @@ } }, "rc-switch": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-1.9.0.tgz", - "integrity": "sha512-Isas+egaK6qSk64jaEw4GgPStY4umYDbT7ZY93bZF1Af+b/JEsKsJdNOU2qG3WI0Z6tXo2DDq0kJCv8Yhu0zww==", + "version": "1.9.2", + "resolved": "https://registry.npm.taobao.org/rc-switch/download/rc-switch-1.9.2.tgz?cache=0&sync_timestamp=1603791200779&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-switch%2Fdownload%2Frc-switch-1.9.2.tgz", + "integrity": "sha1-eSHHZkEf6aZCZRDDQpAi1rpN/eI=", "requires": { "classnames": "^2.2.1", "prop-types": "^15.5.6", @@ -14648,8 +14791,8 @@ }, "rc-table": { "version": "6.10.15", - "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-6.10.15.tgz", - "integrity": "sha512-LAr0M/gqt+irOjvPNBLApmQ0CUHNOfKsEBhu1uIuB3OlN1ynA9z+sdoTQyNd9+8NSl0MYnQOOfhtLChAY7nU0A==", + "resolved": "https://registry.nlark.com/rc-table/download/rc-table-6.10.15.tgz", + "integrity": "sha1-GB9McMT9dPZX7o8jGW5+sIoDZco=", "requires": { "classnames": "^2.2.5", "component-classes": "^1.2.6", @@ -14663,8 +14806,8 @@ }, "rc-tabs": { "version": "9.7.0", - "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-9.7.0.tgz", - "integrity": "sha512-kvmgp8/MfLzFZ06hWHignqomFQ5nF7BqKr5O1FfhE4VKsGrep52YSF/1MvS5oe0NPcI9XGNS2p751C5v6cYDpQ==", + "resolved": "https://registry.npm.taobao.org/rc-tabs/download/rc-tabs-9.7.0.tgz?cache=0&sync_timestamp=1608866453009&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-tabs%2Fdownload%2Frc-tabs-9.7.0.tgz", + "integrity": "sha1-rglpW+9ZY9bmTnvBBSHHbf3YRIs=", "requires": { "@ant-design/create-react-context": "^0.2.4", "babel-runtime": "6.x", @@ -14681,8 +14824,8 @@ "dependencies": { "raf": { "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "resolved": "https://registry.npm.taobao.org/raf/download/raf-3.4.1.tgz", + "integrity": "sha1-B0LpmkplUvRF1z4+4DKK8P8e3jk=", "requires": { "performance-now": "^2.1.0" } @@ -14691,8 +14834,8 @@ }, "rc-time-picker": { "version": "3.7.3", - "resolved": "https://registry.npmjs.org/rc-time-picker/-/rc-time-picker-3.7.3.tgz", - "integrity": "sha512-Lv1Mvzp9fRXhXEnRLO4nW6GLNxUkfAZ3RsiIBsWjGjXXvMNjdr4BX/ayElHAFK0DoJqOhm7c5tjmIYpEOwcUXg==", + "resolved": "https://registry.npm.taobao.org/rc-time-picker/download/rc-time-picker-3.7.3.tgz?cache=0&sync_timestamp=1576572941972&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-time-picker%2Fdownload%2Frc-time-picker-3.7.3.tgz", + "integrity": "sha1-ZajekECTJQrpyCsCpJBeD5leI+I=", "requires": { "classnames": "2.x", "moment": "2.x", @@ -14704,8 +14847,8 @@ "dependencies": { "raf": { "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "resolved": "https://registry.npm.taobao.org/raf/download/raf-3.4.1.tgz", + "integrity": "sha1-B0LpmkplUvRF1z4+4DKK8P8e3jk=", "requires": { "performance-now": "^2.1.0" } @@ -14714,8 +14857,8 @@ }, "rc-tooltip": { "version": "3.7.3", - "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-3.7.3.tgz", - "integrity": "sha512-dE2ibukxxkrde7wH9W8ozHKUO4aQnPZ6qBHtrTH9LoO836PjDdiaWO73fgPB05VfJs9FbZdmGPVEbXCeOP99Ww==", + "resolved": "https://registry.npm.taobao.org/rc-tooltip/download/rc-tooltip-3.7.3.tgz?cache=0&sync_timestamp=1614588684791&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-tooltip%2Fdownload%2Frc-tooltip-3.7.3.tgz", + "integrity": "sha1-KArsavyqROjf8EgPuv+eh/wArsw=", "requires": { "babel-runtime": "6.x", "prop-types": "^15.5.8", @@ -14759,8 +14902,8 @@ }, "rc-tree-select": { "version": "2.9.4", - "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-2.9.4.tgz", - "integrity": "sha512-0HQkXAN4XbfBW20CZYh3G+V+VMrjX42XRtDCpyv6PDUm5vikC0Ob682ZBCVS97Ww2a5Hf6Ajmu0ahWEdIEpwhg==", + "resolved": "https://registry.nlark.com/rc-tree-select/download/rc-tree-select-2.9.4.tgz", + "integrity": "sha1-aqeU4fDmXGbEBqoKKg50/QpVewk=", "requires": { "classnames": "^2.2.1", "dom-scroll-into-view": "^1.2.1", @@ -14777,8 +14920,8 @@ "dependencies": { "rc-tree": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-2.1.4.tgz", - "integrity": "sha512-Xey794Iavgs8YldFlXcZLOhfcIhlX5Oz/yfKufknBXf2AlZCOkc7aHqSM9uTF7fBPtTGPhPxNEfOqHfY7b7xng==", + "resolved": "https://registry.npm.taobao.org/rc-tree/download/rc-tree-2.1.4.tgz?cache=0&sync_timestamp=1615350038621&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-tree%2Fdownload%2Frc-tree-2.1.4.tgz", + "integrity": "sha1-73WfPnmaIbQ8Hs+ceU6hwU5wtZs=", "requires": { "@ant-design/create-react-context": "^0.2.4", "classnames": "2.x", @@ -14791,8 +14934,8 @@ }, "rc-trigger": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-3.0.0.tgz", - "integrity": "sha512-hQxbbJpo23E2QnYczfq3Ec5J5tVl2mUDhkqxrEsQAqk16HfADQg+iKNWzEYXyERSncdxfnzYuaBgy764mNRzTA==", + "resolved": "https://registry.nlark.com/rc-trigger/download/rc-trigger-3.0.0.tgz?cache=0&sync_timestamp=1619590696046&other_urls=https%3A%2F%2Fregistry.nlark.com%2Frc-trigger%2Fdownload%2Frc-trigger-3.0.0.tgz", + "integrity": "sha1-9tmx2oomsrLR2RKgaHbBpIb1mA8=", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.6", @@ -14805,8 +14948,8 @@ "dependencies": { "rc-animate": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-3.1.1.tgz", - "integrity": "sha512-8wg2Zg3EETy0k/9kYuis30NJNQg1D6/WSQwnCiz6SvyxQXNet/rVraRz3bPngwY6rcU2nlRvoShiYOorXyF7Sg==", + "resolved": "https://registry.npm.taobao.org/rc-animate/download/rc-animate-3.1.1.tgz?cache=0&sync_timestamp=1601018005635&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-animate%2Fdownload%2Frc-animate-3.1.1.tgz", + "integrity": "sha1-3v3YY/VoFsIiU05Nxo/t3s0IE4Y=", "requires": { "@ant-design/css-animation": "^1.7.2", "classnames": "^2.2.6", @@ -14865,6 +15008,18 @@ "prop-types": "^15.6.2" } }, + "react-base16-styling": { + "version": "0.6.0", + "resolved": "https://registry.npm.taobao.org/react-base16-styling/download/react-base16-styling-0.6.0.tgz", + "integrity": "sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw=", + "dev": true, + "requires": { + "base16": "^1.0.0", + "lodash.curry": "^4.0.1", + "lodash.flow": "^3.3.0", + "pure-color": "^1.2.0" + } + }, "react-beautiful-dnd": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-10.1.1.tgz", @@ -15242,6 +15397,18 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "react-json-view": { + "version": "1.21.3", + "resolved": "https://registry.npm.taobao.org/react-json-view/download/react-json-view-1.21.3.tgz", + "integrity": "sha1-8YQgnujxvzdPsMQbCBPP9UVJxHU=", + "dev": true, + "requires": { + "flux": "^4.0.1", + "react-base16-styling": "^0.6.0", + "react-lifecycles-compat": "^3.0.4", + "react-textarea-autosize": "^8.3.2" + } + }, "react-jss": { "version": "8.6.1", "resolved": "https://registry.npmjs.org/react-jss/-/react-jss-8.6.1.tgz", @@ -15262,9 +15429,9 @@ } }, "react-lazy-load": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/react-lazy-load/-/react-lazy-load-3.0.13.tgz", - "integrity": "sha1-OwqS0zbUPT8Nc8vm81sXBQsIuCQ=", + "version": "3.1.13", + "resolved": "https://registry.npm.taobao.org/react-lazy-load/download/react-lazy-load-3.1.13.tgz?cache=0&sync_timestamp=1593654792284&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-lazy-load%2Fdownload%2Freact-lazy-load-3.1.13.tgz", + "integrity": "sha1-I2lD92twhMyEWHFtljKhyYU+pc0=", "requires": { "eventlistener": "0.0.1", "lodash.debounce": "^4.0.0", @@ -15418,9 +15585,9 @@ } }, "react-slick": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/react-slick/-/react-slick-0.25.2.tgz", - "integrity": "sha512-8MNH/NFX/R7zF6W/w+FS5VXNyDusF+XDW1OU0SzODEU7wqYB+ZTGAiNJ++zVNAVqCAHdyCybScaUB+FCZOmBBw==", + "version": "0.28.1", + "resolved": "https://registry.nlark.com/react-slick/download/react-slick-0.28.1.tgz", + "integrity": "sha1-EsGNmRtZQy35w3V7pUCiJ7P7hbk=", "requires": { "classnames": "^2.2.5", "enquire.js": "^2.1.6", @@ -15447,6 +15614,34 @@ "prop-types": "^15.5.4" } }, + "react-textarea-autosize": { + "version": "8.3.3", + "resolved": "https://registry.nlark.com/react-textarea-autosize/download/react-textarea-autosize-8.3.3.tgz?cache=0&sync_timestamp=1622628433420&other_urls=https%3A%2F%2Fregistry.nlark.com%2Freact-textarea-autosize%2Fdownload%2Freact-textarea-autosize-8.3.3.tgz", + "integrity": "sha1-9wkTlFNp2kU/1VTBaPa6rNH6BNg=", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "use-composed-ref": "^1.0.0", + "use-latest": "^1.0.0" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.14.8", + "resolved": "https://registry.nlark.com/@babel/runtime/download/@babel/runtime-7.14.8.tgz", + "integrity": "sha1-cRmlb0IQGIUmlCkLn5FICXORtEY=", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.nlark.com/regenerator-runtime/download/regenerator-runtime-0.13.9.tgz?cache=0&sync_timestamp=1626993001371&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.13.9.tgz", + "integrity": "sha1-iSV0Kpj/2QgUmI11Zq0wyjsmO1I=", + "dev": true + } + } + }, "react-transition-group": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", @@ -16328,8 +16523,8 @@ }, "rmc-feedback": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/rmc-feedback/-/rmc-feedback-2.0.0.tgz", - "integrity": "sha512-5PWOGOW7VXks/l3JzlOU9NIxRpuaSS8d9zA3UULUCuTKnpwBHNvv1jSJzxgbbCQeYzROWUpgKI4za3X4C/mKmQ==", + "resolved": "https://registry.npm.taobao.org/rmc-feedback/download/rmc-feedback-2.0.0.tgz", + "integrity": "sha1-y8bLOuY8emNe7w4l5PuvWsNm7qo=", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.5" @@ -16912,8 +17107,8 @@ }, "shallow-equal": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", - "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==" + "resolved": "https://registry.npm.taobao.org/shallow-equal/download/shallow-equal-1.2.1.tgz", + "integrity": "sha1-TBar+lYEOqINBQMk76aJQLDaedo=" }, "shallowequal": { "version": "1.1.0", @@ -17267,6 +17462,11 @@ "is-fullwidth-code-point": "^2.0.0" } }, + "slick-carousel": { + "version": "1.8.1", + "resolved": "https://registry.npm.taobao.org/slick-carousel/download/slick-carousel-1.8.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fslick-carousel%2Fdownload%2Fslick-carousel-1.8.1.tgz", + "integrity": "sha1-pL+ykBSIe7Zs5Si5C9DNomLMj40=" + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -18605,6 +18805,12 @@ "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", "dev": true }, + "ts-essentials": { + "version": "2.0.12", + "resolved": "https://registry.nlark.com/ts-essentials/download/ts-essentials-2.0.12.tgz", + "integrity": "sha1-yTA/PXT3X6dSjD1JuA4ImrCdh0U=", + "dev": true + }, "tslib": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", @@ -19114,6 +19320,30 @@ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, + "use-composed-ref": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/use-composed-ref/download/use-composed-ref-1.1.0.tgz", + "integrity": "sha1-kiDk6UqXt7AtfSfq6rCzcDRDi7w=", + "dev": true, + "requires": { + "ts-essentials": "^2.0.3" + } + }, + "use-isomorphic-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/use-isomorphic-layout-effect/download/use-isomorphic-layout-effect-1.1.1.tgz", + "integrity": "sha1-e7ZYkXDNKYehUgQvkIT57/t1wiU=", + "dev": true + }, + "use-latest": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/use-latest/download/use-latest-1.2.0.tgz", + "integrity": "sha1-pE9lcrgojgly7EEb3QhAraNm8jI=", + "dev": true, + "requires": { + "use-isomorphic-layout-effect": "^1.0.0" + } + }, "user-home": { "version": "1.1.1", "resolved": "https://registry.npm.taobao.org/user-home/download/user-home-1.1.1.tgz", @@ -20709,6 +20939,16 @@ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true }, + "xterm": { + "version": "4.8.1", + "resolved": "https://registry.npm.taobao.org/xterm/download/xterm-4.8.1.tgz", + "integrity": "sha1-FVoXKaQ+Gom0BlJOIsVjQznjnKE=" + }, + "xterm-addon-fit": { + "version": "0.4.0", + "resolved": "https://registry.npm.taobao.org/xterm-addon-fit/download/xterm-addon-fit-0.4.0.tgz", + "integrity": "sha1-BuDF0KaqrPsAnvVl76HIHpPZAZM=" + }, "y18n": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", @@ -20746,9 +20986,9 @@ } }, "zrender": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/zrender/-/zrender-4.3.0.tgz", - "integrity": "sha512-Dii6j2bDsPkxQayuVf2DXJeruIB/mKVxxcGRZQ9GExiBd4c3w7+oBuvo1O/JGHeFeA1nCmSDVDs/S7yKZG1nrA==" + "version": "4.3.2", + "resolved": "https://registry.npm.taobao.org/zrender/download/zrender-4.3.2.tgz", + "integrity": "sha1-7HQy+UFcgsc1hLa3uMR+GwFiCcY=" } } } diff --git a/package.json b/package.json index a44c2475..07cd53c8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "educoder", - "version": "0.1.0", + "name": "forge", + "version": "3.0.0", "private": true, "dependencies": { "@monaco-editor/react": "^2.3.0", @@ -14,6 +14,7 @@ "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", @@ -26,9 +27,11 @@ "codemirror": "^5.61.0", "connected-react-router": "4.4.1", "css-loader": "^3.5.2", + "dompurify": "^2.0.15", "dotenv": "4.0.0", "dotenv-expand": "4.2.0", - "echarts": "^4.7.0", + "echarts": "^4.9.0", + "echarts-wordcloud": "^2.0.0", "editor.md": "^1.5.0", "eslint": "4.10.0", "eslint-config-react-app": "^2.1.0", @@ -45,6 +48,7 @@ "install": "^0.12.2", "jest": "20.0.4", "js-base64": "^2.5.2", + "js2wordcloud": "^1.1.12", "katex": "^0.11.1", "lodash": "^4.17.21", "loglevel": "^1.6.8", @@ -61,7 +65,7 @@ "postcss-loader": "2.0.8", "promise": "8.0.1", "prop-types": "^15.6.1", - "qrcode.react": "^1.0.0", + "qrcode.react": "^1.0.1", "qs": "^6.9.3", "quill": "^1.3.7", "quill-delta-to-html": "^0.11.0", @@ -92,6 +96,7 @@ "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-vis": "^1.11.7", @@ -103,6 +108,7 @@ "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", @@ -112,7 +118,9 @@ "webpack-dev-server": "^3.11.0", "webpack-manifest-plugin": "^2.2.0", "whatwg-fetch": "2.0.3", - "wrap-md-editor": "^0.2.20" + "wrap-md-editor": "^0.2.20", + "xterm": "4.8.1", + "xterm-addon-fit": "0.4.0" }, "scripts": { "start": "node --max_old_space_size=15360 scripts/start.js", @@ -197,6 +205,7 @@ "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", diff --git a/public/css/editormd.min.css b/public/css/editormd.min.css index 5e738886..113ccc67 100755 --- a/public/css/editormd.min.css +++ b/public/css/editormd.min.css @@ -2,4 +2,4 @@ @charset "UTF-8";/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */.fa-ul,.markdown-body .task-list-item,li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}.editormd-form br,.markdown-body hr:after{clear:both}.editormd{width:90%;height:640px;margin:0 auto 15px;text-align:left;overflow:hidden;position:relative;border:1px solid #ddd;font-family:"Meiryo UI","Microsoft YaHei","Malgun Gothic","Segoe UI","Trebuchet MS",Helvetica,Monaco,monospace,Tahoma,STXihei,"华文细黑",STHeiti,"Helvetica Neue","Droid Sans","wenquanyi micro hei",FreeSans,Arimo,Arial,SimSun,"宋体",Heiti,"黑体",sans-serif}.editormd *,.editormd :after,.editormd :before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.editormd a{text-decoration:none}.editormd img{border:none;vertical-align:middle}.editormd .editormd-html-textarea,.editormd .editormd-markdown-textarea,.editormd>textarea{width:0;height:0;outline:0;resize:none}.editormd .editormd-html-textarea,.editormd .editormd-markdown-textarea{display:none}.editormd button,.editormd input[type=text],.editormd input[type=button],.editormd input[type=submit],.editormd select,.editormd textarea{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none}.editormd ::-webkit-scrollbar{height:10px;width:7px;background:rgba(0,0,0,.1)}.editormd ::-webkit-scrollbar:hover{background:rgba(0,0,0,.2)}.editormd ::-webkit-scrollbar-thumb{background:rgba(0,0,0,.3);-webkit-border-radius:6px;-moz-border-radius:6px;-ms-border-radius:6px;-o-border-radius:6px;border-radius:6px}.editormd ::-webkit-scrollbar-thumb:hover{-webkit-box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);-moz-box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);-ms-box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);-o-box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);background-color:rgba(0,0,0,.4)}.editormd-user-unselect{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.editormd-toolbar{width:100%;min-height:37px;background:#fff;display:none;position:absolute;top:0;left:0;z-index:10;border-bottom:1px solid #ddd}.editormd-toolbar-container{padding:0 8px;min-height:35px;-o-user-select:none;user-select:none}.editormd-toolbar-container,.markdown-body .octicon{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.editormd-menu,.markdown-body ol,.markdown-body td,.markdown-body th,.markdown-body ul{padding:0}.editormd-menu{margin:0;list-style:none}.editormd-menu>li{margin:0;padding:5px 1px;display:inline-block;position:relative}.editormd-menu>li.divider{display:inline-block;text-indent:-9999px;margin:0 5px;height:65%;border-right:1px solid #ddd}.editormd-menu>li>a{outline:0;color:#666;display:inline-block;min-width:24px;font-size:16px;text-decoration:none;text-align:center;-webkit-border-radius:2px;-moz-border-radius:2px;-ms-border-radius:2px;-o-border-radius:2px;border-radius:2px;border:1px solid #fff;transition:all 300ms ease-out}.editormd-dropdown-menu>li>a:hover,.editormd-menu>li>a{-webkit-transition:all 300ms ease-out;-moz-transition:all 300ms ease-out}.editormd-menu>li>a.active,.editormd-menu>li>a:hover{border:1px solid #ddd;background:#eee}.editormd-menu>li>a>.fa{text-align:center;display:block;padding:5px}.editormd-menu>li>a>.editormd-bold{padding:5px 2px;display:inline-block;font-weight:700}.editormd-menu>li:hover .editormd-dropdown-menu{display:block}.editormd-menu>li+li>a{margin-left:3px}.editormd-dropdown-menu{display:none;background:#fff;border:1px solid #ddd;width:148px;list-style:none;position:absolute;top:33px;left:0;z-index:100;-webkit-box-shadow:1px 2px 6px rgba(0,0,0,.15);-moz-box-shadow:1px 2px 6px rgba(0,0,0,.15);-ms-box-shadow:1px 2px 6px rgba(0,0,0,.15);-o-box-shadow:1px 2px 6px rgba(0,0,0,.15);box-shadow:1px 2px 6px rgba(0,0,0,.15)}.editormd-dropdown-menu:after,.editormd-dropdown-menu:before{width:0;height:0;display:block;content:"";position:absolute;top:-11px;left:8px;border:5px solid transparent}.editormd-dropdown-menu:before{border-bottom-color:#ccc}.editormd-dropdown-menu:after{border-bottom-color:#fff;top:-10px}.editormd-dropdown-menu>li>a{color:#666;display:block;text-decoration:none;padding:8px 10px}.editormd-dropdown-menu>li>a:hover{background:#f6f6f6;transition:all 300ms ease-out}.editormd-dropdown-menu>li+li{border-top:1px solid #ddd}.editormd-container{margin:0;width:100%;height:100%;overflow:hidden;padding:35px 0 0;position:relative;background:#fff;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.editormd-dialog{color:#666;position:fixed;z-index:99999;display:none;-webkit-border-radius:3px;-moz-border-radius:3px;-ms-border-radius:3px;-o-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 0 10px rgba(0,0,0,.3);-moz-box-shadow:0 0 10px rgba(0,0,0,.3);-ms-box-shadow:0 0 10px rgba(0,0,0,.3);-o-box-shadow:0 0 10px rgba(0,0,0,.3);box-shadow:0 0 10px rgba(0,0,0,.3);background:#fff;font-size:14px}.editormd-dialog-container{position:relative;padding:20px;line-height:1.4}.editormd-dialog-container h1{font-size:24px;margin-bottom:10px}.editormd-dialog-container h1 .fa{color:#2C7EEA;padding-right:5px}.editormd-dialog-container h1 small{padding-left:5px;font-weight:400;font-size:12px;color:#999}.editormd-dialog-container select{color:#999;padding:3px 8px;border:1px solid #ddd}.editormd-dialog-close{position:absolute;top:12px;right:15px;font-size:18px;color:#ccc;-webkit-transition:color 300ms ease-out;-moz-transition:color 300ms ease-out;transition:color 300ms ease-out}.editormd-dialog-close:hover{color:#999}.editormd-dialog-header{padding:11px 20px;border-bottom:1px solid #eee;-webkit-transition:background 300ms ease-out;-moz-transition:background 300ms ease-out;transition:background 300ms ease-out}.editormd-dialog-header:hover{background:#f6f6f6}.editormd-dialog-title{font-size:14px}.editormd-dialog-footer{padding:10px 0 0;text-align:right}.editormd-dialog-info{width:420px}.editormd-dialog-info h1{font-weight:400}.editormd-dialog-info .editormd-dialog-container{padding:20px 25px 25px}.editormd-dialog-info .editormd-dialog-close{top:10px;right:10px}.editormd-dialog-info .hover-link:hover,.editormd-dialog-info p>a{color:#2196F3}.editormd-dialog-info .hover-link{color:#666}.editormd-dialog-info a .fa-external-link{display:none}.editormd-dialog-info a:hover{color:#2196F3}.editormd-dialog-info a:hover .fa-external-link{display:inline-block}.editormd-container-mask,.editormd-dialog-mask,.editormd-mask{display:none;width:100%;height:100%;position:absolute;top:0;left:0}.editormd-dialog-mask-bg,.editormd-mask{background:#fff;opacity:.5;filter:alpha(opacity=50)}.editormd-mask{position:fixed;background:#000;opacity:.2;filter:alpha(opacity=20);z-index:99998}.editormd-container-mask,.editormd-dialog-mask-con{background:url(../images/loading.gif)center center no-repeat;-webkit-background-size:32px 32px;-moz-background-size:32px 32px;-o-background-size:32px 32px;background-size:32px 32px}.editormd-container-mask{z-index:20;display:block;background-color:#fff}@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min-device-pixel-ratio:2){.editormd-container-mask,.editormd-dialog-mask-con{background-image:url(../images/loading@2x.gif)}}@media only screen and (-webkit-min-device-pixel-ratio:3),only screen and (min-device-pixel-ratio:3){.editormd-container-mask,.editormd-dialog-mask-con{background-image:url(../images/loading@3x.gif)}}.editormd-code-block-dialog textarea,.editormd-preformatted-text-dialog textarea{width:100%;height:400px;margin-bottom:6px;overflow:auto;border:1px solid #eee;background:#fff;padding:15px;resize:none}.editormd-code-toolbar{color:#999;font-size:14px;margin:-5px 0 10px}.editormd-grid-table{width:99%;display:table;border:1px solid #ddd;border-collapse:collapse}.editormd-grid-table-row{width:100%;display:table-row}.editormd-grid-table-row a{font-size:1.4em;width:5%;height:36px;color:#999;text-align:center;display:table-cell;vertical-align:middle;border:1px solid #ddd;text-decoration:none;-webkit-transition:background-color 300ms ease-out,color 100ms ease-in;-moz-transition:background-color 300ms ease-out,color 100ms ease-in;transition:background-color 300ms ease-out,color 100ms ease-in}.editormd-grid-table-row a.selected{color:#666;background-color:#eee}.editormd-grid-table-row a:hover{color:#777;background-color:#f6f6f6}.editormd-tab-head{list-style:none;border-bottom:1px solid #ddd}.editormd-tab-head li{display:inline-block}.editormd-tab-head li a{color:#999;display:block;padding:6px 12px 5px;text-align:center;text-decoration:none;margin-bottom:-1px;border:1px solid #ddd;-webkit-border-top-left-radius:3px;-moz-border-top-left-radius:3px;-ms-border-top-left-radius:3px;-o-border-top-left-radius:3px;border-top-left-radius:3px;-webkit-border-top-right-radius:3px;-moz-border-top-right-radius:3px;-ms-border-top-right-radius:3px;-o-border-top-right-radius:3px;border-top-right-radius:3px;background:#f6f6f6;-webkit-transition:all 300ms ease-out;-moz-transition:all 300ms ease-out;transition:all 300ms ease-out}.editormd-tab-head li a:hover{color:#666;background:#eee}.editormd-tab-head li.active a{color:#666;background:#fff;border-bottom-color:#fff}.editormd-tab-head li+li{margin-left:3px}.editormd-tab-box{padding:20px 0}.editormd-form{color:#666}.editormd-form label{float:left;display:block;width:75px;text-align:left;padding:7px 0 15px 5px;margin:0 0 2px;font-weight:400}.editormd-form iframe{display:none}.editormd-form input:focus{outline:0}.editormd-form input[type=text],.editormd-form input[type=number]{color:#999;padding:8px;border:1px solid #ddd}.editormd-form input[type=number]{width:40px;display:inline-block;padding:6px 8px}.editormd-form input[type=text]{display:inline-block;width:264px}.editormd-form .fa-btns{display:inline-block}.editormd-form .fa-btns a{color:#999;padding:7px 10px 0 0;display:inline-block;text-decoration:none;text-align:center}.editormd-form .fa-btns .fa{font-size:1.3em}.editormd-form .fa-btns label{float:none;display:inline-block;width:auto;text-align:left;padding:0 0 0 5px;cursor:pointer}.fa-fw,.fa-li{text-align:center}.editormd-dialog-container .editormd-btn,.editormd-dialog-container button,.editormd-dialog-container input[type=submit],.editormd-dialog-footer .editormd-btn,.editormd-dialog-footer button,.editormd-dialog-footer input[type=submit],.editormd-form .editormd-btn,.editormd-form button,.editormd-form input[type=submit]{color:#666;min-width:75px;cursor:pointer;background:#fff;padding:7px 10px;border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;-ms-border-radius:3px;-o-border-radius:3px;border-radius:3px;-webkit-transition:background 300ms ease-out;-moz-transition:background 300ms ease-out;transition:background 300ms ease-out}.editormd-dialog-container .editormd-btn:hover,.editormd-dialog-container button:hover,.editormd-dialog-container input[type=submit]:hover,.editormd-dialog-footer .editormd-btn:hover,.editormd-dialog-footer button:hover,.editormd-dialog-footer input[type=submit]:hover,.editormd-form .editormd-btn:hover,.editormd-form button:hover,.editormd-form input[type=submit]:hover{background:#eee}.editormd-dialog-container .editormd-btn+.editormd-btn,.editormd-dialog-footer .editormd-btn+.editormd-btn,.editormd-form .editormd-btn+.editormd-btn{margin-left:8px}.editormd-file-input{width:75px;height:32px;margin-left:8px;position:relative;display:inline-block}.editormd-file-input input[type=file]{width:75px;height:32px;opacity:0;cursor:pointer;background:#000;display:inline-block;position:absolute;top:0;right:0}.editormd-file-input input[type=file]::-webkit-file-upload-button{visibility:hidden}.editormd-file-input:hover input[type=submit]{background:#eee}.editormd .CodeMirror,.editormd-preview{display:inline-block;width:50%;height:100%;vertical-align:top;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0}.editormd-preview{position:absolute;top:35px;right:0;overflow:auto;line-height:1.6;display:none;background:#fff}.fa,.fa-stack{display:inline-block}.editormd .CodeMirror{z-index:10;float:left;border-right:1px solid #ddd;font-size:14px;font-family:"YaHei Consolas Hybrid",Consolas,"微软雅黑","Meiryo UI","Malgun Gothic","Segoe UI","Trebuchet MS",Helvetica,Monaco,courier,monospace;line-height:1.6;margin-top:35px}.editormd .CodeMirror pre{font-size:14px;padding:0 12px}.editormd .CodeMirror-linenumbers{padding:0 5px}.editormd .CodeMirror-focused .CodeMirror-selected,.editormd .CodeMirror-selected{background:#70B7FF}.editormd .CodeMirror,.editormd .CodeMirror-scroll,.editormd .editormd-preview{-webkit-overflow-scrolling:touch}.editormd .styled-background{background-color:#ff7}.editormd .CodeMirror-focused .cm-matchhighlight{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);background-position:bottom;background-repeat:repeat-x}.editormd .CodeMirror-empty.CodeMirror-focused{outline:0}.editormd .CodeMirror pre.CodeMirror-placeholder{color:#999}.editormd .cm-trailingspace{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QUXCToH00Y1UgAAACFJREFUCNdjPMDBUc/AwNDAAAFMTAwMDA0OP34wQgX/AQBYgwYEx4f9lQAAAABJRU5ErkJggg==);background-position:bottom left;background-repeat:repeat-x}.editormd .cm-tab{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=)right no-repeat}/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 *//*! * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:FontAwesome;src:url(../fonts/fontawesome-webfont.eot?v=4.3.0);src:url(../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0)format("embedded-opentype"),url(../fonts/fontawesome-webfont.woff2?v=4.3.0)format("woff2"),url(../fonts/fontawesome-webfont.woff?v=4.3.0)format("woff"),url(../fonts/fontawesome-webfont.ttf?v=4.3.0)format("truetype"),url(../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular)format("svg");font-weight:400;font-style:normal}.fa{font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0,0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em}.fa-ul{padding-left:0;margin-left:2.14285714em}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1,-1);-ms-transform:scale(1,-1);transform:scale(1,-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-rotate-90{filter:none}.fa-stack{position:relative;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-close:before,.fa-remove:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-repeat:before,.fa-rotate-right:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-exclamation-triangle:before,.fa-warning:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-floppy-o:before,.fa-save:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-bolt:before,.fa-flash:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-chain-broken:before,.fa-unlink:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:"\f150"}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:"\f151"}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:"\f152"}.fa-eur:before,.fa-euro:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-inr:before,.fa-rupee:before{content:"\f156"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:"\f158"}.fa-krw:before,.fa-won:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-try:before,.fa-turkish-lira:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-bank:before,.fa-institution:before,.fa-university:before{content:"\f19c"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:"\f1c5"}.fa-file-archive-o:before,.fa-file-zip-o:before{content:"\f1c6"}.fa-file-audio-o:before,.fa-file-sound-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-empire:before,.fa-ge:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-paper-plane:before,.fa-send:before{content:"\f1d8"}.fa-paper-plane-o:before,.fa-send-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before,.fa-genderless:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-bed:before,.fa-hotel:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */@font-face{font-family:editormd-logo;src:url(../fonts/editormd-logo.eot?-5y8q6h);src:url(.../fonts/editormd-logo.eot?#iefix-5y8q6h)format("embedded-opentype"),url(../fonts/editormd-logo.woff?-5y8q6h)format("woff"),url(../fonts/editormd-logo.ttf?-5y8q6h)format("truetype"),url(../fonts/editormd-logo.svg?-5y8q6h#icomoon)format("svg");font-weight:400;font-style:normal}.editormd-logo,.editormd-logo-1x,.editormd-logo-2x,.editormd-logo-3x,.editormd-logo-4x,.editormd-logo-5x,.editormd-logo-6x,.editormd-logo-7x,.editormd-logo-8x{font-family:editormd-logo;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;font-size:inherit;line-height:1;display:inline-block;text-rendering:auto;vertical-align:inherit;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.markdown-body hr:after,.markdown-body hr:before{content:"";display:table}.editormd-logo-1x:before,.editormd-logo-2x:before,.editormd-logo-3x:before,.editormd-logo-4x:before,.editormd-logo-5x:before,.editormd-logo-6x:before,.editormd-logo-7x:before,.editormd-logo-8x:before,.editormd-logo:before{content:"\e1987"}.editormd-logo-1x{font-size:1em}.editormd-logo-lg{font-size:1.2em}.editormd-logo-2x{font-size:2em}.editormd-logo-3x{font-size:3em}.editormd-logo-4x{font-size:4em}.editormd-logo-5x{font-size:5em}.editormd-logo-6x{font-size:6em}.editormd-logo-7x{font-size:7em}.editormd-logo-8x{font-size:8em}.editormd-logo-color{color:#2196F3}/*! github-markdown-css | The MIT License (MIT) | Copyright (c) Sindre Sorhus]*>/g
-
function _unescape(str) {
let div = document.createElement('div')
div.innerHTML = str
- return div.childNodes.length === 0 ? "" : div.childNodes[0].nodeValue;
+ return div.childNodes.length === 0 ? "" : div.childNodes[0].nodeValue
}
-export default ({ value = '', className, style = {} }) => {
- let str = String(value)
+
+export default ({
+ value = '',
+ className,
+ style = {},
+ url
+}) => {
+ let str = String(value);
const html = useMemo(() => {
- let rs = marked(str)
- const math_expressions = getMathExpressions()
+ let rs = marked(str);
+ const math_expressions = getMathExpressions();
if (str.match(/\[TOC\]/)) {
rs = rs.replace("[TOC]
", getTocContent())
cleanToc()
}
rs = rs.replace(/(__special_katext_id_\d+__)/g, (_match, capture) => {
const { type, expression } = math_expressions[capture]
- return renderToString(_unescape(expression), { displayMode: type === 'block', throwOnError: false, output: 'html' })
+ return renderToString(_unescape(expression) || '', { displayMode: type === 'block', throwOnError: false, output: 'html' })
})
rs = rs.replace(/▁/g, "▁▁▁")
resetMathExpressions()
- return rs
- }, [str])
+ return dompurify.sanitize(rs)
+ }, [str]);
- const el = useRef()
+ // 锚点跳转,链接地址里含#对应的id
+ useEffect(()=>{
+ if(url && url.hash && html){
+ let u = url.hash;
+ if(u){
+ let id = decodeURIComponent(u.split("#")[1]);
+ let ele = document.getElementById(id);
+ if(ele){
+ window.scrollTo(0, ele.offsetTop + 120);
+ }
+ }
+ }
+ },[url,html])
+
+ 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.startsWith('#')) {
+ let ancher = target.getAttribute('href');
+ if (ancher && ancher.startsWith('#')) {
e.preventDefault()
let viewEl = document.getElementById(ancher.replace('#', ''))
if (viewEl) {
- viewEl.parentNode.scrollTop = viewEl.offsetTop
+ viewEl.scrollIntoView(true)
}
}
}
@@ -61,6 +82,12 @@ export default ({ value = '', className, style = {} }) => {
}
}
}, [html, el.current, onAncherHandler])
-
- return ()
+ return (
+
+ )
}
diff --git a/src/forge/About/Index.jsx b/src/forge/About/Index.jsx
index 964c4e0a..b36b815c 100644
--- a/src/forge/About/Index.jsx
+++ b/src/forge/About/Index.jsx
@@ -67,18 +67,17 @@ function Index(props){
}
return(
-
-
- 项目简介
+
+ 项目概览
{ editOpration && !edit && 编辑 }
{
edit ?
-
+
:
-
+
{content ?
-
+
:
- 暂无简介~
+ 暂无概览~
}
{attachments && attachments.length > 0 &&
}
-
-
+
+
{item.user_name}
{item.created_at && 创建于{item.created_at}}
diff --git a/src/forge/Branch/CloneAddress.js b/src/forge/Branch/CloneAddress.js
index 89cd3f4e..618b5663 100644
--- a/src/forge/Branch/CloneAddress.js
+++ b/src/forge/Branch/CloneAddress.js
@@ -1,39 +1,35 @@
-import React, { Component } from 'react';
-import { Dropdown, Icon, Tooltip } from 'antd';
-import "./branch.css";
+import React, { useState } from 'react';
+import { Dropdown, Menu, Tooltip } from 'antd';
+import "./branch.scss";
-class CloneAddress extends Component {
+function CloneAddress({http_url , ssh_url , zip_url , tar_url}) {
+ const [ key , setKey ] = useState("HTTP");
// 点击按钮复制功能
- jsCopy = () => {
+ function jsCopy(){
var e = document.getElementById("copy_rep_content");
e.select();
document.execCommand("Copy");
}
- render() {
- const { http_url, downloadUrl } = this.props;
- return (
-
- {/* 版本库地址已变更,请基于新地址提交代码
*/}
- {
- http_url && HTTP
- }
-
-
- this.jsCopy()}>
-
- {
- downloadUrl &&
-
-
-
-
-
-
-
- }
+ return (
+
+
+
+
+
+
+
+
+
- )
- }
+
+
+ )
}
export default CloneAddress;
\ No newline at end of file
diff --git a/src/forge/Branch/Select.jsx b/src/forge/Branch/Select.jsx
index 55bb0345..a44584c4 100644
--- a/src/forge/Branch/Select.jsx
+++ b/src/forge/Branch/Select.jsx
@@ -1,111 +1,36 @@
import React , { useState , useEffect } from 'react';
-import { Popover , Input , Spin } from 'antd';
-import './branch.css';
+import { Popover , Dropdown , Input , Spin } from 'antd';
+import './branch.scss';
import { getBranch , getTag } from '../GetData/getData';
+import SelectOverlay from './SelectOverlay';
-export default (({ projectsId , branch , owner , history , changeBranch })=>{
+export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true })=>{
const [ showValue , setShowValue ] = useState(branch);
- const [ inputValue , setInputValue] = useState(undefined);
- const [ nav , setNav ] = useState(0);
- const [ isSpin , setIsSpin ] = useState(true);
- const [ flag , setFlag ] = useState(false);
-
- const [ data , setData ] = useState(undefined);
- const [ datas , setDatas ] = useState(undefined);
useEffect(()=>{
setShowValue(branch);
},[branch])
- useEffect(()=>{
- document.body.addEventListener('click', e => {
- let name = e.target.className;
- let turn = name === "ant-input OptionsInput" || name === "navli active"|| name === "navli" || name === "padding10 bor-bottom-greyE";
- if(turn){
- return;
- }else{
- setFlag(false);
- }
- })
- })
-
- useEffect(()=>{
- getBranchs(projectsId,owner);
- },[owner])
-
-
- 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 = (
-
-
-
-
- - changeNav(0)}>分支列表
- - changeNav(1)}>标签列表
-
-
-
-
- {
- datas && datas.length>0 ?
- datas.map((item,key)=>{
- return(
- - chooseitem(item.name)}>{item.name}
- )
- }):
- 暂无{inputValue}{nav === 0 ?"分支":"标签"}~
- }
-
-
-
+
);
return(
- setFlag(!flag)} overlayClassName="branch-tagBox-list">
+
-
+
)
})
\ No newline at end of file
diff --git a/src/forge/Branch/SelectOverlay.jsx b/src/forge/Branch/SelectOverlay.jsx
new file mode 100644
index 00000000..d536d1c9
--- /dev/null
+++ b/src/forge/Branch/SelectOverlay.jsx
@@ -0,0 +1,84 @@
+import React , { useState , useEffect } from 'react';
+import { Input , Spin , Menu } from 'antd';
+import { getBranch , getTag } from '../GetData/getData';
+
+function SelectOverlay({ changeBranch , tagflag , branchList , projectsId , owner }) {
+ const [ inputValue , setInputValue] = useState(undefined);
+ const [ nav , setNav ] = useState(0);
+ const [ isSpin , setIsSpin ] = useState(true);
+
+ const [ data , setData ] = useState(undefined);
+ const [ datas , setDatas ] = useState(undefined);
+ const [ keys ,setKeys] = useState("branch");
+
+ useEffect(()=>{
+ if(branchList){
+ setData(branchList);
+ setDatas(branchList);
+ setIsSpin(false);
+ }
+ },[branchList])
+
+ async function getBranchs(id,owner){
+ let result = await getBranch(id,owner);
+ setData(result);
+ setDatas(result);
+ setIsSpin(false);
+ }
+ async function getTags(id,owner){
+ let result = await getTag(id,owner);
+ setData(result);
+ setDatas(result);
+ setIsSpin(false);
+ }
+ function chooseitem(value){
+ changeBranch(value);
+ }
+ function changeInputValue(e){
+ setInputValue(e.target.value);
+ let filter = e.target.value ? data && data.length>0 && data.filter(item=>item.name.indexOf(e.target.value)>-1) : data;
+ setDatas(filter);
+ }
+
+ function changeNav(e){
+ setKeys(e.key);
+ setIsSpin(true);
+ if(e.key === "branch"){
+ getBranchs(projectsId,owner);
+ }else{
+ getTags(projectsId,owner);
+ }
+ }
+
+ return(
+
+
+ }
+ placeholder="请输入分支或标签名称搜索"
+ autocomplete="off" className="OptionsInput"
+ value={inputValue}
+ onChange={changeInputValue}
+ />
+
+
+
+
+ {
+ datas && datas.length>0 ?
+ datas.map((item,key)=>{
+ return(
+ - chooseitem(item.name)}>{item.name}
+ )
+ }):
+ 暂无{inputValue}{nav === 0 ?"分支":"标签"}~
+ }
+
+
+
+ )
+}
+export default SelectOverlay;
\ No newline at end of file
diff --git a/src/forge/Branch/branch.css b/src/forge/Branch/branch.css
deleted file mode 100644
index ff65db54..00000000
--- a/src/forge/Branch/branch.css
+++ /dev/null
@@ -1,84 +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{
- 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: 240px;
-}
-.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;
-}
\ No newline at end of file
diff --git a/src/forge/Branch/branch.scss b/src/forge/Branch/branch.scss
new file mode 100644
index 00000000..447b2cee
--- /dev/null
+++ b/src/forge/Branch/branch.scss
@@ -0,0 +1,118 @@
+.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: 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: 36px;
+ 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;
+ }
+ }
+}
+.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:#1890ff!important;
+ }
+ &.ant-menu-item-active{
+ border-color:transparent ;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/forge/Component/AddGroup.jsx b/src/forge/Component/AddGroup.jsx
new file mode 100644
index 00000000..656175d5
--- /dev/null
+++ b/src/forge/Component/AddGroup.jsx
@@ -0,0 +1,83 @@
+import React, { useEffect, useState } from 'react';
+import { AutoComplete , Button , Icon } from 'antd';
+import axios from 'axios';
+
+const { Option } = AutoComplete;
+function AddGroup({organizeId,getGroupID}){
+ const [ id , setID ] = useState(undefined);
+ const [ source , setSource ] = useState(undefined);
+ const [ searchKey , setSearchKey ] = useState("");
+
+ useEffect(()=>{
+ getUserList();
+ },[searchKey])
+
+ function getUserList(e){
+ const url = `/organizations/${organizeId}/teams/search.json`;
+ axios.get(url, {
+ params: {
+ search: searchKey,
+ },
+ }).then((result) => {
+ if (result) {
+ sourceOptions(result.data.teams);
+ }
+ })
+ .catch((error) => {
+ console.log(error);
+ });
+ };
+
+ function sourceOptions(userDataSource){
+ const s = userDataSource && userDataSource.map((item, key) => {
+ return (
+
+ );
+ });
+ setSource(s);
+ }
+
+ function changeInputUser(e){
+ setSearchKey(e || "");
+ };
+
+ // 选择用户
+ function selectInputUser(e, option){
+ setID(e);
+ setSearchKey(option.props.name);
+ };
+
+ function addCollaborator(){
+ getGroupID && getGroupID(id);
+ }
+
+ return(
+
+
+
+
+ )
+}
+export default AddGroup;
\ No newline at end of file
diff --git a/src/forge/Component/AddMember.jsx b/src/forge/Component/AddMember.jsx
new file mode 100644
index 00000000..f927850c
--- /dev/null
+++ b/src/forge/Component/AddMember.jsx
@@ -0,0 +1,100 @@
+import React, { useEffect, useState } from 'react';
+import { AutoComplete , Button , Icon } from 'antd';
+import axios from 'axios';
+import { getImageUrl } from 'educoder';
+
+const { Option } = AutoComplete;
+function AddMember({getID,login,showNotification}){
+ const [ id , setID ] = useState(undefined);
+ const [ source , setSource ] = useState(undefined);
+ const [ searchKey , setSearchKey ] = useState(undefined);
+
+ useEffect(()=>{
+ getUserList();
+ },[searchKey])
+
+ function getUserList(e){
+ const url = `/users/list.json`;
+ axios.get(url, {
+ params: {
+ search: searchKey,
+ },
+ }).then((result) => {
+ if (result) {
+ sourceOptions(result.data.users);
+ }
+ })
+ .catch((error) => {
+ console.log(error);
+ });
+ };
+
+ function sourceOptions(userDataSource){
+ const s = userDataSource && userDataSource.map((item, key) => {
+ return (
+
+ );
+ });
+ setSource(s);
+ }
+
+ function changeInputUser(e){
+ setSearchKey(e);
+ };
+
+ // 选择用户
+ function selectInputUser(e, option){
+ setID(login ? e : option.props.login);
+ setSearchKey(option.props.name);
+ };
+
+ function addCollaborator(){
+ if(source && source.length>0){
+ getID && getID(id);
+ setSearchKey(undefined);
+ }else{
+ showNotification("请选择存在的用户!");
+ }
+ }
+
+ return(
+
+
+
+
+ )
+}
+export default AddMember;
\ No newline at end of file
diff --git a/src/forge/Component/Cards.jsx b/src/forge/Component/Cards.jsx
index f35d890a..f9a3d52e 100644
--- a/src/forge/Component/Cards.jsx
+++ b/src/forge/Component/Cards.jsx
@@ -1,19 +1,23 @@
import React from 'react';
+import { getImageUrl } from 'educoder';
+import { Link } from 'react-router-dom';
import './Component.scss';
-export default (({img , title, desc , rightBtn})=>{
+function Cards({img , title, desc , rightBtn , src , bottomInfos}){
return(
-
+ {img &&
}
- {title}
+ {title}
{rightBtn}
{desc}
+ {bottomInfos}
)
-})
\ No newline at end of file
+}
+export default Cards;
\ No newline at end of file
diff --git a/src/forge/Component/Component.scss b/src/forge/Component/Component.scss
index 202cdd0d..627304e1 100644
--- a/src/forge/Component/Component.scss
+++ b/src/forge/Component/Component.scss
@@ -19,6 +19,8 @@ li.ant-menu-item{
padding:20px 34px;
background-color: #fff;
margin-bottom:18px;
+ min-height: 130px;
+ border:1px solid #eee;
.img{
margin-right: 20px;
width: 190px;
@@ -27,8 +29,10 @@ li.ant-menu-item{
display: flex;
justify-content: center;
align-items: center;
+ overflow: hidden;
img{
max-width: 100%;
+ max-height: 100%;
}
}
.content{
@@ -39,7 +43,9 @@ li.ant-menu-item{
justify-content: space-between;
margin-bottom: 10px!important;
align-items: center;
- &>span{
+ height: 22px;
+ line-height: 22px;;
+ &>a{
font-size:18px ;
color: #333;
}
@@ -50,11 +56,13 @@ li.ant-menu-item{
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
+ line-height: 20px;
}
}
}
// Tabs
.tabsStyle{
+ border:1px solid #eee;
.ant-tabs-bar.ant-tabs-top-bar{
padding-left: 35px;
margin-bottom: 0px;
@@ -104,6 +112,16 @@ li.ant-menu-item{
right:240px;
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;
+}
@media screen and (max-width: 1800px){
.handleBox{
@@ -129,4 +147,273 @@ li.ant-menu-item{
.handleBox{
right:0px;
}
-}
\ No newline at end of file
+}
+.ant-drawer{
+ z-index: 10000!important;
+}
+.ant-drawer-body{
+ padding:0px!important;
+ .drawerHead{
+ background-color: #333;
+ color: #fff;
+ padding:15px 20px;
+ }
+ .ant-tree{
+ margin:0px 20px!important;
+ }
+}
+
+.menuPanels{
+ width: 295px;
+ .leftline{
+ position: relative;
+ color: #666;
+ height: 16px;
+ &::before{
+ position: absolute;
+ left: -10px;
+ top:3px;
+ height: 12px;
+ width: 1px;
+ background-color: #666666;
+ 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-primary{
+ color: #fff;
+ background-color: #2A61FF;
+ }
+ .focusPanelHeadInfo{
+ padding:14px 16px;
+ border-bottom: 1px solid #eee;
+ }
+ .ant-popover-content,.ant-popover-inner{
+ height: 100%;
+ width: 100%;
+ }
+ .ant-popover-inner-content{
+ padding:0px;
+ }
+}
+.halfs{
+ margin-top: 24px;
+ padding:24px 0px 0px 0px;
+ border-top: 1px solid #e8e8e8;
+}
+.aboutSubTitle{
+ display: flex;
+ align-items: center;
+}
+.menuinfos{
+ padding:10px 20px;
+ &>a{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ flex: 1;
+ & >span:first-child{
+ font-size: 16px;
+ font-weight: 500;
+ color: #333;
+ line-height: 22px;
+ }
+ & >span:last-child{
+ color: #666;
+ font-weight: 400;
+ line-height: 20px;
+ margin-top: 6px;
+ }
+ }
+}
+
+/*-------------------个人主页:右侧提示区域--------------------------*/
+.-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
+}
diff --git a/src/forge/Component/Contributors.jsx b/src/forge/Component/Contributors.jsx
new file mode 100644
index 00000000..9890ea76
--- /dev/null
+++ b/src/forge/Component/Contributors.jsx
@@ -0,0 +1,172 @@
+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 { getImageUrl } from 'educoder';
+import './Component.scss';
+import { getUser } from '../GetData/getData';
+import axios from 'axios';
+
+function Contributors({contributors,owner,projectsId,currentLogin}){
+ const [ menuList ,setMenuList ]= useState([]);
+ const [ list , setList ]= useState(undefined);
+ const [ total , setTotal ]= useState(0);
+ const [ menu , setMenu ] = useState("");
+ const [ login , setLogin ] = useState(undefined);
+ const [ isSpin , setIsSpin ] = useState(false);
+
+ useEffect(()=>{
+ if(contributors && contributors.total_count>0){
+ setTotal(contributors.total_count);
+ setList(contributors.list);
+ }
+ },[contributors])
+
+ useEffect(()=>{
+ if(login){
+ getUsers(login);
+ }else{
+ setMenu(undefined);
+ }
+ },[login])
+
+ async function getUsers(login){
+ setIsSpin(true);
+ let a = menuList && menuList.filter(i=>i.login === login);
+ if(a.length === 0){
+ let result = await getUser(login);
+ let arr = menuList;
+ arr.push({...result});
+ setMenuList(arr);
+ setMenusFunc(result);
+ setIsSpin(false);
+ }else{
+ setMenusFunc(a[0]);
+ setIsSpin(false);
+ }
+ }
+
+ function setMenusFunc(data){
+ if(data){
+ let ele = (
+
+
+
+
+
+ {data.name}
+ {
+ data.location &&
+ {data.location}
+ }
+
+ {
+ data.organizations && data.organizations.length > 0 ?
+
+ 所属组织:
+
+ {renderArray(data.organizations)}
+
+
+ :""
+ }
+
+
+
+
+ {data.projects_count}
+ 项目数
+
+
+ {data.followers_count}
+ 粉丝数
+
+
+ {data.following_count}
+ 关注数
+
+
+
+ {
+ currentLogin && (currentLogin === data.login)
+ ?
+
+ :
+ data.is_watch ?
+
+ :
+
+ }
+
+
+ )
+ setMenu(ele);
+ }
+ }
+
+ function FocusFunc(flag,login){
+ axios({
+ method: flag ? 'post' : 'delete',
+ url: `/watchers/${flag ? 'follow' : 'unfollow'}.json`,
+ params: {target_type: "user",id:login}
+ }).then(result => {
+ if (result && (result.data.status === 0 || result.data.status === 2)) {
+ let a = menuList && menuList.filter(i=>i.login === login);
+ if(a){
+ a[0].is_watch = flag;
+ }
+ setMenusFunc(a[0]);
+ }
+ })
+ .catch(error => {
+ console.log(error);
+ });
+ }
+
+ function renderArray(array){
+ let str = "";
+ for(var i = 0;i{substr})
+ }
+
+ function setVisibleFunc(flag,l,index){
+ if(l !== login){
+ setLogin(l);
+ }
+ var lx = list.concat();
+ lx.map(i=>i.visible =false);
+ if(flag){
+ lx[index].visible = flag;
+ }
+ lx.splice();
+ setList(lx);
+ }
+
+ return(
+
+
+ 贡献者
+ { contributors && contributors.total_count > 0 && {contributors.total_count}}
+
+ setVisibleFunc(false)}>
+ {
+ total > 0 ?
+ list.map((item,key)=>{
+ return(
+
+
+
setVisibleFunc(true,item.login,key)}/>
+
+
+ )
+ })
+ :""
+ }
+
+
+ )
+}
+export default Contributors;
\ No newline at end of file
diff --git a/src/forge/Component/DeleteModal/Index.jsx b/src/forge/Component/DeleteModal/Index.jsx
new file mode 100644
index 00000000..7e631dac
--- /dev/null
+++ b/src/forge/Component/DeleteModal/Index.jsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import { AlignCenter } from '../layout';
+import { Modal , Button } from 'antd';
+import './Index.scss';
+
+function DeleteBox({
+ visible ,
+ onCancel ,
+ onSuccess ,
+ title ,
+ subTitle,
+ content
+}) {
+ return(
+
+
+
+
+ }
+ >
+
+ {content}
+ {subTitle}
+
+
+ )
+}
+export default DeleteBox;
\ No newline at end of file
diff --git a/src/forge/Component/DeleteModal/Index.scss b/src/forge/Component/DeleteModal/Index.scss
new file mode 100644
index 00000000..7df79ebf
--- /dev/null
+++ b/src/forge/Component/DeleteModal/Index.scss
@@ -0,0 +1,45 @@
+.deleteBox{
+ .ant-modal-header{
+ background-color: #f8f8f8;
+ border-bottom: none;
+ .ant-modal-title{
+ text-align: left;
+ font-size: 20px;
+ }
+ }
+ .ant-modal-body{
+ padding:30px 50px;
+ p{
+ font-size: 16px;
+ line-height: 26px;
+ color:#666;
+ word-break: break-all;
+ }
+ .desc{
+ .descMain{
+ align-items: center;
+ justify-content: center;
+ font-size: 20px;
+ margin-bottom: 10px;
+ i{
+ font-size: 38px!important;
+ color:#DF0002
+ }
+ }
+ }
+ }
+ .ant-modal-footer{
+ border-top: none;
+ text-align: center;
+ padding-bottom: 40px;
+ button{
+ width: 120px;
+ margin:0px 20px;
+ &.ant-btn-danger{
+ background-color: #fff;
+ color: #DF0002;
+ border-color: #D0D0D0;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/forge/Component/DrawerPanel.jsx b/src/forge/Component/DrawerPanel.jsx
new file mode 100644
index 00000000..0e604d59
--- /dev/null
+++ b/src/forge/Component/DrawerPanel.jsx
@@ -0,0 +1,106 @@
+import React, { useEffect, useState } from 'react';
+import { Drawer , Tree , Spin } from 'antd';
+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);
+ const [first , setFirst ] = useState(true);
+ useEffect(()=>{
+ if(visible && first){
+ if(list){
+ setTreeData(list);
+ setIsSpin(false);
+ }else{
+ getMenulist();
+ }
+ setFirst(false);
+ }
+ },[visible])
+
+ function getMenulist(){
+ const url = `/${owner}/${projectsId}/entries.json`;
+ axios.get(url,{ params: { ref: branch } }).then(result=>{
+ if(result){
+ setTreeData(result.data.entries);
+ }
+ setIsSpin(false);
+ }).catch(error=>{})
+ }
+
+ function renderTreeNodes(data) {
+ return data && data.length > 0 && data.map((item) => {
+ return (
+
+ {renderTreeNodes(item.children)}
+
+ );
+ });
+ }
+
+ function onLoadData(tr){
+ return new Promise((resolve) => {
+ if (tr.props.children) {
+ resolve();
+ return;
+ }
+ let en = [];
+ const url = `/${owner}/${projectsId}/sub_entries.json`;
+ axios.get(url, {
+ params:{
+ filepath:tr.props.dataRef.path,
+ ref:branch,
+ type:"dir"
+ }
+ }).then((result) => {
+ if(result){
+ en = result.data.entries;
+ }
+ }).catch(error=>{})
+ setTimeout(() => {
+ tr.props.dataRef.children = en;
+ setTreeData([...treeData]);
+ resolve();
+ }, 2000);
+ });
+ }
+
+ function selectTree(keys,event){
+ let dataref = event.node.props.dataRef;
+ if(dataref.type==="file"){
+ onClose();
+ let value = turnbar(branch);
+ history.push(`/projects/${owner}/${projectsId}/tree/${value}/${dataref.path}`);
+ }
+ }
+
+ return(
+
+
+
+ {name}
+ {branch}
+
+
+ {treeData && renderTreeNodes(treeData)}
+
+
+
+ )
+}
+export default DrawerPanel;
diff --git a/src/forge/Component/EAccount.scss b/src/forge/Component/EAccount.scss
new file mode 100644
index 00000000..d0fd2ef2
--- /dev/null
+++ b/src/forge/Component/EAccount.scss
@@ -0,0 +1,6 @@
+.ant-modal-mask{
+ z-index: 1001;
+}
+.ant-modal-wrap{
+ z-index: 1002;
+}
\ No newline at end of file
diff --git a/src/forge/Component/EducoderAccount.jsx b/src/forge/Component/EducoderAccount.jsx
new file mode 100644
index 00000000..51fe0ded
--- /dev/null
+++ b/src/forge/Component/EducoderAccount.jsx
@@ -0,0 +1,60 @@
+import React , {forwardRef, useEffect} from 'react';
+import { Modal , Form , Input , Button } from 'antd';
+import './EAccount.scss';
+
+function EducoderAccount({form , visible , onOk , email}){
+ const { getFieldDecorator, validateFields , setFieldsValue } = form;
+
+ useEffect(()=>{
+ if(email){
+ setFieldsValue({email})
+ }
+ },[email])
+
+ function onSure(){
+ validateFields((error,values)=>{
+ if(!error){
+ onOk(values);
+ }
+ })
+ }
+ const layout = {
+ labelCol: { span: 5 },
+ wrapperCol: { span: 18 },
+ };
+ return(
+ 确定
+ }
+ centered
+ >
+
+
+ 为确保您能正常使用平台功能,请确认以下信息:
+
+
+ {getFieldDecorator("email",{
+ rules:[{required:true,message:"请输入邮箱账号"}]
+ })(
+
+ )}
+
+
+ {getFieldDecorator("password",{
+ rules:[{required:true,message:"请输入邮箱密码"}]
+ })(
+
+ )}
+
+
+
+
+ )
+}
+export default Form.create()(forwardRef(EducoderAccount));
\ No newline at end of file
diff --git a/src/forge/Component/Handbook.jsx b/src/forge/Component/Handbook.jsx
index bcb38187..d26c0a8f 100644
--- a/src/forge/Component/Handbook.jsx
+++ b/src/forge/Component/Handbook.jsx
@@ -5,7 +5,7 @@ import './Component.scss';
export default (()=>{
return(
-
+
diff --git a/src/forge/Component/HeadSearch.jsx b/src/forge/Component/HeadSearch.jsx
new file mode 100644
index 00000000..fb7c9f25
--- /dev/null
+++ b/src/forge/Component/HeadSearch.jsx
@@ -0,0 +1,41 @@
+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 (
+
+ {
+ openSearch ?
+ {
+ setTimeout(() => {
+ setOpenSearch(false)
+ }, 500)
+ }}
+ >
+
+
+ :
+ {
+ setOpenSearch(true)
+ }} />
+ }
+
+ )
+};
diff --git a/src/forge/Component/LanguagePower.jsx b/src/forge/Component/LanguagePower.jsx
new file mode 100644
index 00000000..8d3e361b
--- /dev/null
+++ b/src/forge/Component/LanguagePower.jsx
@@ -0,0 +1,54 @@
+import React, { useEffect, useState } from 'react';
+import { FlexAJ } from '../Component/layout';
+
+function LanguagePower({languages}){
+ const [ array , setArray ] = useState(undefined);
+
+ useEffect(()=>{
+ if(languages){
+ let arr = [];
+ Object.keys(languages).map((item,key)=>{
+ arr.push({name:item,percent:languages[item],color:getColor()});
+ })
+ setArray(arr);
+ }
+ },[languages])
+
+ function getColor(){
+ let str = "#";
+ let arr = ["1","2","3","4","4","5","6","7","8","9","a","b","c","d","e","f"];
+ for(var i=0;i<6;i++){
+ let num = parseInt(Math.random() * 16);
+ str+=arr[num];
+ }
+ return str;
+ }
+ return(
+
+ 开发语言
+
+ {
+ array && array.map((item,key)=>{
+ return(
+
+ )
+ })
+ }
+
+ {
+ array && array.length > 0 &&
+
+ {
+ array.map((item,key)=>{
+ return(
+ {item.name}{item.percent}
+ )
+ })
+ }
+
+ }
+
+
+ )
+}
+export default LanguagePower;
\ No newline at end of file
diff --git a/src/forge/Component/ListCount.jsx b/src/forge/Component/ListCount.jsx
index 5a88dd43..d8bedbc6 100644
--- a/src/forge/Component/ListCount.jsx
+++ b/src/forge/Component/ListCount.jsx
@@ -19,7 +19,7 @@ export default (({fork,parise})=>{
}`;
const SpanStyleparise = styled.span`{
display:flex;
- align-item:center;
+ align-items:center;
margin-left:30px;
padding:0px 12px;
border-radius:13px;
diff --git a/src/forge/Component/MemberCards.jsx b/src/forge/Component/MemberCards.jsx
index 78dd78d0..393ddbb1 100644
--- a/src/forge/Component/MemberCards.jsx
+++ b/src/forge/Component/MemberCards.jsx
@@ -1,6 +1,10 @@
import React from 'react';
import './Component.scss';
+import { Button } from 'antd';
import styled from 'styled-components';
+import FocusButton from "../UsersList/focus_button";
+import { getImageUrl } from 'educoder';
+import { Link } from 'react-router-dom';
const Img = styled.img`{
border-radius:50%;
@@ -28,26 +32,8 @@ const I = styled.i`{
font-size:13px!important;
color:#60B25E;
margin-right:2px;
-}`
-const FocusBtn = styled.a`{
- display:inline-block;
- height:30px;
- line-height:26px;
- padding:0px 12px;
- background-color:#fafafa;
- border:1px solid #eee;
- border-radius:2px;
- color:#888!important;
-}`
-const Ifocused = styled.i`{
- font-size:16px!important;
- color:#FFA802;
- margin-right:4px;
-}`
-const Ifocus = styled.i`{
- font-size:16px!important;
- color:#BBBBBB;
- margin-right:4px;
+ height:17px;
+ line-height:17px;
}`
const Div = styled.div`{
margin-bottom: 18px;
@@ -56,17 +42,18 @@ const Div = styled.div`{
align-items: center;
border:1px solid #eee;
}`
-export default (({img,name,time, focusStatus})=>{
- return(
+export default (({ user , img, name, time, focusStatus, is_current_user, login , successFunc }) => {
+ return (
-
+
- {name}
+ {name}
{
- focusStatus ?
- 已关注 :
- 关注
+ is_current_user ?
+
+ :
+
}
diff --git a/src/forge/Component/Monaco.jsx b/src/forge/Component/Monaco.jsx
new file mode 100644
index 00000000..aa70d803
--- /dev/null
+++ b/src/forge/Component/Monaco.jsx
@@ -0,0 +1,62 @@
+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 (
+
+
+
+ );
+}
+
+export default Monaco;
\ No newline at end of file
diff --git a/src/forge/Component/PasswordAuthority.jsx b/src/forge/Component/PasswordAuthority.jsx
index 9951f32e..e15cb53f 100644
--- a/src/forge/Component/PasswordAuthority.jsx
+++ b/src/forge/Component/PasswordAuthority.jsx
@@ -11,6 +11,7 @@ function PasswordAuthority({ authorityValBox , successFunc , cancelFunc }){
// 取消授权-登录密码的输入
function cancelAuthority(){
+ setAuthorityVal(undefined);
cancelFunc();
}
// 确认授权
diff --git a/src/forge/Component/Releases.jsx b/src/forge/Component/Releases.jsx
new file mode 100644
index 00000000..d8c5e86f
--- /dev/null
+++ b/src/forge/Component/Releases.jsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { AlignCenter , AlignTop , FlexAJ } from '../Component/layout';
+import { Link } from 'react-router-dom';
+
+function Releases({owner,projectsId,releaseVersions , baseOperate , projectType}){
+
+ return(
+
+
+ 发行版
+ { releaseVersions && releaseVersions.total_count > 0 && {releaseVersions.total_count}}
+
+ {
+ releaseVersions && releaseVersions.total_count>0 ?
+ releaseVersions.list.map((item,key)=>{
+ return(
+ key === 0 &&
+
+
+ 发布{item.name}版本
+ 最新
+
+ {item.created_at}
+
+
+ )
+ })
+ :
+
+ 您暂未发布任何版本{baseOperate && projectType !==2 && 创建新版本}
+
+ }
+
+
+ )
+}
+export default Releases;
\ No newline at end of file
diff --git a/src/forge/Component/Search.jsx b/src/forge/Component/Search.jsx
index 676006c5..19111ec2 100644
--- a/src/forge/Component/Search.jsx
+++ b/src/forge/Component/Search.jsx
@@ -2,13 +2,15 @@ import React from "react";
import { Input } from "antd";
const { Search } = Input;
-export default ({ placeholder , onSearch }) => {
+export default ({ placeholder , onSearch , onChange }) => {
return (
)
};
diff --git a/src/forge/Component/SearchUser.jsx b/src/forge/Component/SearchUser.jsx
index 1df7ec64..79d23fb6 100644
--- a/src/forge/Component/SearchUser.jsx
+++ b/src/forge/Component/SearchUser.jsx
@@ -2,52 +2,53 @@ import React , { useState , useEffect } from 'react';
import { AutoComplete } from 'antd';
import { getImageUrl } from "educoder";
import axios from 'axios';
+
const Option = AutoComplete.Option;
-export default ({ getUser })=>{
+export default ({ getUser , placeholder, width ,value })=>{
+ const [ source , setSource ] = useState(undefined);
const [ searchKey , setSearchKey ] = useState(undefined);
- const [ userDataSource , setUserDataSource ] = useState(undefined);
+
+ useEffect(()=>{
+ if(!value){
+ setSearchKey(undefined);
+ }
+ },[value])
+
+ useEffect(()=>{
+ getUserList();
+ },[searchKey])
function getUserList(e){
const url = `/users/list.json`;
axios.get(url, {
params: {
- search: e,
+ search: searchKey,
},
- })
- .then((result) => {
+ }).then((result) => {
if (result) {
- setUserDataSource(result.data.users);
+ sourceOptions(result.data.users);
}
})
.catch((error) => {
console.log(error);
});
};
-
- function changeInputUser(value){
- setSearchKey(value);
- getUserList(value);
- }
- function selectInputUser(id, option){
- setSearchKey(option.props.searchValue);
- getUserList(option.props.searchValue);
- getUser && getUser(id);
- }
- const source =
- userDataSource && userDataSource.map((item, key) => {
+ function sourceOptions(userDataSource){
+ const s = userDataSource && userDataSource.map((item, key) => {
return (
);
});
+ setSource(s);
+ }
+
+ function changeInputUser(e){
+ setSearchKey(e);
+ };
+
+ // 选择用户
+ function selectInputUser(e, option){
+ setSearchKey(option.props.name);
+ getUser(option.props.login);
+ };
+
return(
-
+
+ trigger.parentNode}
+ dataSource={source}
+ value={searchKey}
+ style={{ width: width || 300 }}
+ onChange={changeInputUser}
+ onSelect={selectInputUser}
+ placeholder={placeholder || "搜索需要添加的用户..."}
+ allowClear
+ />
+
)
}
\ No newline at end of file
diff --git a/src/forge/Component/SiderBar.js b/src/forge/Component/SiderBar.js
new file mode 100644
index 00000000..3d6b8acf
--- /dev/null
+++ b/src/forge/Component/SiderBar.js
@@ -0,0 +1,91 @@
+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
+ 帮助
+
+ {
+ list && list.map((i,k)=>{
+ return(
+ - {i.question}
+ )
+ })
+ }
+
+
+ }
+
+ function shareContent(){
+ return
+
+ 分享到
+ - setVisible(true)}>
+
+
+ }
+ return (
+
+ setVisible(false)}/>
+ {
+ data && data.length > 0 && (data[0] && data[0].question) ?
+
+
+
+
+
+ :""
+ }
+ {/*
+
+ */}
+
+
+
+
+
+
+
+ )
+}
+
+export default SiderBar;
diff --git a/src/forge/Component/SiderBarShareModal.jsx b/src/forge/Component/SiderBarShareModal.jsx
new file mode 100644
index 00000000..aa8db379
--- /dev/null
+++ b/src/forge/Component/SiderBarShareModal.jsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import { Modal } from 'antd';
+import QRCode from 'qrcode.react';
+
+function SiderBarShareModal({visible,urlValue,onCancel}) {
+ return(
+
+
+ {urlValue && }
+ 打开微信“扫一扫”,点击右上角菜单,即可将网页分享至朋友圈
+
+
+ )
+}
+export default SiderBarShareModal;
\ No newline at end of file
diff --git a/src/forge/Component/User.jsx b/src/forge/Component/User.jsx
index 1c6bf9a9..4d22c77b 100644
--- a/src/forge/Component/User.jsx
+++ b/src/forge/Component/User.jsx
@@ -1,8 +1,8 @@
import React from 'react';
import styled from 'styled-components';
+import { Link } from 'react-router-dom';
-
-export default ({ url , name , column })=>{
+export default ({ url , name , column , id , login })=>{
const Img = styled.span`
display:flex;
${column && "flex-direction: column;text-align:center;"}
@@ -19,8 +19,16 @@ export default ({ url , name , column })=>{
}
`;
return(
+ id?
+
+
+ { url &&
}
+ {name}
+
+
+ :
-
+ { url &&
}
{name}
)
diff --git a/src/forge/Component/layout.jsx b/src/forge/Component/layout.jsx
index f59a8e34..adaf4dbf 100644
--- a/src/forge/Component/layout.jsx
+++ b/src/forge/Component/layout.jsx
@@ -24,18 +24,38 @@ export const AlignCenter = styled.div`{
display:flex;
align-items: center;
}`
+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;
- align-item:flex-start;
+ align-items:flex-start;
+}`
+export const LongWidth = styled.div`{
+ flex:1;
+ width:0;
+ border-radius:5px;
+ margin-bottom:30px;
}`
export const Long = styled.div`{
- width:72%;
+ width:78%;
+ border-radius:5px;
+ margin-bottom:30px;
+}`
+export const ShortWidth = styled.div`{
+ width:300px;
border-radius:5px;
margin-bottom:30px;
}`
export const Short = styled.div`{
- width:28%;
+ flex:1;
border-radius:5px;
margin-bottom:30px;
}`
@@ -61,22 +81,24 @@ export const Redline = styled.a`{
line-height:28px;
border-radius:2px;
border:1px solid #F73030;
- color:#F73030;
+ color:${props => (props.bold ? "#fff" : "#F73030")} !important;
padding:0px 12px;
display:inline-block;
min-width:80px;
text-align:center;
+ background:${props => (props.bold ? "#F73030" : "#fff")};
}`
export const Greenline = styled.a`{
height:30px;
line-height:28px;
border-radius:2px;
border:1px solid #28BD6C;
- color:#28BD6C;
+ color:${props => (props.bold ? "#fff" : "#28BD6C")} !important;
padding:0px 12px;
display:inline-block;
min-width:80px;
text-align:center;
+ background:${props => (props.bold ? "#28BD6C" : "#fff")};
}`
export const Greenback = styled.a`{
height:30px;
@@ -94,7 +116,7 @@ export const Blueback = styled.a`{
line-height:30px;
border-radius:2px;
background-color:rgba(80,145,255,1);
- color:#fff;
+ color:#fff!important;
padding:0px 12px;
display:inline-block;
min-width:80px;
@@ -154,3 +176,9 @@ export const Content = styled.div`{
background-color:#fff;
justify-content: center;
}`
+export const GroupProjectBackgroup = styled.div`{
+ background:#fafafa;
+ padding:20px 30px;
+ width:100%;
+}`
+
diff --git a/src/forge/DevOps/About.jsx b/src/forge/DevOps/About.jsx
index d3e5c184..b9524d54 100644
--- a/src/forge/DevOps/About.jsx
+++ b/src/forge/DevOps/About.jsx
@@ -1,9 +1,10 @@
import React, { forwardRef, useCallback, useState , useEffect } from "react";
import activate from "../Images/activate.png";
-import { Blueback , AlignCenter } from "../Component/layout";
+import { AlignCenter, Blueback } from "../Component/layout";
import PasswordAuthority from "../Component/PasswordAuthority";
import styled from "styled-components";
-import { Form, Input , Spin , Modal } from "antd";
+import { Form, Input , Spin , Button } from "antd";
+import ServiceModal from './ServiceModal';
import axios from "axios";
const P = styled.p`
@@ -20,18 +21,22 @@ const P = styled.p`
function About(props, ref) {
const { form: { getFieldDecorator, validateFields , setFieldsValue } } = props;
const [isSpining, setIsSpining] = useState(true);
- const [ authorityValBox , setAuthorityValBox ] = useState(false);
+
+ // 认证密码
const [ authorityVal , setAuthorityVal ] = useState(undefined);
const [ authorityValFlag , setAuthorityValFlag ] = useState(false);
+
//0: 标识未开启devops
//1: 标识用户已填写了云服务器相关信息,但并未开启认证
- const [step, setStep] = useState(undefined);
- // step大于1时:为true,不能再修改服务器信息
+ const [step, setStep] = useState(0);
+
const owner = props.match.params.owner;
+ const { user } = props;
const projectsId = props.match.params.projectsId;
+ const [ disabled, setDisabled ] = useState(false);
+ const [ typeFlag, setTypeFlag] = useState(false);
-
- const AuthorLogin = props.author && props.author.login;
+ const AuthorLogin = props.projectDetail && props.projectDetail.author && props.projectDetail.author.login;
const CurrentLogin = props.current_user && props.current_user.login;
useEffect(()=>{
if(CurrentLogin === AuthorLogin){
@@ -47,12 +52,12 @@ function About(props, ref) {
method:`${type}`,
url
}).then(result=>{
+ setIsSpining(false);
if(result && result.data ){
- setIsSpining(false);
setStep(result.data.step);
- setFieldsValue({...result.data.cloud_account});
}
}).catch(error=>{
+ setIsSpining(false);
console.log(error);
})
}
@@ -72,8 +77,8 @@ function About(props, ref) {
function goStep() {
validateFields((error, values) => {
if (!error) {
- if(step > 0){
- setAuthorityValBox(true);
+ if(disabled){
+ setStep(1);
}else{
setIsSpining(true);
const url = `/${owner}/${projectsId}/cloud_accounts.json`;
@@ -82,7 +87,6 @@ function About(props, ref) {
if (result && result.data.redirect_url) {
props.showNotification("服务器信息配置完成!");
setStep(1);
- setAuthorityValBox(true);
}
})
.catch((error) => {
@@ -94,6 +98,50 @@ function About(props, ref) {
});
}
+ // 选择服务器后调用接口,点击下一步(1是自有服务器,2是trustie服务器)
+ function sureModal(type){
+ if(type === 2){
+ setTypeFlag(false);
+ setIsSpining(true);
+ const url = `/users/ci/cloud_account/trustie_bind.json`;
+ axios.post(url,{
+ account:user && user.login
+ }).then(result=>{
+ setIsSpining(false);
+ if(result && result.data){
+ setStep(result.data.step);
+ }
+ }).catch(error=>{setIsSpining(false)})
+ }else{
+ setTypeFlag(true);
+ }
+ }
+
+ // 上一步
+ function goUpStep(step){
+ setTypeFlag(false);
+ setStep(step);
+ }
+
+ // 输入用户密码后下一步
+ function authStep(){
+ if(!authorityVal){
+ setAuthorityValFlag(true);
+ return;
+ }
+ setAuthorityValFlag(false);
+ setIsSpining(true);
+ const url = `/users/ci/oauth_grant.json`;
+ axios.get(url,{
+ params:{password:authorityVal}
+ }).then(result=>{
+ setIsSpining(false);
+ if(result){
+ setStep(result.data.step);
+ }
+ }).catch(error=>{setIsSpining(false)});
+ }
+
// 开始激活
function startActive(){
setIsSpining(true);
@@ -111,73 +159,89 @@ function About(props, ref) {
setIsSpining(false);
})
}
- // 取消授权-登录密码的输入
- function cancelAuthority(){
- setAuthorityValBox(false);
- }
- // 确认授权
- function okAuthority(step){
- setAuthorityValBox(false);
- setStep(step);
- }
+
return (
-
+ {/* */}
定义DevOps工作流,帮助您检测bug、发布代码…
{
- CurrentLogin !== AuthorLogin && (step === undefined || (step && step < 1)) &&
- DevOps开启功能暂未对项目创建者以外的角色开放,可以联系项目创建者进行开启,开启后便可查看构建信息。
+ CurrentLogin !== AuthorLogin ?
+ DevOps开启功能暂未对项目创建者以外的角色开放,可以联系项目创建者进行开启,开启后便可查看构建信息。:""
}
-
+
了解什么是DevOps?
-
+
如何使用DevOps?
{
AuthorLogin === CurrentLogin ?
- { step <=1 ?
-
-
-
- 下一步
-
- :""}
- {step > 1 &&
+ {
+ step === 0 && !typeFlag ?
+
+ :""
+ }
+ { step === 0 && typeFlag ?
+
+
+
+
+ { !disabled && }
+ 下一步
+
+
+ :""
+ }
+ {
+ step === 1 ?
+
+
+ 密码:
+
+ setAuthorityVal(e.target.value)} style={{width:"220px"}}>
+ 您已保存相关服务器信息,请输入密码,
确认授权DevOps应用
+
+
+
+ 下一步
+
+ :""
+ }
+ { step === 2 ?
开始激活
-
+ :""
}
:""
diff --git a/src/forge/DevOps/Dispose.jsx b/src/forge/DevOps/Dispose.jsx
index f8aad2eb..2211dbb5 100644
--- a/src/forge/DevOps/Dispose.jsx
+++ b/src/forge/DevOps/Dispose.jsx
@@ -1,118 +1,166 @@
import React , { useState , useEffect } from 'react';
-import { Spin } from 'antd';
+import { Spin , Pagination } from 'antd';
import { Blueback } from '../Component/layout';
-import Editor from "react-monaco-editor";
-import Modals from './DisposeModal';
-import FileLanguage from '../Component/OpsFileLanguage';
+import List from './Dispose/List';
+import Head from './Dispose/head';
import axios from 'axios';
+import PipelineName from './Dispose/PipelineName';
+import styled from 'styled-components';
+const Div = styled.div`{
+ padding:24px 30px;
+}`;
+const limit = 15;
function Dispose(props){
- const [ spining , setSpining ] = useState(true);
- const [ info , setInfo ] = useState('.trustie-pipeline.yml');
+ const [ spining , setSpining ] = useState(true);
+ const [ updateInfo , setUpdateInfo ] = useState(undefined);
+ const [ list , setList ] = useState(undefined);
+ const [ permission , setPermission ] = useState(undefined);
const [ visible , setVisible ] = useState(false);
- const [ ymlValue , setYmlValue ] = useState("");
- const [ sha , setSha ] = useState(undefined);
- const [ fileLanguage , setFileLanguage ] = useState(undefined);
- const [ first , setFirst ] = useState(false);
+ const [ page , setPage ] = useState(1);
+ const [ totalCount , setTotalCount ] = useState(0);
+ const [ branchList , setBranchList ] =useState(undefined);
+
+ const projectDetail = props.projectDetail;
+ const current_user = props.current_user;
let projectsId = props.match.params.projectsId;
let owner = props.match.params.owner;
+
+ // 获取用户的身份角色
useEffect(()=>{
- if(projectsId){
- const url = `/${owner}/${projectsId}/get_trustie_pipeline.json`;
- axios.get(url,{
- params:{
- project_id:projectsId
- }
- }).then(result=>{
- if(result && result.data.content){
- setInfo(result.data.name);
- setYmlValue(result.data.content);
- setFirst(true);
- setSha(result.data.sha);
- }else{
- setFirst(false);
- }
- setSpining(false);
- }).catch(error=>{
- console.log(error);
- })
+ if(projectDetail){
+ setPermission(props.projectDetail.permission);
}
- },[projectsId])
+ },[projectDetail])
- // 修改文件内容
- function changeEditor(value){
- setYmlValue(value);
+ function Init(){
+ const url = `/ci/pipelines/list.json`;
+ axios.get(url,{
+ params:{
+ identifier:projectsId,owner,
+ page,limit
+ }
+ }).then(result=>{
+ if(result && result.data){
+ setList(result.data.pipelines);
+ }
+ setSpining(false);
+ }).catch(error=>{setSpining(false);})
}
- // 切换语言
- function select_language(value,array){
- setFileLanguage(value);
- setYmlValue( array && array.content);
- }
+ useEffect(()=>{
+ Init();
+ },[page])
- // 确定提交
- function submit(){
- let url = '';
- const { defaultBranch } = props;
- let params = {
- branch: defaultBranch,
- content:ymlValue,
- filepath:info,
- message:''
- }
- if(first){
- // 为true,则是编辑否则是新建
- url = `/${owner}/${projectsId}/update_trustie_pipeline.json`;
- axios.put(url,{
- ...params,
- sha
- }).then(result=>{
- if(result){
- setVisible(true);
+ useEffect(()=>{
+ if(owner && projectsId){
+ const url = `/${owner}/${projectsId}/branches.json`;
+ axios.get(url).then(result=>{
+ if(result && result.data){
+ setBranchList(result.data);
}
- }).catch(error=>{
- console.log(error);
- })
+ }).catch(error=>{})
+ }
+ },[owner,projectsId])
+
+ // 新增/编辑流水线
+ function addNew(pipeline_name,id,branch,event){
+ setVisible(true);
+ setUpdateInfo(undefined);
+ if(pipeline_name){
+ let eventA = event.split(",");
+ let l = {pipeline_name,id,branch,event:eventA}
+ setUpdateInfo(l);
}else{
- url = `/${owner}/${projectsId}/create_file.json`;
- axios.post(url,params).then(result=>{
- if(result){
- setVisible(true);
- }
- }).catch(error=>{
- console.log(error);
- })
+ setUpdateInfo(undefined);
}
}
- function suresubmit(){
- setVisible(false);
- props.history.push(`/projects/${owner}/${projectsId}/devops/list`);
+
+ function onOk(pipeline_name,updateId,branch,event){
+ if(pipeline_name){
+ let eventStr = "";
+ for(var i = 0;i{
+ setVisible(false);
+ if(result && result.data){
+ props.showNotification("流水线新增成功,请进行工作流配置!");
+ props.history.push(`/projects/${owner}/${projectsId}/devops/dispose/${result.data.id}`);
+ }else{
+ props.showNotification("流水线新增失败,请稍后再试!");
+ }
+ }).catch(error=>{})
+ }else{
+ // 修改
+ const url = `/ci/pipelines/${updateId}.json`;
+ axios.put(url,{
+ pipeline_name,repo:projectsId,branch,event:eventStr,owner
+ }).then(result=>{
+ if(result && result.data){
+ setVisible(false);
+ Init();
+ props.showNotification("流水线名称更新成功!");
+ }else{
+ props.showNotification("流水线名称更新失败,请稍后再试!");
+ }
+ }).catch(error=>{})
+ }
+ }else{
+ props.showNotification("请输入流水线名称!");
+ }
}
-
+
+ // 删除
+ function deleteFunc(id){
+ const url = `/ci/pipelines/${id}.json`;
+ axios.delete(url).then(result=>{
+ if(result && result.data){
+ props.showNotification("流水线删除成功!");
+ Init();
+ }
+ }).catch(error=>{})
+ }
+
+ // 模板管理
+ function toModalManage(){
+ props.history.push(`/projects/${owner}/${projectsId}/devops/mould`);
+ }
+
+ // 参数管理
+ function toparameter(){
+ props.history.push(`/projects/${owner}/${projectsId}/devops/params`);
+ }
+
+ const operate = current_user && (permission && permission !== "Reporter");
return(
- setVisible(flag)} sureFunc={suresubmit}>
- 编程语言:
-
-
-
+ setVisible(false)} onOk={onOk}/>
+
+
+
+ { operate && addNew(undefined,undefined)}>新增流水线 }
+
+
+ {
+ totalCount > limit &&
+
+ setPage(page)}/>
+
+ }
+
+
- 配置脚本:
-
- {info}
-
-
- 确定提交
)
}
diff --git a/src/forge/DevOps/Dispose/Choosen.jsx b/src/forge/DevOps/Dispose/Choosen.jsx
new file mode 100644
index 00000000..7cbef52b
--- /dev/null
+++ b/src/forge/DevOps/Dispose/Choosen.jsx
@@ -0,0 +1,100 @@
+import React , { useEffect , useState } from 'react';
+
+function Choosen({ chooseFunc, temp , templateId , category }){
+ const [ tempId, setTemId ] = useState(undefined);
+ const [ cate , setCate ]= useState(undefined);
+ const [ templates , setTemplates ] = useState(undefined);
+ const [ categories , setCategories ] = useState(undefined);
+
+ useEffect(()=>{
+ if(templateId){
+ setTemId(templateId);
+ }
+ },[templateId])
+
+ useEffect(()=>{
+ if(category){
+ setCate(category);
+ }
+ },[category])
+
+
+ useEffect(()=>{
+ if(temp && temp.length > 0){
+ if(temp[0].category !== "初始化"){
+ setCategories(temp);
+ }else{
+ setCategories(undefined);
+ }
+ if(category && temp[0].category !== "初始化" && category !== "初始化"){
+ let c = temp.filter(item=>item.category === category);
+ let t = c && c.length > 0 && c[0].templates;
+ setTemplates(t);
+ setCate(category);
+ }else{
+ setTemplates(temp[0].templates);
+ setCate(temp[0].category);
+ }
+ }else{
+ setTemplates(undefined);
+ setCate(undefined);
+ setCategories(undefined);
+ }
+ },[temp,category])
+
+ // 选择类别
+ function changeCate(cate){
+ setCate(cate);
+ let c = categories && categories.filter(item=>item.category === cate);
+ let t = c && c[0].templates;
+ setTemplates(t);
+ let m_t_id = t && t.length>0 && t[0].id;
+ let m_t_content = t && t.length>0 && t[0].content;
+ setTemId(m_t_id);
+ chooseFunc && chooseFunc(m_t_content,m_t_id,cate);
+ }
+
+
+ // 选择模板
+ function chooseOption(id){
+ let item = templates.filter(item=>item.id === id);
+ let content = item && item.length >0 && item[0].content;
+ chooseFunc && chooseFunc(content,id,cate);
+ setTemId(id);
+ }
+
+ return(
+
+ {
+ categories && categories.length > 0 &&
+
+ 模板类别:
+
+ {
+ categories.map((item,key)=>{
+ return(
+ - changeCate(item.category)}>{item.category}
)
+ })
+ }
+
+
+ }
+ {
+ templates && templates.length> 0 &&
+
+ 模板选择:
+
+ {
+ templates.map((item,key)=>{
+ return(
+ - chooseOption(item.id)}>{item.template_name}
+ )
+ })
+ }
+
+
+ }
+
+ )
+}
+export default Choosen;
\ No newline at end of file
diff --git a/src/forge/DevOps/Dispose/Editors.jsx b/src/forge/DevOps/Dispose/Editors.jsx
new file mode 100644
index 00000000..49c17446
--- /dev/null
+++ b/src/forge/DevOps/Dispose/Editors.jsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import Editor from 'react-monaco-editor';
+
+function Editors({value,onChange,theme,height,visible,width="100%",Numbers="on"}){
+ const editor_options = {
+ lineNumbers: Numbers,
+ wordWrap: true, //强制换行
+ selectOnLineNumbers: true,
+ lineHeight: 24,
+ renderLineHighlight: "line",
+ revealHorizontalRightPadding: 5,
+ placeholder:"请输入内容",
+ readOnly: visible,
+ cursorStyle: visible ? "underline-thin" : "line",
+ folding: true,
+ foldingStrategy: "indentation", // 代码可分小段折叠
+ automaticLayout: true, // 自适应布局
+ minimap: {
+ // 不要小地图
+ enabled: false,
+ },
+ }
+ return(
+ onChange(value)}
+ disabled={true}
+ >
+ )
+}
+export default Editors;
\ No newline at end of file
diff --git a/src/forge/DevOps/Dispose/Init.jsx b/src/forge/DevOps/Dispose/Init.jsx
new file mode 100644
index 00000000..86477482
--- /dev/null
+++ b/src/forge/DevOps/Dispose/Init.jsx
@@ -0,0 +1,66 @@
+import React , { useEffect , useState } from 'react';
+import { Button } from 'antd';
+import Choosen from './Choosen';
+import Editors from './Editors';
+
+function Init({ datas , templates , saveFunc , saveDatas}){
+ const [ templateId , setTemplateId ] = useState(undefined);
+ const [ ymlValue , setYmlValue ] = useState(undefined);
+ const [ temp , setTemp ] = useState(undefined);
+
+ useEffect(()=>{
+ if(templates && templates.length > 0){
+ setTemp(templates)
+ }
+ },[templates])
+
+ useEffect(()=>{
+ if(datas && datas.length > 0){
+ setTemplateId(datas[0].template_id);
+ setYmlValue(datas[0].content);
+ }
+ },[datas])
+
+ // 选择模板
+ function chooseFunc(content,id,cate){
+ setTemplateId(id);
+ setYmlValue(content);
+ recieveData(id,content);
+ }
+
+ function recieveData(id,content){
+ let steps = datas;
+ if(datas && datas.length>0){
+ steps[0].content = content || ymlValue;
+ steps[0].template_id = id || templateId ;
+ }else{
+ steps =
+ [{
+ step_name:"初始化",
+ show_index:1,
+ content:content || ymlValue,
+ template_id:id || templateId
+ }]
+ }
+ saveDatas(steps);
+ }
+
+ // 点击下一步时
+ function nextStep(){
+ recieveData();
+ saveFunc(undefined,undefined,undefined,undefined,"next");
+ }
+
+ return(
+
+
+
+
+
+
+
+
+
+ )
+}
+export default Init;
\ No newline at end of file
diff --git a/src/forge/DevOps/Dispose/List.jsx b/src/forge/DevOps/Dispose/List.jsx
new file mode 100644
index 00000000..4c077452
--- /dev/null
+++ b/src/forge/DevOps/Dispose/List.jsx
@@ -0,0 +1,138 @@
+import React from 'react';
+import { Table , Popconfirm } from 'antd';
+import { Link } from 'react-router-dom';
+
+// const STATUS = {
+// running:"运行中",
+// failure:"未通过",
+// error:"未通过",
+// success:"已通过",
+// 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":
+ return (
+
+ 运行中
+
+ );
+ case "failure": case 'error':
+ return (
+
+ 未通过
+
+ );
+ case "success":
+ return (
+
+ 已通过
+
+ );
+ case 'killed':
+ return (
+
+ 已撤销
+
+ );
+ default :
+ return (
+
+ 准备中
+
+ );
+ }
+}
+function List({ list, operate , projectsId , owner , showModal , deleteFunc }){
+
+ const columns = [
+ {
+ title:"流水线名称",
+ dataIndex:"pipeline_name",
+ key:1,
+ ellipsis:true,
+ render:(txt,item)=>{
+ return(
+ showModal(txt,item.id,item.branch,item.event)} style={{display:"block",cursor:"pointer"}}>{txt}
+ )
+ }
+ },
+ {
+ title:"文件名称",
+ dataIndex:"file_name",
+ key:1,
+ width:"15%",
+ ellipsis:true,
+ render:(value,item)=>{
+ let v = turnbar(item.branch);
+ return(
+ {value}
+ )
+ }
+ },
+ {
+ title:"触发分支",
+ dataIndex:"branch",
+ key:1,
+ width:"10%",
+ ellipsis:true
+ },
+ {
+ title:"触发事件",
+ dataIndex:"event",
+ key:1,
+ width:"10%",
+ ellipsis:true
+ },
+ {
+ title:"最近构建时间",
+ dataIndex:"last_build_time",
+ key:1,
+ width:"15%",
+ ellipsis:true
+ },
+ {
+ title:"最近构建状态",
+ dataIndex:"pipeline_status",
+ key:1,
+ width:"12%",
+ ellipsis:true,
+ render:(txt)=>{
+ return renderTableStatus(txt)
+ }
+ },
+ {
+ title:"操作",
+ dataIndex:"operation",
+ key:1,
+ width:"21%",
+ render:(txt,item)=>{
+ return(
+
+ { operate ?
+
+ 编辑 :""
+ }
+ { operate ?
+ deleteFunc(item.id)} okText="确定" cancelText={"取消"}>
+ 删除
+ :""
+ }
+ 查看运行记录
+
+ )
+ }
+ }
+ ]
+ return(
+ row.id} pagination={false}>
+ )
+}
+export default List;
\ No newline at end of file
diff --git a/src/forge/DevOps/Dispose/PipelineName.jsx b/src/forge/DevOps/Dispose/PipelineName.jsx
new file mode 100644
index 00000000..4acaa206
--- /dev/null
+++ b/src/forge/DevOps/Dispose/PipelineName.jsx
@@ -0,0 +1,67 @@
+import React , { useEffect , useState } from 'react';
+import { Modal , Input , Select } from 'antd';
+const { Option }= Select;
+
+const EVENT = ["push","pull_request","tag","cron","custom","promote","rollback"]
+function PipelineName({visible,onCancel,onOk,value ,branchList}){
+ const [ name , setName ] = useState(undefined);
+ const [ branchValue , setBranchValue ] = useState(undefined);
+ const [ eventValue , setEventValue ] = useState([EVENT[0]]);
+
+ useEffect(()=>{
+ if(branchList && branchList.length>0){
+ setBranchValue(branchList[0].name);
+ }
+ },[branchList])
+
+ useEffect(()=>{
+ if(value){
+ setName(value.pipeline_name);
+ setBranchValue(value.branch);
+ setEventValue(value.event);
+ }else{
+ setName(undefined);
+ }
+ },[value])
+
+ function onSure(){
+ onOk(name,value && value.id,branchValue,eventValue);
+ }
+ return(
+
+
+ 流水线名称:
+ setName(e.target.value)} placeholder="请输入名称" style={{width:"340px",margin:"6px 0px"}}/>
+
+
+ 触发条件:
+
+
+
+
+ )
+}
+export default PipelineName;
\ No newline at end of file
diff --git a/src/forge/DevOps/Dispose/Stage.jsx b/src/forge/DevOps/Dispose/Stage.jsx
new file mode 100644
index 00000000..e31cabf5
--- /dev/null
+++ b/src/forge/DevOps/Dispose/Stage.jsx
@@ -0,0 +1,102 @@
+import React , { useEffect , useState } from 'react';
+import { Button , Popconfirm } from 'antd';
+import { Cancel } from '../../Component/layout';
+import Item from './StageItem';
+
+function Stage({
+ templates ,
+ datas ,
+ saveDatas ,
+ saveFunc ,
+ stepName ,
+ deleteStep ,
+ deleteFunc ,
+ deleteFlag
+}){
+ const [ stepList , setStepList ] = useState(undefined);
+ const [ temp , setTemp ] = useState(undefined);
+
+ useEffect(()=>{
+ if(templates && templates.length > 0){
+ setTemp(templates);
+ }
+ },[templates])
+
+ useEffect(()=>{
+ if(datas){
+ if(datas.length > 0 && stepList !== datas){
+ setStepList(datas);
+ }else if(datas.length === 0){
+ let list = [];
+ setStepList(list);
+ }
+ }
+ },[datas])
+
+ // 添加步骤
+ function addFunc(){
+ let list = stepList;
+ let length = list ? list.length : 0;
+ let pre = temp && temp.length > 0 && temp[0];
+ let c = pre && pre.category;
+ let child = pre && pre.templates && pre.templates.length > 0 && pre.templates[0];
+ let step =
+ {
+ "category":c,
+ "step_name": stepName+`${length + 1}`,
+ "show_index": length + 1,
+ "content":child.content,
+ "template_id":child.id,
+ "hide":false
+ }
+ list.push(step);
+ saveDatas(list);
+ }
+
+ // 将修改的对应项保存在数组中
+ function saveItems(content,id,cate,key){
+ let item = stepList;
+ item[key].content = content;
+ item[key].template_id = id;
+ item[key].category = cate;
+ saveDatas([...item]);
+ }
+
+ function slideItems(key,hide){
+ let item = stepList;
+ item[key].hide = !hide;
+ setStepList([...item]);
+ saveDatas(item);
+ }
+
+ function deleteItem(id,key){
+ deleteStep(id,key);
+ }
+ // 点击下一步时
+ function nextStep(btn){
+ saveFunc(undefined,undefined,undefined,undefined,btn);
+ }
+
+ return(
+
+ {
+ stepList && stepList.length > 0 && stepList.map((item,key)=>{
+ return(
+ -
+ )
+ })
+ }
+ + 添加步骤
+
+
+
+ {!deleteFlag &&
+
+ 删除
+
+ }
+
+
+ )
+}
+export default Stage;
\ No newline at end of file
diff --git a/src/forge/DevOps/Dispose/StageItem.jsx b/src/forge/DevOps/Dispose/StageItem.jsx
new file mode 100644
index 00000000..db461eb1
--- /dev/null
+++ b/src/forge/DevOps/Dispose/StageItem.jsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import { FlexAJ } from '../../Component/layout';
+import Editors from './Editors';
+import Choosen from './Choosen';
+import { Popconfirm } from 'antd';
+
+
+function StageItem({item, templates,saveItems,k, slideItems , deleteStep}){
+
+ function onChangevalue(value){
+ saveItems(value,item.template_id,item.category,k);
+ }
+ // 选择模板
+ function chooseFunc(content,id,cate){
+ saveItems(content,id,cate,k);
+ }
+
+ return(
+
+
+ {item.step_name}
+
+ deleteStep(item.id,k)}
+ >
+
+
+ slideItems(k,item.hide)}>
+
+
+
+
+
+
+
+ )
+}
+export default StageItem;
\ No newline at end of file
diff --git a/src/forge/DevOps/Dispose/Sure.jsx b/src/forge/DevOps/Dispose/Sure.jsx
new file mode 100644
index 00000000..1195e1bd
--- /dev/null
+++ b/src/forge/DevOps/Dispose/Sure.jsx
@@ -0,0 +1,32 @@
+import React ,{useEffect , useState} from 'react';
+import { Button } from 'antd';
+import Editors from './Editors';
+
+function Sure({datas , name , saveFunc , sureSubmit , loading}){
+ const [ value , setValue ] = useState(undefined);
+ useEffect(()=>{
+ if(datas && datas.content){
+ setValue(datas.content)
+ }
+ },[datas]);
+
+ function sure(){
+ sureSubmit();
+ }
+
+ return(
+
+
+ 工作流名称:{name}
+
+
+
+
+
+
+ { value && }
+
+
+ )
+}
+export default Sure;
\ No newline at end of file
diff --git a/src/forge/DevOps/Dispose/head.jsx b/src/forge/DevOps/Dispose/head.jsx
new file mode 100644
index 00000000..5ba168bb
--- /dev/null
+++ b/src/forge/DevOps/Dispose/head.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import { AlignCenterBetween , Blueline , FlexAJ } from '../../Component/layout';
+
+
+function head({manager , parameter}){
+ return(
+
+ 工作流配置
+
+ {
+ parameter && 参数管理
+ }
+ {
+ manager && 模板管理
+ }
+ 模板使用说明
+
+
+ )
+}
+export default head;
\ No newline at end of file
diff --git a/src/forge/DevOps/Dispose/menus.jsx b/src/forge/DevOps/Dispose/menus.jsx
new file mode 100644
index 00000000..c598cad8
--- /dev/null
+++ b/src/forge/DevOps/Dispose/menus.jsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import MenusRename from './menusRename';
+import MenusAdd from './menusAdd';
+
+const typeIcon = {
+ init:"icon-initialize",build:"icon-structure",deploy:"icon-arrange",customize:"icon-newStage",confirm:'icon-sure'
+}
+
+function Menus({step,changeStep, menuList , renameFunc , checkDatas , addFunc }){
+
+ function InitActive(key,stage_type,stage_id,stage_name){
+ changeStep(key,stage_type,stage_id,stage_name);
+ }
+
+ // 新增阶段
+ function getName(name,index){
+ addFunc && addFunc(name,index);
+ }
+
+ return(
+
+ {
+ menuList && menuList.length > 0 && menuList.map((item,key)=>{
+ return(
+
+ - InitActive(item.show_index,item.stage_type,item.id,item.stage_name)} className={item.show_index === step ?"active":""}>
+
+
+
+ { key !== (menuList.length-1) && menuList.length < 7 ?
+ :""
+ }
+
+ )
+ })
+ }
+
+ )
+}
+export default Menus;
\ No newline at end of file
diff --git a/src/forge/DevOps/Dispose/menusAdd.jsx b/src/forge/DevOps/Dispose/menusAdd.jsx
new file mode 100644
index 00000000..88383c45
--- /dev/null
+++ b/src/forge/DevOps/Dispose/menusAdd.jsx
@@ -0,0 +1,55 @@
+import React , { useState , useEffect } from 'react';
+import { Input } from 'antd';
+
+function menusAdd ({ getName , checkDatas , k }){
+ const [ show, setShow ] = useState(false);
+ const [ value , setValue ] = useState(undefined);
+ const [ index , setIndex ] = useState(undefined);
+ const [ref, setRef ] = useState(undefined);
+ const [put, setPut ] = useState(false);
+
+ useEffect(() => {
+ if (put && ref) {
+ ref.focus();
+ }
+ })
+ useEffect(() => {
+ if (k) {
+ setIndex(k);
+ }
+ },[k])
+
+
+ function blurInput(){
+ if(value){
+ getName(value , index);
+ }
+ setValue(undefined);
+ setShow(false);
+ setPut(false);
+ }
+
+ function showInput(){
+ let c = checkDatas();
+ if(c || c === "" ){
+ setShow(true);
+ setPut(true);
+ }
+ }
+
+ return(
+
+ { !show && }
+ setRef(el)}
+ size={"small"}
+ maxLength={8}
+ style={{width:"75px",display : `${show?"block":'none'}`}}
+ placeholder="新阶段名称"
+ value={value}
+ onChange={(e)=>setValue(e.target.value)} onBlur={blurInput}
+ />
+
+ )
+}
+export default menusAdd;
\ No newline at end of file
diff --git a/src/forge/DevOps/Dispose/menusRename.jsx b/src/forge/DevOps/Dispose/menusRename.jsx
new file mode 100644
index 00000000..e657d337
--- /dev/null
+++ b/src/forge/DevOps/Dispose/menusRename.jsx
@@ -0,0 +1,53 @@
+import React , { useEffect , useState } from 'react';
+import { Input } from 'antd';
+
+function menusRename({ name , edit , id , renameFunc }){
+ const [ n , setN ] = useState(undefined);
+ const [ show , setShow ] = useState(false);
+ const [ref, setRef ] = useState(undefined);
+ const [put, setPut ] = useState(false);
+
+ useEffect(() => {
+ if (edit && ref) {
+ ref.focus();
+ }
+ })
+
+ useEffect(()=>{
+ if(name){
+ setN(name)
+ }
+ },[name])
+
+ // 显示input框编辑
+ function changeShow(e){
+ e.stopPropagation();
+ setShow(true);
+ setPut(true);
+ }
+
+ function blurInput(e){
+ renameFunc(e.target.value,id);
+ setPut(false);
+ setShow(false);
+ }
+ return(
+
+
+ { !show && n }
+ setRef(el)}
+ value={n}
+ size="small"
+ maxLength={8}
+ onClick={(e)=>e.stopPropagation()}
+ onBlur={blurInput}
+ style={{width:"75px",display : `${show?"block":'none'}`}}
+ onChange={(e)=>setN(e.target.value)}
+ />
+ { !show && edit && }
+
+
+ )
+}
+export default menusRename
\ No newline at end of file
diff --git a/src/forge/DevOps/Index.jsx b/src/forge/DevOps/Index.jsx
index 77b82eb0..c3a29a3e 100644
--- a/src/forge/DevOps/Index.jsx
+++ b/src/forge/DevOps/Index.jsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React , { useEffect } from 'react';
import { WhiteBack } from '../Component/layout';
import './ops.scss';
@@ -10,27 +10,65 @@ const About = Loadable({
loader: () => import('./About'),
loading: Loading,
})
-const Infos = Loadable({
- loader: () => import('./Infos'),
+const New = Loadable({
+ loader: () => import('./disposePipeline'),
loading: Loading,
})
+const Dispose = Loadable({
+ loader: () => import('./Dispose'),
+ loading: Loading,
+})
+const Stucture = Loadable({
+ loader: () => import('./Structure'),
+ loading: Loading,
+})
+const Mould = Loadable({
+ loader: () => import('./Mould'),
+ loading: Loading,
+})
+const Params = Loadable({
+ loader: () => import('./Manage/Params'),
+ loading: Loading,
+})
+
export default ((props)=>{
+
return(
- ( )
+ (p) => ( )
}
>
- ( )
+ (p) => ( )
+ }
+ >
+ ( )
+ }
+ >
+ ( )
+ }
+ >
+ ( )
+ }
+ >
+ ( )
}
>
( )
+ (p) => ( )
}
>
diff --git a/src/forge/DevOps/Infos.jsx b/src/forge/DevOps/Infos.jsx
index eb9848c5..b5220138 100644
--- a/src/forge/DevOps/Infos.jsx
+++ b/src/forge/DevOps/Infos.jsx
@@ -1,9 +1,8 @@
-import React , { useEffect , useState , useRef } from 'react';
+import React , { useEffect , useState } from 'react';
import { Banner } from '../Component/layout';
import { Link } from 'react-router-dom';
import Dispost from './Dispose';
-import Structure from './Structure';
import styled from 'styled-components';
@@ -11,22 +10,11 @@ const Div = styled.div`{
padding:24px 30px;
}`;
export default ((props)=>{
- const [ menu , setMenu ] = useState(false);
const [ permission , setPermission ] = useState("");
- const childRef = useRef();
- const path = props.location.pathname;
const owner = props.match.params.owner;
- const projectsId = props.match.params.projectsId;
const projectDetail = props.projectDetail;
- useEffect(()=>{
- if(path === `/projects/${owner}/${projectsId}/devops/list`){
- setMenu(true);
- }else{
- setMenu(false);
- }
- },[path])
useEffect(()=>{
if(projectDetail){
@@ -34,23 +22,14 @@ export default ((props)=>{
}
},[projectDetail])
- const updateChildState = () => {
- // changeVal就是子组件暴露给父组件的方法
- if (childRef.current) {
- childRef.current.changeVal();
- }
- }
return(
- { permission !=="Reporter" && 工作流配置}
- 构建列表
- { menu===true && 刷新}
+ { permission !=="Reporter" && 工作流配置}
- { menu === true && childRef.current = form} ref={childRef}/> }
- { menu === false && permission !=="Reporter" && }
+
)
diff --git a/src/forge/DevOps/Manage/Params.jsx b/src/forge/DevOps/Manage/Params.jsx
new file mode 100644
index 00000000..7cb55276
--- /dev/null
+++ b/src/forge/DevOps/Manage/Params.jsx
@@ -0,0 +1,119 @@
+import React , { useEffect , useState , useRef } from 'react';
+import { Banner , Blueback , FlexAJ , AlignCenter } from '../../Component/layout';
+import { Input , Table , Popconfirm , Pagination } from 'antd';
+import { Link } from 'react-router-dom';
+import styled from 'styled-components';
+import New from './ParamsNew';
+import "./manage.scss";
+import axios from 'axios';
+import { result } from 'lodash';
+
+const Div = styled.div`{
+ padding:24px 30px;
+ min-height:420px;
+}`;
+function Params(props){
+ const [ list ,setList ] = useState(undefined);
+ const [ editList ,setEditList ] = useState(undefined);
+ const [ visible ,setVisible ] = useState(false);
+
+ let projectsId = props.match.params.projectsId;
+ let owner = props.match.params.owner;
+
+ useEffect(()=>{
+ Init()
+ },[])
+
+ function Init(){
+ const url = `/ci/secrets.json`;
+ axios.get(url,{
+ params:{
+ owner,repo:projectsId
+ }
+ }).then(result=>{
+ if(result){
+ setList(result.data);
+ }
+ }).catch(error=>{})
+ }
+
+ const columns=[
+ {
+ title:"参数名",
+ dataIndex:"name",
+ key:1,
+ ellipsis:true
+ },
+ {
+ title:"操作",
+ dataIndex:"operation",
+ key:4,
+ render:(txt,item)=>{
+ return(
+
+ editMouldFunc(item)}>编辑
+ deleteMouldFunc(item.id,item.name)} okText="确定" cancelText={"取消"}>
+ 删除
+
+
+ )
+ }
+ }
+ ]
+
+ // 编辑
+ function editMouldFunc(item){
+ setEditList(item);
+ setVisible(true);
+ }
+
+ // 删除
+ function deleteMouldFunc(id,name){
+ if(id && name){
+ const url = `/ci/secrets/${id}.json`;
+ axios.delete(url,{
+ params:{owner,repo:projectsId,name}
+ }).then(result=>{
+ if(result){
+ Init();
+ props.showNotification(`参数删除成功!`);
+ }
+ }).catch(error=>{})
+ }
+ }
+
+ function successFunc(values,id){
+ const url = `/ci/secrets.json?owner=${owner}&repo=${projectsId}`;
+ axios.post(url,{
+ ...values,id
+ }).then(result=>{
+ if(result){
+ props.showNotification(`${id ? '参数编辑':"新增参数"}成功!`);
+ Init();
+ }
+ }).catch(error=>{})
+ }
+
+ function CancelFunc(){
+ setVisible(false)
+ }
+
+ return(
+
+
+
+
+ 工作流 - 参数管理
+ 返回
+
+
+
+
+ setVisible(true)}>新建
+
+ row.id} pagination={false}>
+
+
+ )
+}
+export default Params;
\ No newline at end of file
diff --git a/src/forge/DevOps/Manage/ParamsNew.jsx b/src/forge/DevOps/Manage/ParamsNew.jsx
new file mode 100644
index 00000000..97d41f27
--- /dev/null
+++ b/src/forge/DevOps/Manage/ParamsNew.jsx
@@ -0,0 +1,73 @@
+import React , { useEffect , useState , useRef , forwardRef } from 'react';
+import { Modal , Input , Form } from 'antd';
+
+const { TextArea } = Input;
+
+function ParamsNew({ form , visble,successFunc,CancelFunc ,editList }){
+ const { getFieldDecorator, validateFields , setFieldsValue } = form;
+ const layout = {
+ labelCol: { span: 5 },
+ wrapperCol: { span: 18 },
+ };
+
+ useEffect(()=>{
+ if(editList && editList.id){
+ setFieldsValue({
+ name:editList.name,
+ data:editList.data
+ })
+ }else{
+ setFieldsValue({
+ name:undefined,
+ data:undefined
+ })
+ }
+ },[editList])
+
+ // 确定
+ function onConfirmFunc(){
+ validateFields((error,values)=>{
+ if(!error){
+ successFunc(values,editList && editList.id);
+ onCancelFunc();
+ }
+ })
+ }
+ function onCancelFunc(){
+ setFieldsValue({
+ name:undefined,
+ data:undefined
+ })
+ CancelFunc();
+ }
+ return(
+
+
+ {getFieldDecorator("name",{
+ rules:[{required:true,message:"请输入参数名称"}]
+ })(
+
+ )}
+
+
+ {getFieldDecorator("data",{
+ rules:[{required:true,message:"请输入参数值"}]
+ })(
+
+ )}
+
+
+
+ )
+}
+export default Form.create()(forwardRef(ParamsNew));
\ No newline at end of file
diff --git a/src/forge/DevOps/Manage/manage.scss b/src/forge/DevOps/Manage/manage.scss
new file mode 100644
index 00000000..2add6a86
--- /dev/null
+++ b/src/forge/DevOps/Manage/manage.scss
@@ -0,0 +1,4 @@
+.ant-form-explain{
+ position: absolute;
+ bottom: -15px;
+}
\ No newline at end of file
diff --git a/src/forge/DevOps/Mould.jsx b/src/forge/DevOps/Mould.jsx
new file mode 100644
index 00000000..933299d6
--- /dev/null
+++ b/src/forge/DevOps/Mould.jsx
@@ -0,0 +1,160 @@
+import React , { useEffect , useState , useRef } from 'react';
+import { Banner , Blueback , FlexAJ } from '../Component/layout';
+import { Input , Table ,Pagination , Select , Popconfirm } from 'antd';
+import { Link } from 'react-router-dom'
+import styled from 'styled-components';
+import axios from 'axios';
+import New from './MouldNew';
+
+const { Option } = Select;
+
+const Div = styled.div`{
+ padding:24px 30px;
+ min-height:420px;
+}`;
+const STAGE = [
+ {stage_name:"所有",stage_type:"all"},
+ {stage_name:"初始化",stage_type:"init"},
+ {stage_name:"编译构建",stage_type:"build"},
+ {stage_name:"部署",stage_type:"deploy"},
+ {stage_name:"其他",stage_type:"customize"}
+]
+const limit = 15;
+function Mould(props){
+ const [ visible ,setVisible ] = useState(false);
+ const [ list ,setList ] = useState(undefined);
+ const [ page ,setPage ] = useState(1);
+ const [ totalCount ,setTotalCount ] = useState(0);
+ const [ stageType ,setStageType ] = useState("all");
+ const [ search ,setSearch ] = useState(undefined);
+ const childRef = useRef();
+ let projectsId = props.match.params.projectsId;
+ let owner = props.match.params.owner;
+ useEffect(()=>{
+ Init(page,stageType);
+ },[page,stageType])
+
+ function Init(page,stageType,searchvalue){
+ const url = `/ci/templates/list.json`;
+ axios.get(url,{
+ params:{
+ page,limit,stage_type:stageType,name:searchvalue
+ }
+ }).then(result=>{
+ if(result && result.data){
+ setList(result.data.templates);
+ setTotalCount(result.data.total_count);
+ }
+ }).catch(error=>{})
+ }
+
+ const columns=[
+ {
+ title:"名称",
+ dataIndex:"template_name",
+ key:1,
+ ellipsis:true
+ },
+ {
+ title:"所属阶段",
+ dataIndex:"stage_type",
+ key:2,
+ ellipsis:true,
+ render:(txt,item)=>{
+ let i = STAGE.filter(item=>item.stage_type === txt);
+ return i && i.length>0 && i[0].stage_name
+ }
+ },
+ {
+ title:"模板类型",
+ dataIndex:"category",
+ key:3,
+ ellipsis:true
+ },
+ {
+ title:"操作",
+ dataIndex:"operation",
+ key:4,
+ ellipsis:true,
+ render:(txt,item)=>{
+ return(
+
+ editMouldFunc(item)}>编辑
+ deleteMouldFunc(item.id)} okText="确定" cancelText={"取消"}>
+ 删除
+
+
+ )
+ }
+ }
+ ]
+
+ // 编辑模板
+ function editMouldFunc(item){
+ if (childRef.current) {
+ childRef.current.setEditInfo(item);
+ }
+ setVisible(true);
+ }
+
+ // 删除模板
+ function deleteMouldFunc(id){
+ const url = `/ci/templates/${id}.json`;
+ axios.delete(url).then(result=>{
+ if(result && result.data){
+ props.showNotification("模板删除成功!");
+ Init(page,stageType,search);
+ }
+ })
+ }
+
+ function searchValue(){
+ Init(page,stageType,search);
+ }
+
+ function newMouldFunc(){
+ if (childRef.current) {
+ childRef.current.setEditInfo(undefined);
+ }
+ setVisible(true);
+ }
+
+ function onOk(){
+ Init(page,stageType);
+ }
+ return(
+
+ childRef.current = f} ref={childRef} visible={visible} onCancel={()=>setVisible(false)} onOk={onOk}>
+
+ 工作流 - 模板管理返回
+
+
+
+ 新建模板
+
+ 阶段:
+
+ setSearch(e.target.value)} allowClear style={{width:"160px",marginLeft:"15px"}}/>
+ 搜索
+
+
+ row.id} pagination={false}>
+ {
+ totalCount > limit &&
+
+ setPage(page)}/>
+
+ }
+
+
+ )
+}
+export default Mould;
\ No newline at end of file
diff --git a/src/forge/DevOps/MouldNew.jsx b/src/forge/DevOps/MouldNew.jsx
new file mode 100644
index 00000000..a0d7a465
--- /dev/null
+++ b/src/forge/DevOps/MouldNew.jsx
@@ -0,0 +1,166 @@
+import React , { useImperativeHandle , useState , forwardRef , useCallback } from 'react';
+import { Form , Modal , Input , Select , Spin } from 'antd';
+import Editor from './Dispose/Editors';
+import axios from 'axios';
+
+const { Option } = Select;
+const TYPE = ["Java","C","C++","Python","Go","Ruby","R","PHP",
+ "Perl","Node","Docker","Rust","Swift","Erlang","Other"]
+
+function MouldNew({ form , visible , onCancel , onOk }, ref){
+ const [value , setValue ] = useState(undefined);
+ const [isSpin , setIsSpin ] = useState(false);
+ const [valueFlag , setValueFlag ] = useState(false);
+ const [ id , setId ] = useState(false);
+ const [ buildFlag , setBuildFlag ] = useState(false);
+
+ const { getFieldDecorator, validateFields , setFieldsValue } = form;
+
+ useImperativeHandle(ref, () => ({
+ setEditInfo: (info) => {
+ if(info){
+ setFieldsValue({
+ ...info
+ })
+ if(info.stage_type === "build"){
+ setBuildFlag(true);
+ setFieldsValue({
+ category:TYPE[0]
+ })
+ }else{
+ removeCate();
+ }
+ setValue(info.content);
+ setId(info.id);
+ }else{
+ removeCate();
+ clear();
+ setId(undefined);
+ }
+ }
+ }))
+
+ const helper = useCallback(
+ (label, name, rules, widget, className, isRequired,flag) => (
+
+ {getFieldDecorator(name, { rules, validateFirst: true , valuePropName:flag ? "checked":"value" })(widget)}
+
+ ),
+ []
+ );
+ function changeContent(v){
+ if(v){
+ setValue(v);
+ setValueFlag(false);
+ }
+ }
+ function cancel(){
+ clear();
+ onCancel();
+ }
+ function sure(){
+ if(!value){
+ setValueFlag(true);
+ return;
+ }
+ validateFields((error,values)=>{
+ if(!error){
+ setIsSpin(true);
+ const url = `/ci/templates.json`;
+ axios.post(url,{
+ ...values,id,content:value,category:buildFlag ? values.category:""
+ }).then(result=>{
+ if(result && result.data){
+ setIsSpin(false);
+ cancel();
+ onOk();
+ }
+ }).catch(error=>{})
+ }
+ })
+ }
+ function clear(){
+ setFieldsValue({
+ stage_type:"init",
+ template_name:undefined,
+ category:"Java",
+ })
+ setValue("");
+ setValueFlag(false);
+ }
+
+ function changeStage(e){
+ if(e === "build"){
+ setBuildFlag(true);
+ setFieldsValue({
+ category:TYPE[0]
+ })
+ }else{
+ removeCate();
+ }
+ }
+
+ function removeCate(){
+ setBuildFlag(false);
+ setFieldsValue({
+ category:""
+ })
+ }
+ return(
+
+
+
+
+
+ )
+}
+export default Form.create()(forwardRef(MouldNew));
+
diff --git a/src/forge/DevOps/OpsDetailRightpanel.jsx b/src/forge/DevOps/OpsDetailRightpanel.jsx
index 1e0ed86a..93bf370c 100644
--- a/src/forge/DevOps/OpsDetailRightpanel.jsx
+++ b/src/forge/DevOps/OpsDetailRightpanel.jsx
@@ -1,7 +1,8 @@
import React, { useState, useEffect } from "react";
-import { Spin } from "antd";
+import { Spin , Menu } from "antd";
import { FlexAJ, AlignCenter } from "../Component/layout";
import axios from "axios";
+import CodeSSH from './ssh/Index';
export default ({
data,
@@ -17,6 +18,8 @@ export default ({
const [spining, setSpining] = useState(true);
const [stage, setStage] = useState(undefined);
const [step, setStep] = useState(undefined);
+ const [nav, setNav] = useState("0");
+
useEffect(() => {
setSpining(rightSpin);
}, [rightSpin]);
@@ -35,6 +38,7 @@ export default ({
: p[0];
setStep(sub);
+ setNav("0");
if (sub && sub.status !== "skipped") {
getStep(pre.number, sub.number);
}
@@ -65,43 +69,55 @@ export default ({
}
}
return (
-
-
- {data && data.status !== "error" ? (
-
-
- {step && step.name}
-
- {step && step.duration_time}
-
-
-
-
- {coders && coders.length > 0 ? (
- coders.map((item, key) => {
- return (
+
+ {/* */}
+ {
+ nav === "0" &&
+
+
+ {data && data.status !== "error" ? (
+
+
+ {step && step.name}
+
+ {step && step.duration_time}
+
+
+
+
+ {coders && coders.length > 0 ? (
+ coders.map((item, key) => {
+ return (
+
+ {key + 1}
+ {item.out}
+
+ );
+ })
+ ) : empty ? (
- {key + 1}
- {item.out}
+ 1
+
+ {stage && stage.name} – {step && step.name}: Skipped
+
- );
- })
- ) : empty ? (
-
- 1
-
- {stage && stage.name} – {step && step.name}: Skipped
-
+ ) : (
+ ""
+ )}
- ) : (
- ""
- )}
-
+
+ ) : (
+ error:{data && data.error}
+ )}
- ) : (
- error:{data && data.error}
- )}
-
-
+
+ }
+ {
+ nav === "1" &&
+ }
+
);
};
diff --git a/src/forge/DevOps/ServiceModal.jsx b/src/forge/DevOps/ServiceModal.jsx
new file mode 100644
index 00000000..3fac8bc9
--- /dev/null
+++ b/src/forge/DevOps/ServiceModal.jsx
@@ -0,0 +1,21 @@
+import React, { useState } from 'react';
+import { Radio , Button } from 'antd';
+
+function ServiceModal({sureModal}){
+ const [ type , setType ] = useState(1);
+
+ function changeType(e){
+ setType(e.target.value);
+ }
+
+ return(
+
+
+ 自有服务器
+ Trustie服务器
+
+
+
+ )
+}
+export default ServiceModal;
\ No newline at end of file
diff --git a/src/forge/DevOps/Structure.jsx b/src/forge/DevOps/Structure.jsx
index 87a2b6cc..52ac1682 100644
--- a/src/forge/DevOps/Structure.jsx
+++ b/src/forge/DevOps/Structure.jsx
@@ -1,10 +1,16 @@
import React, { useState, useEffect , useImperativeHandle ,forwardRef } from "react";
-import { FlexAJ, AlignCenter } from "../Component/layout";
+import { FlexAJ, AlignCenter , Banner } from "../Component/layout";
import { Table, Pagination, Popconfirm } from "antd";
import { truncateCommitId } from "../common/util";
-import {getUrl} from 'educoder';
+import { getImageUrl } from 'educoder';
import axios from "axios";
+import { Link } from 'react-router-dom';
+import styled from 'styled-components';
+
+const Div = styled.div`{
+ padding:24px 30px;
+}`;
const STATUS = [
{ name: "所有"},
{ name: "运行中", value: "running" },
@@ -22,6 +28,7 @@ function Structure(props,ref){
let projectsId = props.match.params.projectsId;
let owner = props.match.params.owner;
+ let branch = props.match.params.branch;
const permission = props.projectDetail && props.projectDetail.permission;
useImperativeHandle(ref, () => ({
@@ -43,7 +50,7 @@ function Structure(props,ref){
axios.get(url,{
params:{
search:status,
- page,limit:LIMIT
+ page,limit:LIMIT,branch
}
}).then((result) => {
if (result && result.data) {
@@ -51,6 +58,7 @@ function Structure(props,ref){
return {
...item,
author:item.author && item.author.name,
+ image_url:item.author && item.author.image_url,
message: {
branch: item.branch_target,
message: item.message,
@@ -180,7 +188,7 @@ function Structure(props,ref){
已撤销
);
- case 'pending':
+ default:
return (
准备中
@@ -237,7 +245,7 @@ function Structure(props,ref){
{meg.sha && {meg.sha}}
-
+
{meg.message}
@@ -278,42 +286,45 @@ function Structure(props,ref){
},
];
return (
-
-
- {renderStatus()}
- {/* 手动创建 */}
- {/*
- 分支
-
-
-
- 标签
- */}
-
- {
- return{
- onClick:(event)=>clickRows(event,record)
- }
- }}
- columns={column}
- className="normalTable"
- dataSource={data}
- pagination={false}
- loading={tableLoading}
- >
- {total > LIMIT ?
-
-
-
- :
- "" }
+
+
+
+ 构建列表
+ 返回
+
+
+
+
+
+ {renderStatus()}
+ Init(status)} className="color-red font-16">刷新
+
+ {
+ return{
+ onClick:(event)=>clickRows(event,record)
+ }
+ }}
+ columns={column}
+ className="normalTable"
+ dataSource={data}
+ pagination={false}
+ loading={tableLoading}
+ >
+ {total > LIMIT ?
+
+
+
+ :
+ "" }
+
+
);
};
diff --git a/src/forge/DevOps/disposePipeline.jsx b/src/forge/DevOps/disposePipeline.jsx
new file mode 100644
index 00000000..1da142f6
--- /dev/null
+++ b/src/forge/DevOps/disposePipeline.jsx
@@ -0,0 +1,317 @@
+import React , { useEffect , useState } from 'react';
+import { WhiteBack } from '../Component/layout';
+import { Spin } from 'antd';
+import Head from './Dispose/head';
+import Menus from './Dispose/menus';
+import Init from './Dispose/Init';
+import Sure from './Dispose/Sure';
+import Stage from './Dispose/Stage';
+import axios from 'axios';
+
+function disposePipeline(props){
+ const [ spining , setSpining ] = useState(true);
+ const [ stage , setStage ] = useState(1);
+ const [ pipeLineName , setPipeLineName ] = useState(undefined);
+ const [ stepName , setStepName ] = useState(undefined);
+ const [ stageId , setStageId ] =useState(undefined);
+ const [ menuList , setMenuList ] = useState(undefined);
+ const [ stageType , setStageType ] = useState("init");
+ const [ datas , setDatas ] = useState(undefined);
+ const [ templates , setTemplates] = useState(undefined);
+ const [ datasUpdataFlag , setDatasUpdataFlag ] = useState(false);
+ const [ loading ,setLoading ] = useState(false);
+
+ const { disposeId } = props.match.params;
+ let projectsId = props.match.params.projectsId;
+ let owner = props.match.params.owner;
+ useEffect(()=>{
+ if(stageType && stageType !=="confirm"){
+ InitTemplates();
+ }
+ },[stageType])
+
+ // 获取模板
+ function InitTemplates(){
+ const url = `/ci/templates/templates_by_stage.json`;
+ axios.get(url,{
+ params:{ stage_type:stageType, id:disposeId }
+ }).then(result=>{
+ if(result && result.data){
+ setTemplates(result.data);
+ }
+ }).catch(error=>{})
+ }
+
+ useEffect(()=>{
+ if(disposeId && (stageType && stageType !=="confirm")){
+ getData(0);
+ }
+ },[disposeId])
+ // 获取所有阶段默认第一个阶段的数据
+ function getData(index){
+ const url = `/ci/pipelines/${disposeId}/stages.json`;
+ axios.get(url).then(result=>{
+ if(result && result.data){
+ setMenuList(result.data.stages);
+ if(index || index === 0){
+ let first = result.data.stages[index];
+ setStage(first.show_index);
+ setStageId(first.id);
+ setPipeLineName(`${first.pipeline_name}`);
+ }
+ }
+ })
+ }
+
+ useEffect(()=>{
+ if(stageId){
+ getStageStep(stageId);
+ }
+ },[stageId])
+ // 切换阶段时获取阶段步骤数据(第一次默认查询”初始化“阶段的数据)
+ function getStageStep(stageId){
+ let url = "";
+ if(stageType && stageType === "confirm"){
+ url = `/ci/pipelines/${disposeId}/content.json`;
+ axios.get(url,{
+ params:{
+ owner,repo:projectsId
+ }
+ }).then(result=>{
+ if(result && result.data){
+ setDatas(result.data);
+ }
+ }).catch(error=>{})
+ }else{
+ url = `/ci/pipelines/${disposeId}/${stageId}/steps.json`;
+ axios.get(url).then(result=>{
+ if(result && result.data){
+ let step = result.data.steps;
+ setDatas(step);
+ let flag = !step || (step && step.length === 0);
+ setDatasUpdataFlag(flag);
+ }
+ }).catch(error=>{})
+ }
+ setSpining(false);
+ }
+
+ // 切换阶段:s:show_index,stage_type:stage_type
+ function changestage(show_index,stage_type,stage_id,stage_name){
+ if(show_index !== stage){
+ saveFunc(show_index,stage_type,stage_id,stage_name);
+ }
+ }
+
+ // 获取子组件传过来的数据
+ function saveDatas(steps){
+ setDatas([...steps]);
+ setDatasUpdataFlag(true);
+ }
+
+ // 检查数组里面是否有空数据
+ function checkDatas(){
+ if(datas && datas.length > 0){
+ for(let i= 0;i< datas.length;i++){
+ if(datas[i] && (!datas[i].content || !datas[i].template_id)){
+ props.showNotification("请先选择模板!");
+ return false;
+ }
+ }
+ }else{
+ if(stageType === "init" ){
+ props.showNotification("请先选择模板!");
+ return false;
+ }else if(stageType === "confirm" ){
+ return true;
+ }else{
+ return "";
+ }
+ }
+ return true;
+ }
+
+ // 保存步骤
+ function saveFunc(show_index,stage_type,stage_id,stageName,btn){
+ setSpining(true);
+ // 判断数据是否有过更新
+ if(datasUpdataFlag && stageType !== "confirm"){
+ // 先判断子组件传过来的数据是否有undefined --datas
+ let f = checkDatas();
+ if(f && (datas && datas.length !== 0)){
+ // 数据没问题后先保存数据再切换阶段
+ saveDataFunc(btn,show_index,stage_type,stage_id,stageName);
+ }
+ else{
+ setSpining(false);
+ f === "" && elseFunc(btn,show_index,stage_type,stage_id,stageName);
+ }
+ }else{
+ elseFunc(btn,show_index,stage_type,stage_id,stageName);
+ }
+ }
+
+ function saveDataFunc(btn,show_index,stage_type,stage_id,stageName){
+ const url = `/ci/pipelines/${disposeId}/${stageId}/stage_step.json`;
+ axios.post(url,{
+ steps:datas
+ }).then(result=>{
+ if(result && result.data){
+ setDatasUpdataFlag(false);
+ if(!btn){
+ setStage(show_index);
+ setStageType(stage_type);
+ setStageId(stage_id);
+ setStepName(pipeLineName+`-`+stageName);
+ }else{
+ enters(btn);
+ }
+ }else{
+ props.showNotification("阶段更新失败,请稍微重试!");
+ }
+ }).catch(error=>{})
+ }
+
+ function elseFunc(btn,show_index,stage_type,stage_id,stageName){
+ if(btn){
+ enters(btn);
+ }else{
+ setStage(show_index);
+ setStageType(stage_type);
+ setStageId(stage_id);
+ setStepName(pipeLineName+`-`+stageName);
+ }
+ }
+
+ // 上一步、下一步
+ function enters(btn){
+ let s = stage;
+ if(btn === "next"){
+ // 点击阶段里面的下一步
+ s = s+1;
+ }else{
+ // 上一步
+ s = s-1;
+ }
+ let item = menuList && menuList.filter(i=>i.show_index === (s));
+ setStage(s);
+ setStageType(item[0].stage_type);
+ setStageId(item[0].id);
+ setStepName(pipeLineName+`-`+item[0].stage_name);
+ }
+ // 删除步骤
+ function deleteStep(id,index){
+ if(id){
+ const url = `/ci/pipelines/${disposeId}/${stageId}/${id}/delete_step.json`;
+ axios.delete(url).then(result=>{
+ if(result && result.data){
+ getStageStep(stageId);
+ props.showNotification("阶段步骤删除成功!");
+ }
+ }).catch(error=>{})
+ }else{
+ let d = datas.filter(s=>s.show_index !== (index+1));
+ setDatas(d);
+ }
+ }
+ function renameFunc(value,id){
+ const url = `/ci/pipelines/${disposeId}/${id}/update_stage.json`;
+ axios.put(url,{
+ stage_name:value
+ }).then(result=>{
+ if(result && result.data){
+ getData();
+ }
+ }).catch(error=>{})
+ }
+
+ // 新增阶段
+ function addMenuFunc(name,index){
+ const url = `/ci/pipelines/${disposeId}/create_stage.json`;
+ axios.post(url,{
+ show_index:index,
+ stage_name:name
+ }).then(result=>{
+ if(result && result.data){
+ getData(index-1);
+ setStageType("customize");
+ }else{
+ props.showNotification("阶段新增失败!");
+ }
+ })
+ }
+
+ // 删除阶段
+ function deleteStageFunc(){
+ let next = menuList && menuList.filter(item=>item.show_index === (stage+1));
+ let nextStageType = next && next.length>0 && next[0].stage_type;
+ const url = `/ci/pipelines/${disposeId}/${stageId}/delete_stage.json`;
+ axios.delete(url,{
+ params:{show_index:stage}
+ }).then(result=>{
+ if(result && result.data){
+ getData(stage-1);
+ setStageType(nextStageType);
+ }else{
+ props.showNotification("阶段删除失败!");
+ }
+ }).catch(error=>{})
+ }
+
+ // 确认提交
+ function sureSubmit(){
+ setLoading(true);
+ let params = {
+ branch: datas.branch,
+ content:datas.content,
+ filepath:'.trustie-pipeline.yml',
+ message:'',
+ sha:datas.sha || undefined,
+ owner:owner,
+ repo:projectsId
+ }
+ let url = `/${owner}/${projectsId}/update_trustie_pipeline.json`;
+ axios.put(url,{
+ ...params
+ }).then(result=>{
+ if(result){
+ props.history.push(`/projects/${owner}/${projectsId}/devops/dispose`);
+ }
+ setLoading(false);
+ }).catch(error=>{
+ console.log(error);
+ setLoading(false);
+ })
+ }
+
+ return(
+
+
+
+
+
+
+ {
+ stageType === "init" ?
+ :
+ stageType === "confirm" ?
+ :
+
+ }
+
+
+
+
+ )
+}
+export default disposePipeline;
\ No newline at end of file
diff --git a/src/forge/DevOps/ops.scss b/src/forge/DevOps/ops.scss
index 7a98d240..94838095 100644
--- a/src/forge/DevOps/ops.scss
+++ b/src/forge/DevOps/ops.scss
@@ -10,6 +10,7 @@
padding:60px 0px;
}
.disposePanel{
+ border:1px solid #eee;
.language{
display: flex;
margin-bottom: 20px;
@@ -81,48 +82,7 @@
.ant-modal-close{
top:7px;
}
- // 列表
- .listPart{
- .statusTag{
- display: flex;
- padding:0px 16px;
- height: 32px;
- line-height: 32px;
- border-radius:20px;
- float: left;
- i{
- font-size: 20px!important;
- margin-right: 7px;
- }
- &.running{
- background:#F1F8FF;
- border:1px solid #5091FF;
- color: #5091FF;
- }
- &.Preparing{
- background:rgba(255,248,244,1);
- border:1px solid rgba(255,110,33,1);
- color:rgba(255,110,33,1) ;
- }
- &.pass{
- background:#EEFDF5;
- border:1px solid #28BD6C;
- color:#28BD6C ;
- }
- &.failed{
- background:#FCEEEE;
- border:1px solid #F73030;
- color:#F73030 ;
- }
- &.killed{
- background:#eee;
- border:1px solid #999;
- color:#999 ;
- }
- }
-
- }
-
+
}
// ops详情
.opsDetailPanel{
@@ -234,6 +194,18 @@
&.rightSection{
width:100%;
background-color: #081930;
+ .devopsNav{
+ background-color: #111c24;
+ border-bottom: none;
+ .ant-menu-item{
+ color: #ccc;
+ padding:0px;
+ margin:0px 20px!important;
+ }
+ .ant-menu-item.ant-menu-item-selected{
+ color: #1890ff;
+ }
+ }
.rightMainContent{
padding:24px 30px;
height:100vh;
@@ -313,4 +285,240 @@
text-align:center;
line-height:22px;
color:#666;
+}
+
+.disposeList{
+ min-height: 450px;
+ .ant-table-body{
+ margin:0px!important;
+ .ant-table-thead{
+ background-color: #fafafa;
+ }
+ }
+}
+.txtright{
+ text-align: right;
+}
+.menus{
+ display: flex;
+ box-shadow: 0px 0px 6px rgba(0,3,8,0.1);
+ padding:20px 0px 10px 0px;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ & > li{
+ display: flex;
+ flex-flow: column;
+ align-items:center;
+ justify-content: flex-start;
+ text-align: center;
+ color: #787878;
+ font-size: 16px;
+ position: relative;
+ cursor: pointer;
+ max-width: 122px;
+ flex:2;
+ &>i{
+ font-size: 30px!important;
+ height: 30px;
+ width: 30px;
+ line-height: 30px;
+ }
+ &:hover,&.active{
+ & > i{
+ color: #1890FF;
+ }
+ }
+ &.active::after{
+ position: absolute;
+ left: 50%;
+ margin-left: -25px;
+ bottom:-10px;
+ width: 50px;
+ height: 2px;
+ background-color: #1890FF;
+ content: "";
+ }
+ .aboutEdit{
+ width: 100%;
+ .operateName{
+ position: relative;
+ line-height: 22px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0px 15px;
+ min-height: 40px;
+ & > i{
+ position: absolute;
+ right:0px;
+ top:10px;
+ display: none;
+ }
+ }
+ &:hover i{
+ display: block;
+ }
+ }
+ }
+ & > li.menuAdd{
+ position: relative;
+ flex: 1;
+ &:hover{
+ & > i{
+ color: #787878;
+ }
+ }
+ & > i{
+ font-size: 18px!important;
+ position: absolute;
+ z-index: 1;
+ top:0px;
+ }
+ & > input{
+ position: absolute;
+ z-index: 1;
+ top:3px;
+ }
+ &::before{
+ position: absolute;
+ left: 0;
+ width: 100%;
+ border-bottom: 1px dashed #eee;
+ content: "";
+ top:15px;
+ margin-top: -1px;
+ z-index: 0;
+ }
+ }
+}
+.chooseCon.ant-select-dropdown{
+ z-index: 100001;
+}
+
+.choosenList{
+ display: flex;
+ flex-wrap: wrap;
+ line-height: 35px;
+ align-items: center;
+ & > span{
+ display: block;
+ min-width: 75px;
+ text-align: right;
+ font-size: 14px;
+ color: #333;
+ height: 35px;
+ margin-right: 12px;
+ }
+ & > ul{
+ display: flex;
+ flex-wrap: wrap;
+ li{
+ padding:0px 12px;
+ height: 35px;
+ line-height: 35px;
+ border:1px solid #e1e4e8;
+ background-color: #fff;
+ margin:6px 0px;
+ margin-right: 12px;
+ border-radius: 5px;
+ cursor: pointer;
+ color: #333;
+ }
+ li.active{
+ color: #fff;
+ background-color: #1890FF;
+ }
+ }
+ .ant-select-selection.ant-select-selection--multiple{
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ height: 35px;
+ }
+}
+.addStageBtn{
+ display: block;
+ width: 100%;
+ border:1px solid #e1e4e8;
+ height: 48px;
+ line-height: 48px;
+ color: #1890FF;
+ font-size: 16px;
+ border-radius: 3px;
+ padding: 0px 20px;
+}
+.stepsItem{
+ border:1px solid #e1e4e8;
+ border-radius: 4px;
+ margin-bottom: 15px;
+ .stepsHead{
+ padding:8px 15px;
+ span > a > i{
+ margin-left: 8px;
+ color: #666!important;
+ }
+ }
+ .stepsBody{
+ padding:10px 15px;
+ border-top: 1px solid #e1e4e8;
+ background-color: rgb(251, 251, 251);
+ display: none;
+ transition: 0.3s;
+ }
+ .stepsBody.active{
+ display: block;
+ }
+}
+.editorPanel{
+ border:1px solid #eee;
+ .margin{
+ width: 0px;
+ }
+ .monaco-scrollable-element.editor-scrollable{
+ left: 0px!important;
+ width: 100%!important;
+ .view-lines{
+ width: 336px!important;
+ }
+ }
+}
+.hide{
+ display: none!important;
+}
+.statusTag{
+ display: flex;
+ padding:0px 16px;
+ height: 32px;
+ line-height: 32px;
+ border-radius:20px;
+ float: left;
+ i{
+ font-size: 20px!important;
+ margin-right: 7px;
+ }
+ &.running{
+ background:#F1F8FF;
+ border:1px solid #5091FF;
+ color: #5091FF;
+ }
+ &.Preparing{
+ background:rgba(255,248,244,1);
+ border:1px solid rgba(255,110,33,1);
+ color:rgba(255,110,33,1) ;
+ }
+ &.pass{
+ background:#EEFDF5;
+ border:1px solid #28BD6C;
+ color:#28BD6C ;
+ }
+ &.failed{
+ background:#FCEEEE;
+ border:1px solid #F73030;
+ color:#F73030 ;
+ }
+ &.killed{
+ background:#eee;
+ border:1px solid #999;
+ color:#999 ;
+ }
}
\ No newline at end of file
diff --git a/src/forge/DevOps/opsDetail.jsx b/src/forge/DevOps/opsDetail.jsx
index 92f620a7..6ac3dc44 100644
--- a/src/forge/DevOps/opsDetail.jsx
+++ b/src/forge/DevOps/opsDetail.jsx
@@ -87,7 +87,7 @@ export default (props) => {
退出
diff --git a/src/forge/DevOps/ssh/Index.jsx b/src/forge/DevOps/ssh/Index.jsx
new file mode 100644
index 00000000..9a896a83
--- /dev/null
+++ b/src/forge/DevOps/ssh/Index.jsx
@@ -0,0 +1,42 @@
+import React, { useState, useEffect } from "react";
+import XmlPanel from "./XmlPanel";
+import mediator from "./mediator";
+import axios from "axios";
+
+// const defaulturl = `http://47.111.130.18:48088`;
+const defaultValue = {
+ host: "106.75.231.63",
+ port: "2021",
+ ws_url: "wss://pre-webssh.educoder.net/ws",
+ username: "root",
+ secret: "Dron_123123",
+};
+function Index() {
+ const [sshConfigData, setSshConfigData] = useState(undefined);
+
+ useEffect(() => {
+ if (!sshConfigData) {
+ init();
+ }
+ setTimeout(() => {
+ mediator.publish("create-socket", 1);
+ }, 300);
+ }, [sshConfigData]);
+
+ // 获取服务器连接信息
+ function init() {
+ const url = `/api/ci/pipelines/ssh_server.json`;
+ axios.get(url).then(result=>{
+ if(result && result.data){
+ setSshConfigData({...result.data})
+ }
+ }).catch(error=>{})
+ }
+ return (
+
+ );
+}
+export default Index;
diff --git a/src/forge/DevOps/ssh/XmlPanel.jsx b/src/forge/DevOps/ssh/XmlPanel.jsx
new file mode 100644
index 00000000..ae642caa
--- /dev/null
+++ b/src/forge/DevOps/ssh/XmlPanel.jsx
@@ -0,0 +1,219 @@
+import React, { useRef, useEffect, useState } from 'react';
+import { Base64 } from 'js-base64';
+
+import { Terminal } from 'xterm';
+import 'xterm/css/xterm.css';
+import mediator from './mediator';
+import ResizeObserver from 'resize-observer-polyfill';
+
+function getColsAndRows(width, height, term) {
+ let w = term._core._renderService.dimensions.actualCellWidth || 9.5;
+ let h = term._core._renderService.dimensions.actualCellHeight || 18;
+ const rows = Math.floor(height / h);
+ const cols = Math.floor(width / w);
+ return [cols, rows];
+}
+
+function onLayout(term, el) {
+ const ro = new ResizeObserver(entries => {
+ console.log(entries);
+ for (let entry of entries) {
+ if (entry.target.offsetHeight > 0 || entry.target.offsetWidth > 0) {
+ const [cols, rows] = getColsAndRows(
+ entry.target.offsetWidth,
+ entry.target.offsetHeight,
+ term,
+ );
+ console.log('cols, rows', cols, rows);
+ term.resize(cols, rows);
+ mediator.publish('ssh-xterm-resize', {
+ columns: cols,
+ rows: rows,
+ width: entry.target.offsetWidth,
+ height: entry.target.offsetHeight,
+ });
+ }
+ }
+ });
+ ro.observe(el);
+ return ro;
+}
+
+const TimeTicket = 30000;
+
+//建立 websockt 来交互
+//根据容器大小计算行数和列数并做到自适应
+//socket 与 term 需要分开初始化 因为socket 可能重置连接
+//mediator 监听消息,如果和id匹配,则建立连接,重置,或关闭连接
+
+export default ({ sshConfigData, sid }) => {
+ const [term, setTerm] = useState(null);
+
+ const { ws_url, password, port, secret } = sshConfigData;
+ const el = useRef();
+ const socket = useRef();
+ const isFirstConnected = useRef(false);
+
+ //term init
+ useEffect(() => {
+ if (el.current && ws_url) {
+ const term = new Terminal({ fontSize: 16, rendererType: 'dom' });
+ term.open(el.current);
+
+ term.onData(data => {
+ if (socket.current) {
+ if (socket.current.readyState === 1) {
+ socket.current.send(JSON.stringify({ tp: 'client', data: data }));
+ mediator.publish('on-operating-ssh'); //有操作则自动延时
+ } else {
+ //断开连接后重连
+ // socket.current = null
+ // mediator.publish('create-socket', sid)
+ }
+ }
+ });
+ term.write('Connecting...');
+ setTerm(term);
+ const ro = onLayout(term, el.current);
+ return () => {
+ term.dispose();
+ ro.unobserve(el.current);
+ };
+ }
+ }, [ws_url, el.current]);
+
+ useEffect(() => {
+ if (term && ws_url) {
+ function createSocket() {
+ const socketInstance = new WebSocket(ws_url);
+ socket.current = socketInstance;
+
+ socketInstance.onopen = () => {
+ let container = term.element.parentElement;
+ if (container) {
+ let width = container.offsetWidth;
+ let height = container.offsetHeight;
+ console.log('init', {
+ tp: 'init',
+ data: {
+ ...sshConfigData,
+ secret: secret,
+ width,
+ height,
+ rows: term.rows,
+ columns: term.cols,
+ },
+ });
+ socketInstance.send(
+ JSON.stringify({
+ tp: 'init',
+ data: {
+ ...sshConfigData,
+ secret: secret,
+ width,
+ height,
+ rows: term.rows,
+ columns: term.cols,
+ },
+ }),
+ );
+ }
+ term.focus();
+ };
+ socketInstance.onerror = error => {
+ console.log(
+ '------in socket error----',
+ error,
+ socketInstance,
+ ws_url,
+ );
+ //连接报错后,重新请求资源
+ // mediator.publish('on-recreate-socket')
+ };
+ socketInstance.onmessage = event => {
+ if (!isFirstConnected.current) {
+ term.write('\r');
+ // term.focus()
+ setTimeout(() => {
+ // term.clear();
+ }, 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);
+ };
+
+ socketInstance.onclose = evt => {
+ if (tid) {
+ clearInterval(tid);
+ }
+ term.write('\r\nconnection closed');
+ };
+ }
+
+ const tid = setInterval(() => {
+ if (socket.current) {
+ socket.current.send(JSON.stringify({ tp: 'h' }));
+ }
+ }, TimeTicket);
+
+ const unSubCreate = mediator.subscribe('create-socket', id => {
+ if (sid === id) {
+ if (socket.current && socket.current.readyState === 1) {
+ term.focus();
+ } else {
+ createSocket();
+ }
+ term.focus();
+ }
+ });
+
+ const unSubClose = mediator.subscribe('close-socket', id => {
+ if (sid === id) {
+ if (socket.current) {
+ socket.current.close();
+ isFirstConnected.current = false;
+ term.clear();
+ }
+ socket.current = null;
+ }
+ });
+
+ const unSubResize = mediator.subscribe('ssh-xterm-resize', option => {
+ if (socket.current && socket.current.readyState === 1) {
+ socket.current.send(
+ JSON.stringify({ tp: 'resize', data: { ...option } }),
+ );
+ }
+ });
+
+ const unSubAddTime = mediator.subscribe('ssh-add-connect-time', () => {
+ if (socket.current && socket.current.readyState === 1) {
+ socket.current.send(JSON.stringify({ tp: 'overtime' }));
+ }
+ });
+
+ return () => {
+ unSubClose();
+ unSubCreate();
+ unSubResize();
+ unSubAddTime();
+ if (socket.current) {
+ socket.current.close();
+ isFirstConnected.current = false;
+ }
+ };
+ }
+ }, [term, ws_url, port]);
+
+ return (
+
+ {!ws_url ? 正在连接命令行服务...
: null}
+
+ );
+};
\ No newline at end of file
diff --git a/src/forge/DevOps/ssh/mediator.jsx b/src/forge/DevOps/ssh/mediator.jsx
new file mode 100644
index 00000000..70a4e30f
--- /dev/null
+++ b/src/forge/DevOps/ssh/mediator.jsx
@@ -0,0 +1,46 @@
+function Mediator(obj) {
+ const channels = {};
+
+ const mediator = {
+ subscribe: function(channel, cb) {
+ if (!channels[channel]) {
+ channels[channel] = [];
+ }
+ channels[channel].push(cb);
+ return this.unsubscribe.bind(null, channel, cb);
+ },
+
+ unsubscribe: function(channel, cb) {
+ let rs = channels[channel];
+ let index = -1;
+ if (rs) {
+ for (let i = 0; i < rs.length; i++) {
+ if (rs[i].name === cb.name) {
+ index = i;
+ break;
+ }
+ }
+ if (index >= 0) {
+ channels[channel].splice(index, 1);
+ return true;
+ }
+ }
+ return false;
+ },
+
+ publish: function(channel) {
+ if (!channels[channel]) {
+ return false;
+ }
+ const args = Array.prototype.slice.call(arguments, 1);
+ channels[channel].forEach(subscription => {
+ subscription.apply(null, args);
+ });
+ return this;
+ },
+ };
+
+ return obj ? Object.assign(obj, mediator) : mediator;
+}
+const mediator = new Mediator();
+export default mediator;
\ No newline at end of file
diff --git a/src/forge/Divert/DivertModal.jsx b/src/forge/Divert/DivertModal.jsx
new file mode 100644
index 00000000..a6ecdc05
--- /dev/null
+++ b/src/forge/Divert/DivertModal.jsx
@@ -0,0 +1,175 @@
+import React ,{ forwardRef, useEffect, useState } from 'react';
+import { Modal , Form , Input , Radio , Select } from 'antd';
+import SearchUser from '../Component/SearchUser';
+import './Index.scss';
+import Axios from 'axios';
+
+const { Option } = Select;
+function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
+ const { getFieldDecorator, validateFields , setFieldsValue } = form;
+ const [ cate , setCate ] = useState(0);
+ const [ value , setValue ] = useState(undefined);
+
+ const [ organizations , setOrganizations ] = useState(undefined);
+
+ useEffect(()=>{
+ setFieldsValue({goal:cate})
+ },[])
+
+ useEffect(()=>{
+ if(owner && repo && visible===true){
+ getTeam();
+ }
+ if(!visible){
+ setFieldsValue({
+ owner_name:undefined,
+ identifier:undefined
+ })
+ setValue(undefined)
+ }
+ },[repo,owner,visible])
+
+ function getTeam(){
+ const url = `/${owner}/${repo}/applied_transfer_projects/organizations.json`;
+ Axios.get(url).then(result=>{
+ if(result){
+ setOrganizations(result.data.organizations);
+ }
+ }).catch(error=>{})
+ }
+
+ // 确认转移
+ 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){
+ onSuccess(result.data && result.data.owner);
+ }
+ }).catch(error=>{})
+ }
+ })
+
+ }
+ function changeType(e){
+ setCate(e.target.value);
+ setFieldsValue({
+ owner_name:undefined
+ })
+ }
+
+ function checkIdentifier(rule, value, callback){
+ if(!value){
+ callback();
+ }
+ if (repo && value !== repo) {
+ callback("请输入当前项目的标识!");
+ }
+ callback();
+ }
+
+ const layout = {
+ labelCol: { span: 5 },
+ wrapperCol: { span: 18 },
+ };
+
+ function getUser(id){
+ setValue(id);
+ setFieldsValue({
+ owner_name:id
+ })
+ }
+ return(
+
+
+ {
+ cate === 0 ?
+
+ - 转移需对方确认接受,转移成功后你将被移出仓库,其他已有成员权限不变
+ - 转移成功后,仓库的地址将变更至目标用户的命名空间下
+ - 已有成员如需继续操作仓库,需更新本地仓库的remote,使之指向新的地址
+
+ :
+
+ - 仓库仅可以转移到您已经加入的组织中,不可以转移到未加入的组织中
+ - 涉及到仓库改名操作,请提前做好仓库备份并且在转移后对本地仓库的remote进行修改
+ - 转移仓库到组织后,你和组织创建者/管理员同时拥有对该仓库的管理操作
+
+ }
+
+ {getFieldDecorator("goal",{
+ rules:[]
+ })(
+
+ 个人
+ 组织
+
+ )}
+
+ {
+ cate === 0 &&
+
+ {getFieldDecorator("owner_name",{
+ rules:[{required:true,message:"请输入目标用户名"}]
+ })(
+ //
+
+ )}
+
+ }
+ {
+ cate === 1 &&
+
+ {getFieldDecorator("owner_name",
+ {rules:[{required:true,message:"请选择目标组织"}]}
+ )(
+
+ )}
+
+ }
+
+
+ {getFieldDecorator("identifier",
+ {
+ rules:[
+ {required:true,message:"请输入仓库标识!"},
+ {
+ validator:checkIdentifier
+ }
+ ]
+ }
+ )(
+
+ )}
+
+ 请输入当前项目的标识:{repo}进行确认!
+
+
+
+ )
+}
+export default Form.create()(forwardRef(DivertModal));
\ No newline at end of file
diff --git a/src/forge/Divert/Index.scss b/src/forge/Divert/Index.scss
new file mode 100644
index 00000000..0a39e4e2
--- /dev/null
+++ b/src/forge/Divert/Index.scss
@@ -0,0 +1,12 @@
+.diverModal{
+ .descUl{
+ background-color: #fffae6;
+ border-radius: 4px;
+ padding:10px 15px;
+ color: #efc16b;
+ border:1px solid #efc16b;
+ }
+ .ant-form-item-required::before{
+ content: "";
+ }
+}
\ No newline at end of file
diff --git a/src/forge/GetData/getData.jsx b/src/forge/GetData/getData.jsx
index 3e2f2224..2ecc3111 100644
--- a/src/forge/GetData/getData.jsx
+++ b/src/forge/GetData/getData.jsx
@@ -10,4 +10,12 @@ export const getTag = async (id,owner)=>{
// 获取hooks(仓库设置-管理web钩子)列表
export const getHooks = async (id,params)=>{
return (await axios.get(`/projects/${id}/hooks.json`,{params})).data;
+}
+// 获取子目录列表
+export const getSubEntries = async (owner,projectsId,params)=>{
+ return (await axios.get(`/${owner}/${projectsId}/sub_entries.json`,{params})).data;
+}
+// 获取用户信息
+export const getUser = async (login)=>{
+ return (await axios.get(`/users/${login}/hovercard.json`)).data;
}
\ No newline at end of file
diff --git a/src/forge/Head/AddProjectModal.jsx b/src/forge/Head/AddProjectModal.jsx
new file mode 100644
index 00000000..8e3073e3
--- /dev/null
+++ b/src/forge/Head/AddProjectModal.jsx
@@ -0,0 +1,84 @@
+import React, { useState , forwardRef, useEffect } from 'react';
+import { Form , Modal , Input , Radio } from 'antd';
+import Axios from 'axios';
+
+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(
+
+ setVisible(false)}
+ >
+
+ {getFieldDecorator("code",{
+ rules:[
+ {required:true,message:"请输入6位项目邀请码"},
+ {validator:checkValue}
+ ]
+ })(
+
+ )}
+
+
+ {getFieldDecorator("role",{
+ rules:[{required:true,message:"请选择角色"}]
+ })(
+
+ 管理员
+ 开发者
+ 报告者
+
+ )}
+
+
+
+ setVisible(true)}>加入项目
+
+ )
+ })
+)
\ No newline at end of file
diff --git a/src/forge/Head/Footer.jsx b/src/forge/Head/Footer.jsx
new file mode 100644
index 00000000..568583ea
--- /dev/null
+++ b/src/forge/Head/Footer.jsx
@@ -0,0 +1,66 @@
+import React, { useEffect , useState } from 'react';
+import './header.scss';
+
+function Footer(){
+ const [ value , setValue ] = useState(undefined);
+
+ useEffect(()=>{
+ try {
+ var chromesettingArray = JSON.parse(localStorage.getItem('chromesetting'));
+ setValue(chromesettingArray.footer);
+ } catch (e) {
+ }
+ },[])
+
+ function showhtml(htmlString){
+ var html = {__html:htmlString};
+ return ;
+ }
+
+ return(
+
+
+
+ {value && showhtml(value)}
+ {/*
+
+
+ - 支持与服务
+ - API文档
+ - 帮助中心
+ - Git常用命令
+ - DevOps使用文档
+ - 日志更新
+
+
+
+ - 合作伙伴
+ - 热线:
+ - QQ群:1071514693
+
+
+ © Copyright 2007~2021 国防科技大学Trustie团队 & IntelliDE 湘ICP备 17009477号
*/}
+
+
+ )
+}
+export default Footer;
diff --git a/src/forge/Head/Header.js b/src/forge/Head/Header.js
new file mode 100644
index 00000000..7364ebd3
--- /dev/null
+++ b/src/forge/Head/Header.js
@@ -0,0 +1,456 @@
+import React, { Component } from 'react';
+import AccountProfile from "../../modules/user/AccountProfile";
+import { getImageUrl } from 'educoder'
+import axios from 'axios';
+import { Input , notification , Dropdown , Menu } from 'antd';
+import { Link } from 'react-router-dom';
+
+import LoginDialog from '../../modules/login/LoginDialog';
+import HeadSearch from '../Component/HeadSearch';
+
+import AddProjectModal from './AddProjectModal';
+import '../../modules/tpm/TPMIndex.css';
+
+import './header.scss';
+const $ = window.$
+// TODO 这部分脚本从公共脚本中直接调用
+const { Search } = Input;
+let old_url;
+
+window._header_componentHandler = null;
+// 非trustie链接则新开页跳转
+const str = ['www.trustie.net','forgeplus.trustie.net','forum.trustie.net','testforgeplus.trustie.net']
+class NewHeader extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ Addcoursestypes: false,
+ tojoinitemtype: false,
+ tojoinclasstitle: undefined,
+ rolearr: ["", ""],
+ Checkboxteacherchecked: false,
+ Checkboxstudentchecked: false,
+ Checkboxteachingchecked: false,
+ Checkboxteachertype: false,
+ Checkboxteachingtype: false,
+ code_notice: false,
+ RadioGroupvalue: undefined,
+ submitapplications: false,
+ isRender: false,
+ showTrial: false,
+ setevaluatinghides: false,
+ occupation: 0,
+ mydisplay: false,
+ headtypesonClickbool: false,
+ headtypess: "/",
+ settings: null,
+ visiblemyss: false,
+ openSearch:false,
+ }
+ }
+ componentDidMount() {
+ this.geturlsdata();
+ window._header_componentHandler = this;
+
+ //下拉框的显示隐藏
+ var hoverTimeout;
+ var hoveredPanel;
+ $(".edu-menu-panel").hover(function () {
+ if (hoverTimeout) { // 一次只显示一个panel
+ if (hoveredPanel && hoveredPanel !== this) {
+ $(hoveredPanel).find(".edu-menu-list").hide()
+ }
+ clearTimeout(hoverTimeout);
+ hoverTimeout = null;
+ }
+ hoveredPanel = this;
+ $(this).find(".edu-menu-list").show();
+ }, function () {
+ var that = this;
+ // 延迟hide
+ hoverTimeout = setTimeout(function () {
+ $(that).find(".edu-menu-list").hide();
+ }, 800)
+
+ });
+ //获取游览器地址
+ try {
+ window.sessionStorage.setItem("yslgeturls", JSON.stringify(window.location.href))
+ } catch (e) {}
+ }
+
+ openNotification = (messge) => {
+ notification.open({
+ message: "提示",
+ description:
+ messge,
+ });
+ };
+
+ componentWillReceiveProps(newProps, oldProps) {
+ this.setState({
+ user: newProps.user
+ })
+ if (newProps.Headertop !== undefined) {
+ old_url = newProps.Headertop.old_url
+ }
+ }
+
+ educoderlogin = () => {
+ //登录账号
+ this.setState({
+ isRender: true
+ })
+ }
+ educoderloginysl = () => {
+ //退出账号
+ var url = `/accounts/logout.json`;
+ axios.get((url)).then((result) => {
+ if (result !== undefined) {
+ window.location.href = "/";
+ }
+ }).catch((error) => {
+ console.log(error);
+ })
+ }
+
+ hideAddcoursestypes = () => {
+ this.setState({
+ Addcoursestypes: false
+ })
+ };
+ HideAddcoursestypess = (i) => {
+ console.log("调用了");
+ this.setState({
+ Addcoursestypes: false,
+ mydisplay: true,
+ occupation: i,
+ })
+ };
+ ModalCancelsy = () => {
+ this.setState({
+ mydisplay: false,
+ })
+ };
+
+ // 关闭
+ cancelModulationModels = () => {
+ this.setState({ isRenders: false })
+ }
+
+ setevaluatinghides = () => {
+ this.setState({
+ setevaluatinghides: true
+ })
+ }
+ //修改登录方法
+ Modifyloginvalue = () => {
+ this.setState({
+ isRender: false,
+ })
+ }
+
+ hideAccountProfile = () => {
+ this.setState({
+ AccountProfiletype: false
+ })
+ };
+ headtypesonClick = (url, bool) => {
+ this.setState({
+ headtypess: url,
+ headtypesonClickbool: bool,
+ })
+ }
+ //获取数据为空的时候
+ gettablogourlnull = () => {
+ this.setState({
+ settings: undefined
+ });
+ var link = document.createElement('link'),
+ oldLink = document.getElementById('dynamic-favicon');
+ link.id = 'dynamic-favicon';
+ link.rel = 'shortcut icon';
+ link.href = "/react/build/./favicon.ico";
+ if (oldLink) {
+ document.head.removeChild(oldLink);
+ }
+ document.head.appendChild(link);
+ };
+
+ //获取数据的时候
+ gettablogourldata = (response) => {
+ document.title = response.data.setting.name;
+ var link = document.createElement('link'),
+ oldLink = document.getElementById('dynamic-favicon');
+ link.id = 'dynamic-favicon';
+ link.rel = 'shortcut icon';
+ link.href = '/' + response.data.setting.tab_logo_url;
+ if (oldLink) {
+ document.head.removeChild(oldLink);
+ }
+ document.head.appendChild(link);
+ }
+
+ handleVisibleChanges = (boll) => {
+ this.setState({
+ visiblemyss: boll,
+ })
+ }
+
+ 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));
+ } else {
+ this.gettablogourlnull();
+ }
+ }).catch((error) => {
+ this.gettablogourlnull();
+ });
+ }
+
+ matchpaths = (url) => {
+ const { match } = this.props;
+ if(url){
+ if (match.path.indexOf(url) > -1) {
+ return true
+ }else {
+ return false
+ }
+ }
+ }
+
+ addMenu=(list)=>{
+ return(
+ list && list.length >0 &&
+
+
+
+ )
+ }
+ renderMenu=(personal)=>{
+ const { current_user } = this.props;
+ return(
+
+ )
+ }
+
+ render() {
+ const { match} = this.props;
+ let current_user = this.props.user;
+ let {
+ AccountProfiletype,
+ user,
+ isRender,
+ headtypesonClickbool,
+ headtypess,
+ settings,
+ } = this.state;
+ /*用户名称 用户头像url*/
+ let activeIndex = false;
+ let activeForums = false;
+ let activeShixuns = false;
+ let activePaths = false;
+ let coursestype = false;
+ let activePackages = false;
+ let activeMoopCases = false;
+ let activeCompetitions = false;
+
+ if (match.path === '/forums') {
+ activeForums = true;
+ } else if (match.path.startsWith('/shixuns')) {
+ activeShixuns = true;
+ } else if (match.path.startsWith('/paths')) {
+ activePaths = true;
+ } else if (match.path.startsWith('/courses')) {
+ coursestype = true;
+ } else if (match.path.startsWith('/crowdsourcing')) {
+ activePackages = true;
+ } else if (match.path.startsWith('/moop_cases')) {
+ activeMoopCases = true;
+ } else if (match.path.startsWith('/competitions')) {
+ activeCompetitions = true;
+ } else {
+ activeIndex = true;
+ }
+
+ let headtypes = '/';
+ if (settings) {
+ if (settings.navbar) {
+ if (settings.navbar.length > 0) {
+ if (match.path === '/') {
+ if (headtypesonClickbool === false) {
+ headtypes = undefined;
+ } else {
+ headtypes = headtypess;
+ }
+ } else {
+ for (var i = 0; i < settings.navbar.length; i++) {
+ if (match.path === settings.navbar[i].link) {
+ headtypes = settings.navbar[i].link;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ let shixuntype = false;
+ let pathstype = false;
+ let coursestypes = false;
+ if (this.props && this.props.mygetHelmetapi != null) {
+ let shixun = "/shixuns";
+ let paths = "/paths";
+ let courses = "/courses";
+ this.props.mygetHelmetapi && this.props.mygetHelmetapi.navbar && this.props.mygetHelmetapi.navbar.map((item, key) => {
+ var reg = RegExp(item.link);
+ if (shixun.match(reg)) {
+ if (item.hidden === true) {
+ shixuntype = true
+ }
+ }
+ if (paths.match(reg)) {
+ if (item.hidden === true) {
+ pathstype = true
+ }
+ }
+ if (courses.match(reg)) {
+ if (item.hidden === true) {
+ coursestypes = true
+ }
+ }
+ })
+ }
+
+ // let search_url = settings && settings.common && settings.common.search;
+ let notice_url = settings && settings.common && settings.common.notice;
+ return (
+
+
+ {isRender === true ?
+ this.Modifyloginvalue()}
+ /> : ""}
+
+ {AccountProfiletype === true ?
+ this.hideAccountProfile()}
+ {...this.props}
+ {...this.state}
+ /> : ""}
+ {
+ settings && settings.nav_logo_url ?
+
+
+
+ :
+ ""
+ }
+
+
+ {/* {search_url ? this.SearchInput(openSearch,search_url):""} */}
+
+ {
+ current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)?
+
+
+ :""
+ }
+
+ {this.props.user && this.props.user.login && notice_url ?
+
+ {user && user.login &&
+
+
+
+
+
+ }
+ :""
+ }
+
+ {!user || (user && !user.login) ?
+
+ this.educoderlogin()} className="mr5 color-grey-6">登录
+ {
+ settings && settings.common && settings.common.register &&
+ 注册
+ }
+
+ :
+
+
+
+
+
+ }
+
+
+ );
+ }
+}
+
+export default NewHeader;
diff --git a/src/forge/Head/header.scss b/src/forge/Head/header.scss
new file mode 100644
index 00000000..0246658a
--- /dev/null
+++ b/src/forge/Head/header.scss
@@ -0,0 +1,122 @@
+
+.dropdownFlex{
+ display:flex;
+ background:#fff;
+ border-radius: 3px;
+ .ant-menu-vertical > .ant-menu-item{
+ border:none;
+ 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: 30px;
+}
+.currentMenu{
+ width: 120px;
+ text-align: center;
+ padding:0px;
+ 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;
+ bottom: 0;
+ width: 100%;
+ background: #323232;
+ clear: both;
+ min-width: 1200px;
+ z-index: 8;
+ left: 0px;
+ p {
+ margin-top: 0;
+ margin-bottom:0px !important;
+ }
+ .footerInfos{
+ display: flex;
+ max-width: 1200px;
+ margin:0px auto;
+ justify-content: space-around;
+ padding:60px 0px;
+ & >ul{
+ padding:0px 40px;
+ box-sizing: border-box;
+ max-width: 25%;
+ text-align: left;
+ li{
+ color: #fff;
+ font-weight: 300;
+ &:first-child{
+ font-size: 17px;
+ }
+ &>a,&>span{
+ color: #bbb;
+ }
+ &>a:hover{
+ color: #4cacff;
+ }
+ }
+ }
+ }
+ .footerCopy{
+ color: #bbb;
+ border-top: 1px solid #4e4e4e;
+ padding:10px 0px;
+ a{
+ color: #bbb;
+ &:hover{
+ color: #4cacff;
+ }
+ }
+ }
+}
+.inviteForm{
+ .ant-form-item{
+ margin-right: 0px;
+ }
+ .ant-form-item-label{
+ width: 110px;
+ text-align: right;
+ }
+}
\ No newline at end of file
diff --git a/src/forge/Index.js b/src/forge/Index.js
index eca6d871..3870c088 100644
--- a/src/forge/Index.js
+++ b/src/forge/Index.js
@@ -6,7 +6,6 @@ import { withRouter } from "react-router";
import { SnackbarHOC } from "educoder";
import { CNotificationHOC } from "../modules/courses/common/CNotificationHOC";
import { TPMIndexHOC } from "../modules/tpm/TPMIndexHOC";
-import Handbook from './Component/Handbook';
import "./css/index.scss";
import Loadable from "react-loadable";
@@ -27,24 +26,37 @@ const ProjectDetail = Loadable({
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 (
-
+ (
+
+ )}
+ >
(
)}
>
+ (
+
+ )}
+ >
(
@@ -58,12 +70,8 @@ class Index extends Component {
)}
>
(
- this.props.current_user && this.props.current_user.login ?
-
- :
)}
>
diff --git a/src/forge/Main/CoderDepot.jsx b/src/forge/Main/CoderDepot.jsx
new file mode 100644
index 00000000..ee2bc092
--- /dev/null
+++ b/src/forge/Main/CoderDepot.jsx
@@ -0,0 +1,541 @@
+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 { getImageUrl } from "educoder";
+import { Link } from 'react-router-dom';
+import CloneAddress from '../Branch/CloneAddress';
+
+import SelectBranch from '../Branch/Select';
+import User from '../Component/User';
+import axios from 'axios';
+import Path from './CoderDepotPath';
+import Catalogue from './CoderDepotCatalogue';
+import ReadMe from './CoderDepotReadme';
+import CoderRootFileDetail from './CoderRootFileDetail';
+import './Index.scss';
+import Releases from '../Component/Releases';
+import Contributors from '../Component/Contributors';
+import LanguagePower from '../Component/LanguagePower';
+import DrawerPanel from '../Component/DrawerPanel';
+import UpdateDescModal from './sub/UpdateDescModal';
+import Nodata from '../Nodata';
+import Invite from './sub/Invite';
+/**
+ * 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);
+ const [ lastCommitAuthor,setLastCommitAuthor ] = useState(undefined);
+ const [ type ,setType ] = useState('dir');
+ const [ hide , setHide ] = useState(true);
+ const [ hideBtn , setHideBtn ] = useState(false);
+ const [ commitCount ,setCommitCount ] = useState(0);
+ const [ dirInfo ,setDirInfo ] = useState(undefined);//文件夹目录列表
+ const [ fileInfo ,setFileInfo ] = useState(undefined);//文件内容信息
+ const [ zip_url , setZip_url ] = useState(undefined);
+ const [ tar_url , setTar_url ] = useState(undefined);
+ const [ readOnly , setReadOnly] = useState(true);
+ const [ isSpin , setIsSpin] = useState(true);
+ const [ visible ,setVisible ] = useState(false);
+ const [ mainFlag ,setMainFlag ] = useState(false);
+ const [ openModal , setOpenModal ] = useState(false);
+ 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 owner = props.match.params.owner;
+ const projectsId = props.match.params.projectsId;
+ let branchName = props.match.params.branchName;
+ branchName = returnbar(branchName);
+ const details = props.projectDetail;
+ let pathname = props.history.location.pathname;
+
+ const { bannerList } = props;
+
+ 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(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])
+
+ useEffect(()=>{
+ if(treeValue){
+ setTreeValuePath(treeValue.split('/'));
+ }else{
+ setTreeValuePath(undefined);
+ }
+ },[treeValue])
+
+
+ useEffect(()=>{
+ if (projectsId && owner && defaultBranch){
+ let b = turnbar(branchName) ;
+ if(pathname.indexOf(`/projects/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${b}/`) > -1) {
+ let url = pathname.split(`/tree/${b}/`)[1];
+ setTreeValue(url);
+ getFileInfo(url,branchName);
+ setType("file");
+ }else{
+ setTreeValue(undefined);
+ getDirInfo(branchName || defaultBranch);
+ setType("dir");
+ }
+ }
+ },[projectsId,owner,pathname,defaultBranch])
+
+ // 获取主目录列表
+ function getDirInfo(branch){
+ setIsSpin(true);
+ const url = `/${owner}/${projectsId}/entries.json`;
+
+ axios.get(url, {
+ params: { ref: branch }
+ }).then((result) => {
+ if (result) {
+ setCommitCount(result.data.commits_count);
+ setDirInfo(result.data.entries);
+ setFileInfo(undefined);
+ setTar_url(result.data.tar_url);
+ setZip_url(result.data.zip_url);
+ let c = result.data.last_commit
+ setLastCommit(c && c.commit);
+ setLastCommitAuthor(c && c.committer);
+ setMainFlag(true);
+ setReadOnly(true);
+ setReadme(result.data.readme);
+ setEditReadme(false);
+ setHide(true);
+ }
+ setTimeout(function(){setIsSpin(false);},500);
+ }).catch(error=>{setIsSpin(false);})
+ }
+
+ useEffect(()=>{
+ if(projectDetail && lastCommit)
+ {
+ let ele = document.getElementById("ptxt");
+ if(ele){
+ let h = ele.offsetHeight;
+ if( h > 18 ) setHideBtn(true);
+ }
+ }
+ },[projectDetail,lastCommit])
+ // 获取子目录列表
+ function getFileInfo(path, ref){
+ setIsSpin(true);
+ const url = `/${owner}/${projectsId}/sub_entries.json`;
+ axios.get(url, {
+ params:{
+ filepath:path,
+ ref:ref || branchName,
+ type
+ }
+ }).then((result) => {
+ if (result) {
+ let en = result.data.entries;
+ if(en.type){
+ setDirInfo(undefined);
+ setFileInfo(en);
+ setType(en.type);
+ }else{
+ setFileInfo(undefined);
+ setDirInfo(en);
+ setType("dir");
+ }
+ let c = result.data.last_commit
+ setLastCommit(c && c.commit);
+ setLastCommitAuthor(c && c.committer);
+ setMainFlag(false);
+ setReadOnly(!editReadme);
+ setHide(true);
+ }
+ setTimeout(function(){setIsSpin(false);},500)
+ }).catch(error=>{setIsSpin(false);})
+ }
+
+ // 切换分支或者标签
+ function changeBranch(value){
+ let checkvalue = turnbar(value);
+ let url = `/projects/${owner}/${projectsId}${value && `/tree/${checkvalue}`}${treeValue ? `/${treeValue}`:""}`;
+ props.history.push(url);
+ }
+
+ // 文件相关的下拉项
+ function fileMenu(){
+ let b = branchName || defaultBranch;
+ let checkvalue = turnbar(b);
+ return (
+
+ )
+ }
+
+ function getPathUrl(array,index){
+ if(array && array.length>0 && index){
+ let str = "";
+ for(let i=0;i
+ )
+ // 确认修改简介、website、实践课程链接
+ function okUpdate(d,w,l){
+ const url = `/${owner}/${projectsId}.json`;
+ axios.put(url,{
+ description:d,website:w,lesson_url:l
+ }).then(result=>{
+ if(result && result.data && result.data.id){
+ setDesc(result.data.description);
+ setWebsite(result.data.website);
+ setLessonUrl(result.data.lesson_url);
+ }
+ })
+ }
+ let n = fileInfo && fileInfo.name;
+ const mdFlag = n && n.substring(n.length-3,n.length) === ".md";
+
+ const { current_user } = props;
+ const baseOperate = projectDetail && projectDetail.permission && projectDetail.permission !=="Reporter";
+ const fileOperate = type === "dir" && projectDetail && projectDetail.type !== 2 && ((projectDetail.permission && projectDetail.permission !=="Reporter") || (current_user && current_user.admin));
+ return(
+
+ setOpenModal(false)} onOk={okUpdate}/>
+
+ {
+ (dirInfo || fileInfo) &&
+
+ setVisible(false)}
+ list = {mainFlag ? dirInfo : undefined}
+ />
+ setVisible(true)}>
+
+ 目录
+
+
+ }
+
+ {
+ projectDetail &&
+
+
+
+
+
+
+ {
+ props && props.platform ?
+
+ :
+ 分支:{branchName || defaultBranch}
+ }
+
+
+
+
+ 分支
+ {projectDetail && projectDetail.branches && projectDetail.branches.total_count}
+
+
+
+
+
+ 标签
+ {projectDetail && projectDetail.tags && projectDetail.tags.total_count}
+
+
+
+
+ {
+ baseOperate && projectDetail.type !== 2 && pullsFlag &&
+
+ }
+ {
+ baseOperate && issuesFlag &&
+
+ }
+ { fileOperate &&
+
+
+
+ }
+
+
+
+
+
+
+ {
+ dirInfo || fileInfo ?
+
+ {
+ lastCommit &&
+
+
+
+ {lastCommit && lastCommit.message}
+
+ { hideBtn && changeHide(hide)}> }
+
+ {lastCommit && lastCommit.time_from_now}
+ {
+ commitCount ?
+
+ {commitCount}次提交
+ :""
+ }
+
+ }
+
+ {
+ treeValuePath && treeValuePath.length > 0 &&
+
+ }
+ {
+ dirInfo && dirInfo.length > 0 &&
+ dirInfo.map((item,key)=>{
+ return(
+
+ )
+ })
+ }
+ {
+ fileInfo &&
+
+ }
+
+
+ : ""
+ }
+ {
+ (dirInfo && dirInfo.length === 0) && (fileInfo && fileInfo.length === 0) ? :""
+ }
+ {/* readme文件显示(显示文件详情时不显示readme文件) */}
+ { dirInfo && (readme && readme.content) ? :"" }
+
+
+ {
+ !fileInfo &&
+
+
+
+ 关于
+ {projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner") &&
+ setOpenModal(true)} className="iconfont icon-a-shezhi font-15">
+ }
+
+ {desc && {desc}
}
+ {
+ website &&
+
+
+ {website}
+
+ }
+
+
+ README.md
+
+
+
+ {projectDetail && projectDetail.size}
+
+ {
+ projectDetail && projectDetail.license_name &&
+
+
+ {projectDetail.license_name}
+
+ }
+
+ {
+ inviteCode &&
+
+
+
+
+ }
+ {
+ lesson_url &&
+
+ }
+ {/* 发布 */}
+ {
+ projectDetail && projectDetail.release_versions &&
+
+
+
+
+ }
+ {/* 贡献者 */}
+ {
+ projectDetail && projectDetail.contributors &&
+
+ }
+ {/* 语言 */}
+ { projectDetail && projectDetail.languages &&
+
+
+
+
+ }
+
+
+ }
+
+ }
+
+
+
+ )
+}
+export default CoderDepot;
\ No newline at end of file
diff --git a/src/forge/Main/CoderDepotCatalogue.jsx b/src/forge/Main/CoderDepotCatalogue.jsx
new file mode 100644
index 00000000..37fd3269
--- /dev/null
+++ b/src/forge/Main/CoderDepotCatalogue.jsx
@@ -0,0 +1,28 @@
+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-wenjian5 font-15',
+ "dir":"icon-wenjianjia3 font-15"
+}
+
+function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
+ return(
+
+
+ goToSubRoot(item.path,item.type,item.name)} className={item.type === "submodule" && "submoduleStyle"}>
+ {item.name}
+
+
+
+
+ {item.commit && item.commit.message}
+
+
+ {item.commit && item.commit.time_from_now}
+
+ )
+}
+export default CoderDepotCatalogue;
\ No newline at end of file
diff --git a/src/forge/Main/CoderDepotPath.jsx b/src/forge/Main/CoderDepotPath.jsx
new file mode 100644
index 00000000..ad4bb109
--- /dev/null
+++ b/src/forge/Main/CoderDepotPath.jsx
@@ -0,0 +1,30 @@
+import React from 'react';
+
+
+function CoderDepotPath({treeValuePath , returnUlr , returnMain , getPathUrl , identifier}){
+ return(
+
+
+
+ {identifier}
+
+ {treeValuePath.map((item, key) => {
+ return (
+
+ {
+ key === treeValuePath.length-1 ?
+ {item}
+ :
+ returnUlr(`${getPathUrl(treeValuePath,key+1)}`)} className="color-blue subFileName">{item}
+ }
+
+ );
+ })}
+
+
+ )
+}
+export default CoderDepotPath;
\ No newline at end of file
diff --git a/src/forge/Main/CoderDepotReadme.jsx b/src/forge/Main/CoderDepotReadme.jsx
new file mode 100644
index 00000000..e5f6cbc4
--- /dev/null
+++ b/src/forge/Main/CoderDepotReadme.jsx
@@ -0,0 +1,73 @@
+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';
+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 }
+ });
+ setMenuList(items);
+ },[content])
+
+ function menu(){
+ if(menuList && menuList.length > 0){
+ return(
+
+ )
+ }else{
+ return
+ }
+ }
+
+ return(
+
+
+
+
+
+
+
+ 目录
+
+
+ README.md
+
+ {
+ operate ?
+ ChangeFile(readme && readme.path, false)}>
+
+
+ :""
+ }
+
+
+ {
+ content &&
+
+
+
+ }
+
+ )
+}
+export default CoderDepotReadme;
\ No newline at end of file
diff --git a/src/forge/Main/CoderRootBranch.js b/src/forge/Main/CoderRootBranch.js
index 4369d2fe..0ee71929 100644
--- a/src/forge/Main/CoderRootBranch.js
+++ b/src/forge/Main/CoderRootBranch.js
@@ -3,15 +3,21 @@ import { Link } from "react-router-dom";
import { Dropdown , Menu , Icon , Tooltip , Spin } from 'antd';
import { truncateCommitId } from '../common/util';
import { getBranch } from '../GetData/getData';
+import Nodata from '../Nodata';
+import './list.scss';
-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])
@@ -32,7 +38,7 @@ export default ((props)=>{
return(
- {item.name}
+ {item.name}
{item.last_commit && truncateCommitId(item.last_commit.sha)}
{item.last_commit && item.last_commit.message}
@@ -40,7 +46,10 @@ export default ((props)=>{
- 创建合并请求
+ {
+ (isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) &&
+ 创建合并请求
+ }
@@ -54,6 +63,8 @@ export default ((props)=>{
)
+ }else if(data && data.length === 0){
+ return ( )
}
}
const menu =(zip_url,tar_url)=> (
@@ -62,13 +73,14 @@ export default ((props)=>{
TAR.GZ
)
+
return(
分支列表
- {list()}
+ {list()}
diff --git a/src/forge/Main/CoderRootCommit.js b/src/forge/Main/CoderRootCommit.js
index 0b3526ac..b6ca0be6 100644
--- a/src/forge/Main/CoderRootCommit.js
+++ b/src/forge/Main/CoderRootCommit.js
@@ -2,12 +2,19 @@ import React , { Component } from 'react';
import { Spin , Pagination } from 'antd';
import { getImageUrl } from 'educoder';
import { truncateCommitId } from '../common/util';
+import { AlignTop } from '../Component/layout';
import SelectBranch from '../Branch/Select';
import Nodata from '../Nodata';
import axios from 'axios';
import {Link} from "react-router-dom";
+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)
@@ -16,12 +23,24 @@ class CoderRootCommit extends Component{
dataCount:undefined,
limit:20,
page:1,
- isSpining:false
+ isSpining:false,
+ branchList:undefined
}
}
componentDidMount=()=>{
this.Init();
+ this.getBranchs();
+ }
+
+ // 获取分支列表
+ getBranchs=()=>{
+ const { projectsId , owner } = this.props.match.params;
+ axios.get(`/${owner}/${projectsId}/branches.json`).then(result=>{
+ this.setState({
+ branchList:result.data
+ })
+ }).catch((error)=>{})
}
componentDidUpdate=(prevProps)=>{
@@ -44,11 +63,12 @@ class CoderRootCommit extends Component{
this.setState({
isSpining:true
})
+ console.log(returnbar(branch));
const { projectsId , owner } = this.props.match.params;
const url = `/${owner}/${projectsId}/commits.json`;
axios.get(url,{
params:{
- sha:branch,
+ sha:returnbar(branch),
page,
limit
}
@@ -62,6 +82,7 @@ class CoderRootCommit extends Component{
array.push({
name:item.author && item.author.name,
login: item.author && item.author.login,
+ id: item.author && item.author.id,
image_url:item.author && item.author.image_url,
sha:item.sha,
time_from_now:item.time_from_now,
@@ -79,14 +100,6 @@ class CoderRootCommit extends Component{
// 切换分支 search:tag为根据标签搜索
changeBranch=(value)=>{
- // const { page , limit } = this.state;
- // const { getTopCount } = this.props;
- // this.setState({
- // isSpining:true,
- // branch:value,
- // })
- // this.getCommitList(value , page , limit);
- // getTopCount && getTopCount(value);
const { projectsId , owner } = this.props.match.params;
this.props.history.push(`/projects/${owner}/${projectsId}/commits/branch/${value}`);
}
@@ -97,13 +110,13 @@ class CoderRootCommit extends Component{
this.getCommitList(branchName , page , limit);
}
render(){
- const { commitDatas , dataCount , limit , page , isSpining } = this.state;
+ 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 = branchName || defaultBranch;
+ let branch = returnbar(branchName || defaultBranch);
return(
-
+
@@ -123,23 +137,32 @@ class CoderRootCommit extends Component{
{
- commitDatas && commitDatas.length > 0 ? commitDatas.map((item,k)=>{
+ commitDatas && commitDatas.length > 0 && commitDatas.map((item,k)=>{
return(
-
- {truncateCommitId(`${item.sha}`)}
- {item.message}
-
+
+ {truncateCommitId(`${item.sha}`)}
+ {item.message}
+
-
- {item.image_url?
:""}
-
-
+ {
+ item.id ?
+
+ {item.image_url?
:""}
+
+ :
+
+ {item.image_url?
:""}
+
+
+ }
+
)
- }):
+ })
}
+ {commitDatas && commitDatas.length === 0 && }
{
diff --git a/src/forge/Main/CoderRootDirectory.js b/src/forge/Main/CoderRootDirectory.js
deleted file mode 100644
index 21a6a59f..00000000
--- a/src/forge/Main/CoderRootDirectory.js
+++ /dev/null
@@ -1,543 +0,0 @@
-import React, { Component } from "react";
-import { Menu, Spin } from "antd";
-import { getImageUrl } from "educoder";
-import { Link } from "react-router-dom";
-
-import './list.css';
-import SelectBranch from '../Branch/Select';
-import CloneAddress from '../Branch/CloneAddress';
-import RootTable from './RootTable';
-import CoderRootFileDetail from './CoderRootFileDetail';
-import { truncateCommitId } from '../common/util';
-import RenderHtml from '../../components/render-html';
-import Nodata from '../Nodata';
-
-import axios from "axios";
-/**
- * address:http和SSH,http_url(对应git地址)
- * filePath:点击目录时当前目录的路径
- * subfileType:保存当前点击目录的文件类型(显示目录列表时才显示新建文件,如果点击的是文件就不显示新建文件按钮)
- * readMeContent:根目录下面的readme文件内容
- */
-function getPathUrl(array,index){
- if(array && array.length>0 && index){
- let str = "";
- for(let i=0;i {
- this.setState({
- address,
- });
- };
-
- componentDidMount = () => {
- this.Init();
- };
-
- componentDidUpdate = (prevState) => {
- const { location } = this.props;
- const prevlocation = prevState && prevState.location;
- if (location !== prevlocation) {
- this.setState({
- isSpin: true,
- });
- this.Init();
- }
- };
-
- Init = () => {
- let { search } = this.props.history.location;
- const { branchName } = this.props.match.params;
- const { defaultBranch } = this.props;
- let branch = branchName || defaultBranch;
- if (search && (search.indexOf("?url=") > -1 || search.indexOf("&url=") > -1)) {
- let url = search.split("url=")[1];
- if(url && decodeURI(url).indexOf("&")){
- url=decodeURI(url).split("&")[0];
- }
- this.getFileDetail(decodeURI(url),branch);
- } else {
- this.getProjectRoot(branch);
- }
- };
-
- // 页面地址返回到主目录
- returnMain = (branch) => {
- const { projectsId , owner , branchName } = this.props.match.params;
- this.setState({
- readOnly:true
- })
- this.props.history.push(`/projects/${owner}/${projectsId}${branchName?`/branch/${branchName}`:""}`);
- this.getProjectRoot(branch);
- };
-
- // 获取根目录
- getProjectRoot = (branch) => {
- const { projectsId , owner } = this.props.match.params;
- const url = `/${owner}/${projectsId}/entries.json`;
- axios.get(url, { params: { ref: branch } })
- .then((result) => {
- if (result) {
- let last_commit = result.data && result.data.last_commit;
- let entries = result.data && result.data.entries;
- this.setState({
- filePath: undefined,
- fileDetail: undefined,
- isSpin: false,
- branchLastCommit: last_commit && last_commit.commit,
- lastCommitAuthor:
- last_commit && (last_commit.author || (last_commit.commit && last_commit.commit.author)),
- zip_url: result.data.zip_url,
- tar_url: result.data.tar_url
- });
- if (entries && entries.length > 0) {
- this.renderData(entries);
- }
- this.setState({
- rootList: entries,
- subFileType: true,
- });
- }
- }).catch((error) => {});
- };
-
- ChangeFile = (arr, readOnly) => {
- const { projectsId , owner } = this.props.match.params;
- //点击直接跳转页面 加载一次路由
- this.props.history.push(`/projects/${owner}/${projectsId}?url=${arr.path}`);
- this.setState({
- readOnly: readOnly,
- chooseType:"file"
- });
- };
-
- renderUrl = (name, path, type) => {
- let list = [];
- const { filePath } = this.state;
- if (path.indexOf("/")) {
- const array = path.split("/");
- let str = "";
- array.map((i, k) => {
- str += "/" + i;
- return list.push({
- key: k,
- index: k,
- name: i,
- path: str.substr(1),
- type: filePath && filePath.length > 0 ? filePath[k] ? filePath[k].type : type : type,
- });
- });
- const { projectsId , owner } = this.props.match.params;
- //点击直接跳转页面 加载一次路由
- this.props.history.push(`/projects/${owner}/${projectsId}?url=${str.substr(1)}`);
- } else {
- list.push({
- index: 0,
- name,
- path,
- type,
- });
- }
- this.setState({
- filePath: list,
- });
- };
-
- // 获取子目录
- getFileDetail = (path, ref) => {
- this.setState({
- filePath: decodeURI(path),
- });
- const { projectsId , owner , branchName } = this.props.match.params;
- const { chooseType } = this.state;
- const url = `/${owner}/${projectsId}/sub_entries.json`;
- axios.get(url,{
- params:{
- filepath:path,
- ref:ref || branchName,
- type:chooseType
- }
- }).then((result)=>{
- let entries = result.data && result.data.entries;
- this.setState({
- isSpin:false
- })
- if(result){
- if(entries){
- // 返回对象entries.type则是文件类型,否则是文件夹
- if(entries.type){
- this.setState({
- fileDetail:[entries],
- rootList:undefined,
- subFileType:false
- })
- }else{
- this.setState({
- fileDetail:undefined,
- rootList:entries,
- branchLastCommit:result.data.last_commit && result.data.last_commit.commit,
- lastCommitAuthor:result.data.last_commit && (result.data.last_commit.author || (result.data.last_commit.commit && result.data.last_commit.commit.author))
- })
- this.renderData(entries);
- }
- }else{
- this.setState({
- fileDetail:undefined,
- rootList:undefined,
- isSpin:false,
- subFileType:false
- })
- }
- }
- })
- .catch((error) => {
- this.setState({
- isSpin:false
- })
- console.log(error);
- });
- };
-
- renderData = (data) => {
- const rootList = [];
- const readMeContent = [];
- const readMeFile = [];
- data && data.map((item, key) => {
- rootList.push({
- key,
- message: item.commit && item.commit.message,
- ...item,
- });
- if (item.is_readme_file) {
- readMeContent.push({ ...item });
- readMeFile.push({ ...item });
- }
- });
- this.setState({
- rootList: rootList,
- readMeContent,
- readMeFile,
- });
- };
-
- // 点击跳转到子目录
- goToSubRoot=(path,type,filename)=>{
- this.setState({
- chooseType:type
- })
- const { projectsId, owner , branchName } = this.props.match.params;
- this.props.history.push(`/projects/${owner}/${projectsId}${branchName?`/branch/${branchName}`:""}?url=${path}`);
- if(filename.substring(filename.length - 3) === ".md"){
- this.setState({
- md:true
- })
- }else{
- this.setState({
- md:false
- })
- }
- };
-
- // readme文件内容
- renderReadMeContent = (readMeContent, permission) => {
- const { fileDetail, readMeFile } = this.state;
- if (fileDetail) {
- return;
- }
- if (readMeContent && readMeContent.length > 0) {
- return (
-
-
-
-
-
-
- {readMeContent[0].name}
-
- {permission ?
- this.ChangeFile(readMeFile[0], false)}
- className="ml20 pull-right"
- >
-
-
- :
- ""
- }
-
-
- {readMeContent[0].content ?
-
- :
- 暂无~
- }
-
-
- );
- }
- };
-
- // 选择分支
- changeBranch = (value) => {
- let { search } = this.props.history.location;
- const { projectsId , owner } = this.props.match.params;
-
- let url = `/projects/${owner}/${projectsId}${value && `/branch/${value}`}`;
- if (search && (search.indexOf("?url=") > -1 || search.indexOf("&url=") > -1)) {
- let u = search.split("url=")[1];
- if(u && decodeURI(u).indexOf("&")){
- u=decodeURI(u).split("&")[0];
- }
- url += `?url=${u}`;
- }
- this.props.history.push(url);
- }
-
- // 子目录路径返回链接
- returnUlr=(url)=>{
- this.setState({
- chooseType:"dir",
- readOnly:true
- })
- const { projectsId , owner } = this.props.match.params;
- this.props.history.push(`/projects/${owner}/${projectsId}?url=${url}`);
- }
-
- onEdit=(readOnly)=>{
- this.setState({
- readOnly
- })
- }
-
- downloadUrl = (zip_url,tar_url) => {
- return(
-
- )
- }
-
- title = (branchLastCommit,lastCommitAuthor) => {
- if (branchLastCommit) {
- const { projectsId , owner } = this.props.match.params;
- return (
-
- {lastCommitAuthor ? (
-
- {lastCommitAuthor.login ? (
-
-
- {lastCommitAuthor.name}
-
- ) : (
- {lastCommitAuthor.name}
- )}
-
- ) : (
- ""
- )}
-
- {branchLastCommit.message}
-
- {branchLastCommit.time_from_now}
-
- {truncateCommitId(branchLastCommit.sha)}
-
-
- );
- }else{
- return false;
- }
- }
-
- render(){
- const { branchLastCommit , lastCommitAuthor , rootList ,filePath , fileDetail , subFileType , readMeContent, isSpin , zip_url , tar_url} = this.state;
- const { isManager , isDeveloper , projectDetail , platform , defaultBranch } = this.props;
-
- const { projectsId , owner , branchName } = this.props.match.params;
- let branch = branchName || defaultBranch;
- const columns = [
- {
- key:"name",
- dataIndex: 'name',
- width:"30%",
- render: (text,item) => (
- this.goToSubRoot(item.path,item.type,text)} className="ml12 task-hide" style={{ display: "block", maxWidth: "345px" }}>
- {text}
-
- ),
- },
- {
- key:"message",
- dataIndex: "message",
- width: "60%",
- render: (text, item) =>
- item.commit && item.commit.message ?
-
- {item.commit.message}
-
- : ""
- },
- {
- key:"time_from_now",
- dataIndex: "time_from_now",
- width: "10%",
- className: "edu-txt-right",
- render: (text, item) =>
- item.commit && item.commit.time_from_now ?
-
- {item.commit.time_from_now}
-
- :""
- },
- ];
-
- const urlRoot = filePath === undefined ? "" : `/${filePath}`;
- let array = filePath && filePath.split("/");
- return (
-
-
-
-
- {
- platform ?
-
- :
- 分支:master
- }
-
-
- {filePath && (
-
- this.returnMain(branch)}
- className="color-blue"
- >
- {projectDetail && projectDetail.identifier}
-
- {array &&
- array.map((item, key) => {
- return (
-
- {
- key === array.length-1 ?
- {item}
- :
- this.returnUlr(`${getPathUrl(array,key+1)}`)} className="color-blue subFileName">{item}
- }
-
- );
- })}
-
- )}
-
-
- {subFileType && (projectDetail && parseInt(projectDetail.type)) !== 2 && (isManager || isDeveloper) && platform && (
-
-
-
- 上传文件
-
-
-
-
- 新建文件
-
-
-
- )}
- {projectDetail && projectDetail.clone_url && (
-
- )}
-
-
- {/* 主目录列表 */}
- {rootList && (
- this.title(branchLastCommit,lastCommitAuthor)}
- >
- )}
- {/* 子目录列表、文件 */}
- {fileDetail && fileDetail.length > 0 && (
-
- )}
- {
- !rootList && !fileDetail &&
- }
- { rootList && this.renderReadMeContent(readMeContent, isManager || isDeveloper)}
-
-
- );
- }
-}
-export default CoderRootDirectory;
diff --git a/src/forge/Main/CoderRootFileDetail.js b/src/forge/Main/CoderRootFileDetail.js
index 343d2826..4adb229d 100644
--- a/src/forge/Main/CoderRootFileDetail.js
+++ b/src/forge/Main/CoderRootFileDetail.js
@@ -1,6 +1,6 @@
import React, { Component } from "react";
import { Popconfirm , Select } from "antd";
-import "./list.css";
+import "./list.scss";
import axios from "axios";
import Meditor from "../Newfile/m_editor";
import RenderHtml from "../../components/render-html";
@@ -24,13 +24,25 @@ class CoderRootFileDetail extends Component {
}
componentDidMount = () => {
- const { detail } = this.props;
+ const { detail , mdFlag } = this.props;
this.setState({
value: detail.content,
});
this.languages_total();
};
+ componentDidUpdate=(prevProps)=>{
+ const { content } = this.props && this.props.detail;
+ const prevcontent = prevProps.detail && prevProps.detail.content;
+ if (content && prevcontent) {
+ if (prevcontent !== content){
+ this.setState({
+ description: content
+ });
+ }
+ }
+ }
+
languages_total = () => {
const { detail } = this.props;
const file_name = detail.path.split("/").pop().split(".").pop();
@@ -164,15 +176,16 @@ class CoderRootFileDetail extends Component {
current_user,
isManager,
isDeveloper,
- md,
currentBranch,
- platform
+ platform,
+ md,
+ type
} = this.props;
const { language, languages, description } = this.state;
let flag = current_user && current_user.login && (isManager || isDeveloper);
const Option = Select.Option;
return (
-
+
@@ -185,17 +198,18 @@ class CoderRootFileDetail extends Component {
{readOnly ? (
{
- detail.direct_download ?
- ""
- :
+ !detail.direct_download?
this.DownLoadFile(detail.download_url)} className="ml20">
- this.EditFile(false)} className="ml20">
-
-
-
+ {
+ type !==2 &&
+ this.EditFile(false)} className="ml20">
+
+
+ }
+ :""
}
) : (
@@ -226,18 +240,21 @@ class CoderRootFileDetail extends Component {
)}
-
-
-
-
-
-
+ {
+ type !==2 &&
+
+
+
+
+
+ }
+
)}
@@ -245,11 +262,7 @@ class CoderRootFileDetail extends Component {
{detail.image_type ? (
-
+
) : detail.direct_download ? (
@@ -260,7 +273,7 @@ class CoderRootFileDetail extends Component {
) : (
md && readOnly ?
-
+
:
)}
-
+
);
}
}
diff --git a/src/forge/Main/CoderRootIndex.js b/src/forge/Main/CoderRootIndex.js
index 27dbbb9d..84ab94d3 100644
--- a/src/forge/Main/CoderRootIndex.js
+++ b/src/forge/Main/CoderRootIndex.js
@@ -13,10 +13,6 @@ const UploadFile = Loadable({
loader: () => import('../Newfile/upload_file'),
loading: Loading,
})
-const CoderRootDirectory = Loadable({
- loader: () => import('./CoderRootDirectory'),
- loading: Loading,
-})
const CoderRootCommit = Loadable({
loader: () => import('./CoderRootCommit'),
loading: Loading,
@@ -71,6 +67,7 @@ class CoderRootIndex extends Component{
this.getTopCount(branchName || defaultBranch);
}
+ // 获取 组件里要显示的数据
getTopCount=(branch)=>{
const { projectsId , owner } = this.props.match.params;
const url = `/${owner}/${projectsId}/top_counts.json`;
@@ -105,11 +102,9 @@ class CoderRootIndex extends Component{
(props) => ( )
}
>
-
- {/* diff */}
( )
+ () => ( )
}
>
( )
}
>
-
( )
@@ -133,33 +127,21 @@ class CoderRootIndex extends Component{
() => ( )
}
>
-
( )
}
>
-
( )
}
>
- ( )
- }
- >
( )
}
>
- ( )
- }
- >
)
diff --git a/src/forge/Main/CoderRootTag.js b/src/forge/Main/CoderRootTag.js
index 6a035fee..a87386d5 100644
--- a/src/forge/Main/CoderRootTag.js
+++ b/src/forge/Main/CoderRootTag.js
@@ -26,10 +26,11 @@ export default (( props, { projectDetail }) => {
}, [owner, projectsId]);
return (
-
+
- {
- data && data.length > 0 ?
+
+ {
+ data && data.length > 0 &&
-
@@ -40,7 +41,7 @@ export default (( props, { projectDetail }) => {
{
- data && data.length > 0 && data.map((item, key) => {
+ data.map((item, key) => {
return (
-
@@ -60,9 +61,9 @@ export default (( props, { projectDetail }) => {
}
- :
-
- }
+ }
+ { data && data.length === 0 && }
+
)
diff --git a/src/forge/Main/Detail.js b/src/forge/Main/Detail.js
index 685e297d..dc6da437 100644
--- a/src/forge/Main/Detail.js
+++ b/src/forge/Main/Detail.js
@@ -1,26 +1,17 @@
import React, { Component } from 'react';
-import { Spin, Tooltip } from 'antd';
+import { Spin, Tooltip, Button } from 'antd';
import { Link, Route, Switch } from 'react-router-dom';
-import { Content } from '../Component/layout';
+import { Content , AlignTop, AlignCenter } from '../Component/layout';
+import DetailBanner from './sub/DetailBanner';
+import { numFormat } from 'educoder';
import '../css/index.scss'
-import './list.css';
+import './list.scss';
import Loadable from 'react-loadable';
import Loading from '../../Loading';
import axios from 'axios';
-import img_1 from '../Images/1.png';
-import img_2 from '../Images/2.png';
-import img_3 from '../Images/3.png';
-import img_6 from '../Images/6.png';
-import img_7 from '../Images/7.png';
-import img_parise from '../Images/parise.png';
-import img_focus from '../Images/focus.png';
-import img_parised from '../Images/parised.png';
-import img_focused from '../Images/focused.png';
-import img_fork from '../Images/fork.png';
-import img_milepost from '../Images/milepost.png';
const Setting = Loadable({
loader: () => import('../Settings/Index'),
loading: Loading,
@@ -107,7 +98,19 @@ const ForkUsers = Loadable({
loader: () => import('../UsersList/fork_users'),
loading: Loading,
})
+const Contribute = Loadable({
+ loader: () => import('./sub/Contribute'),
+ loading: Loading,
+})
+const CoderRootCommit = Loadable({
+ loader: () => import('./CoderRootCommit'),
+ loading: Loading,
+})
+const CoderDepot = Loadable({
+ loader: () => import('./CoderDepot'),
+ loading: Loading,
+})
const TrendsIndex = Loadable({
loader: () => import('../Activity/Activity'),
@@ -118,30 +121,47 @@ const DevAbout = Loadable({
loader: () => import('../About/Index'),
loading: Loading,
})
+const Source = Loadable({
+ loader: () => import('../Source/Index'),
+ loading: Loading,
+})
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,
+});
/**
* permission:Manager:管理员,Reporter:报告人员(只有读取权限),Developer:开发人员(除不能设置仓库信息外)
*/
-function checkPathname(pathname){
+function checkPathname(projectsId,owner,pathname){
let name = "";
- if(pathname){
- if(pathname.indexOf("/about")>-1){
+ if(pathname && pathname !== `/projects/${owner}/${projectsId}`){
+ let url = pathname.split(`/projects/${owner}/${projectsId}`)[1];
+ if(url.indexOf("/about")>-1){
name="about"
- }else if(pathname.indexOf("/issues")>-1 ||pathname.indexOf("Milepost") > 0){
+ }else if(url.indexOf("/issues")>-1 ||url.indexOf("Milepost") > 0){
name = "issues";
- }else if(pathname.indexOf("/pulls")>-1){
+ }else if(url.indexOf("/pulls")>-1){
name="pulls"
- }else if(pathname.indexOf("/milestones")>-1){
+ }else if(url.indexOf("/milestones")>-1){
name="milestones"
- }else if(pathname.indexOf("/activity")>-1){
+ }else if(url.indexOf("/activity")>-1){
name="activity"
- }else if(pathname.indexOf("/setting")>-1){
+ }else if(url.indexOf("/setting")>-1){
name="setting"
- }else if(pathname.indexOf("/devops")>-1){
+ }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;
@@ -161,13 +181,13 @@ class Detail extends Component {
watched: false,
praised: false,
http_url: undefined,
- author: undefined,
branchs: undefined,
branchList: undefined,
project: null,
firstSync:false,
secondSync:false,
open_devops:false,
+ forkSpin:false,
// 默认分支
defaultBranch:undefined,
@@ -199,17 +219,6 @@ class Detail extends Component {
platform:result.data.platform && result.data.platform !== 'educoder'
})
- // 工作流:两种状态进入的链接不同
- const pathname = this.props.history.location.pathname;
- let p = checkPathname(pathname);
- if(p==="devops"){
- if(result.data.open_devops && pathname === `/projects/${owner}/${projectsId}/devops`){
- this.props.history.push(`/projects/${owner}/${projectsId}/devops/list`);
- }else if(result.data.open_devops===false && pathname !== `/projects/${owner}/${projectsId}/devops`){
- this.props.history.push(`/projects/${owner}/${projectsId}/devops`);
- }
- }
-
if (result.data.type !== 0 && result.data.mirror_status === 1) {
console.log("--------start channel --------");
// 是镜像项目,且未完成迁移
@@ -217,7 +226,7 @@ class Detail extends Component {
if(num){
this.setState({
secondSync:true,
- firsrtSync:false
+ firstSync:false
})
}else{
this.setState({
@@ -228,7 +237,7 @@ class Detail extends Component {
}else{
this.getDetail();
this.setState({
- firsrtSync:false,
+ firstSync:false,
secondSync:false
})
}
@@ -249,7 +258,7 @@ class Detail extends Component {
var cable = actioncable.createConsumer(`wss://${name}/cable`);
this.canvasChannel1 = cable.subscriptions.create({
channel: `MirrorProjectChannel`,
- id: project && project.identifier
+ id: project && project.id
}, {
connected: () => {
console.log("###### channel connected! ######");
@@ -259,6 +268,10 @@ class Detail extends Component {
console.log(`###### ---received data--- ######`);
if (data) {
this.getDetail();
+ this.setState({
+ firstSync:false,
+ secondSync:false
+ });
cable.subscriptions.consumer.disconnect();
}
}
@@ -267,7 +280,8 @@ class Detail extends Component {
getDetail = () => {
const { projectsId , owner } = this.props.match.params;
- const url = `/${owner}/${projectsId}.json`;
+ this.getBanner();
+ const url = `/${owner}/${projectsId}/detail.json`;
axios.get(url).then((result) => {
if (result && result.data) {
this.setState({
@@ -277,7 +291,6 @@ class Detail extends Component {
isReporter: result.data.permission && result.data.permission === "Reporter",
isDeveloper: result.data.permission && result.data.permission === "Developer",
http_url: result.data.clone_url,
- author: result.data.author,
praised: result.data.praised,
watched: result.data.watched,
watchers_count: result.data.watchers_count,
@@ -289,6 +302,19 @@ class Detail extends Component {
}).catch((error) => { })
}
+ // 获取动态导航栏菜单
+ getBanner(){
+ const { projectsId , owner } = this.props.match.params;
+ const url = `/${owner}/${projectsId}/menu_list.json`;
+ axios.get(url).then(result=>{
+ if(result){
+ this.setState({
+ bannerList:result.data
+ })
+ }
+ }).catch(error=>{})
+ }
+
// 关注和取消关注
focusFunc = (flag) => {
const { platform } = this.state;
@@ -348,6 +374,9 @@ 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`;
@@ -356,8 +385,13 @@ class Detail extends Component {
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 => {
- console.log(error);
+ this.setState({
+ forkSpin:false
+ })
})
}
@@ -369,6 +403,7 @@ 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.props.showNotification("镜像同步成功!");
this.getProject(2);
} else {
this.props.showNotification("镜像同步失败!");
@@ -378,32 +413,33 @@ 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 ?
+
+ 复刻自
+ {fork_info.fork_project_user_name}
+ /
+ {fork_info.fork_form_name}
+ : ""
+ }
+
render() {
const { projectDetail, watchers_count, praises_count,
forked_count, firstSync , secondSync ,
isManager, watched, praised,
- project , open_devops , platform , defaultBranch } = this.state;
+ project , open_devops , platform , defaultBranch , bannerList , forkSpin } = this.state;
const url = this.props.history.location.pathname;
const urlArr = url.split("/");
const urlFlag = (urlArr.length === 3);
- let pathname = checkPathname(url);
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 ?
-
- forked from
- {projectDetail.fork_info.fork_project_user_name}
- /
- {projectDetail.fork_info.fork_form_name}
- : ""
- );
-
const common = {
getDetail: this.getDetail,
changeOpenDevops:this.changeOpenDevops,
@@ -413,175 +449,148 @@ class Detail extends Component {
-
-
- {project && project.author &&
-
- {project.author.name}
-
- }
- /
-
- {project && project.name}
- {
- projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ?
-
-
-
+
+
+
+
+ {project && project.author &&
+ {project.author.name}
+ }
+ /
+ {projectDetail && projectDetail.name}
+
+ { projectDetail && projectDetail.private && 私有}
+
+
+
+ {
+ firstSync ? "":
+
+ {
+ ((current_user && current_user.admin) || isManager) && (projectDetail && projectDetail.type && projectDetail.type === 2) ?
+ 同步镜像 : ""
+ }
+
+ this.focusFunc(watched)}>
+
+ {watched ? '取消关注' : '关注'}
+
+ {
+ watchers_count > 0 ?
+ platform ?
+
+ {numFormat(watchers_count)}
- : ""
- }
- {
- projectDetail && projectDetail.type && projectDetail.type !== 0 ?
- projectDetail.type === 2 ?
-
-
-
- :
-
-
-
- :""
- }
-
-
+ :
+ {watchers_count}
+ :""
+ }
+
+
+ this.pariseFunc(praised)}>
+
+ {praised ? '取消点赞' : '点赞'}
+
+ {
+ praises_count > 0 ?
+ platform ?
+
+ {numFormat(praises_count)}
+ :
+ {praises_count}
+ :""
+ }
+
+
+
+
+
+ 复刻
+
+
+ {
+ forked_count > 0 ?
+ platform ?
+
+ {numFormat(forked_count)}
+
+ :
+ {forked_count}
+ :""
+ }
+
+
+ }
+
+
+
{
- firstSync ? "":
-
- {
- projectDetail && projectDetail.type && projectDetail.type === 2 ?
- 同步镜像 : ""
- }
-
- this.focusFunc(watched)}>
-
- {watched ? '取消关注' : '关注'}
-
- {
- platform ?
-
- {watchers_count}
-
- :
- {watchers_count}
- }
-
-
-
- this.pariseFunc(praised)}>
-
- {praised ? '取消点赞' : '点赞'}
-
- {
- platform ?
-
- {praises_count}
- :
- {praises_count}
- }
-
-
-
- Fork
-
- {
- platform ?
-
- {forked_count}
-
- :
- {praises_count}
- }
-
-
+ 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 ?
+ 镜像自 {projectDetail.mirror_url}
+ :""
}
{
firstSync ? "" :
-
-
- -
-
-
- 主页
-
-
- -
-
-
- 代码库
-
-
- -
-
-
- 任务
- {projectDetail && projectDetail.issues_count ? {projectDetail.issues_count} : ""}
-
-
- {
- projectDetail && parseInt(projectDetail.type) !== 2 && platform &&
- -
-
-
- 合并请求
- {projectDetail && projectDetail.pull_requests_count ? {projectDetail.pull_requests_count} : ""}
-
-
- }
- {
- platform &&
- -
-
- 工作流(beta版)
- {projectDetail && projectDetail.ops_count ? {projectDetail.ops_count} : ""}
-
-
- }
-
- -
-
-
- 里程碑
- {projectDetail && projectDetail.versions_count ? {projectDetail.versions_count} :""}
-
-
- -
-
-
- 动态
-
-
- {
- isManager && platform &&
- - 0 ? "active" : ""}>
-
- 0 ? "iconfont icon-cangku color-grey-3 mr5 font-14":"iconfont icon-cangku color-grey-6 font-14 mr5"}>
- 仓库设置
-
-
- }
-
-
+
}
{
firstSync ?
-
-
+
:
+ {/* 资源 */}
+ ( )
+ }
+ >
{/* 主页 */}
( )
}
>
+ {/* wiki新增文件 */}
+ ( )
+ }
+ >
+ {/* wiki编辑文件 */}
+ ( )
+ }
+ >
+ {/* wiki */}
+ ( )
+ }
+ >
{/* 工作流 */}
( )
}
>
+ {/* 新建合并请求 */}
+ ( )
+ }
+ >
( )
@@ -692,11 +707,6 @@ class Detail extends Component {
(props) => ( )
}
>
- ( )
- }
- >
( )
@@ -712,19 +722,32 @@ class Detail extends Component {
(props) => ( )
}
>
- ( )
+ () => ( )
}
>
- ( )
+ (props) => ( )
+ }
+ >
+ ( )
+ }
+ >
+ ( )
}
>
( )
+ (props) => ( )
}
>
diff --git a/src/forge/Main/Diff.jsx b/src/forge/Main/Diff.jsx
index 8007e1fc..a6b0b49c 100644
--- a/src/forge/Main/Diff.jsx
+++ b/src/forge/Main/Diff.jsx
@@ -51,7 +51,7 @@ export default ({ match , history }) => {
}
}, [projectsId , owner, sha]);
return (
-
+
@@ -59,13 +59,13 @@ export default ({ match , history }) => {
{commit && commit.message &&
{commit.message}
}
-
+
{committer && committer.time_from_now && - {committer.time_from_now}
}
diff --git a/src/forge/Main/Index.js b/src/forge/Main/Index.js
index 4952d429..0169d84b 100644
--- a/src/forge/Main/Index.js
+++ b/src/forge/Main/Index.js
@@ -1,9 +1,12 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { Menu, Input , Spin, Pagination , Popover , Select } from 'antd';
-import { getUrl } from 'educoder';
+import Slider from "react-slick";
+import { getImageUrl } from 'educoder';
+import "slick-carousel/slick/slick.css";
+import "slick-carousel/slick/slick-theme.css";
import '../css/index.scss'
-import './list.css';
+import './list.scss';
import './Index.scss';
import ListItem from './IndexItem'
import axios from 'axios';
@@ -30,6 +33,8 @@ class Index extends Component {
categoryList: undefined,
recommendList:undefined,
+ recommendOriList:undefined,
+
languageList:undefined,
languageId:undefined
}
@@ -47,6 +52,8 @@ class Index extends Component {
this.getRecommand();
this.getLanguage();
+
+ // this.getRecommandOri();
}
// 获取语言列表
@@ -72,6 +79,17 @@ class Index extends Component {
}).catch(error=>{})
}
+ getRecommandOri=()=>{
+ const url = `/organizations/recommend.json`;
+ axios.get(url).then(result=>{
+ if(result){
+ this.setState({
+ recommendOriList:result.data.organizations
+ })
+ }
+ }).catch(error=>{})
+ }
+
// 获取列表
getListData = (page, limit, search, sort, project_type, category_id,languageId) => {
const { current_user } = this.props;
@@ -245,10 +263,10 @@ class Index extends Component {
pagination=(total,limit,page)=>{
return(
- total && total > limit &&
+ total && total > limit ?
-
+
:""
)
}
@@ -256,22 +274,56 @@ class Index extends Component {
const { current_user } = this.props;
const { projectsList , recommendList , languageList , languageId ,
- isSpin, total, search, limit, page, typeList, categoryList } = this.state;
+ isSpin, total, search, limit, page, typeList, categoryList , recommendOriList } = this.state;
+
+ const setting={
+ dots: true,
+ infinite: true,
+ speed: 500,
+ slidesToShow: 5,
+ slidesToScroll: 5,
+ autoplay:false,
+ arrows:false,
+ adaptiveHeight:true
+ }
+ const settings={
+ dots: true,
+ infinite: true,
+ speed: 500,
+ slidesToShow: 6,
+ slidesToScroll: 6,
+ autoplay:false,
+ arrows:false,
+ adaptiveHeight:true
+ }
return (
+ {/* {
+ recommendOriList && recommendOriList.length>0?
+
+ {
+ recommendOriList.map((i,k)=>{
+ return(
+ })
+ )
+ })
+ }
+
+ :""
+ } */}
{
recommendList && recommendList.length>0 &&
-
+ 5 ? "recommandProjects":"recommandProjects mb20"}>
{
recommendList.map((item,key)=>{
return(
- this.getoDetail(item.author && item.author.login,item.identifier)}>
+ this.getoDetail(item.author && item.author.login,item.identifier)}>
-
+
{item.name}
{item.author && item.author.name}
@@ -283,9 +335,8 @@ class Index extends Component {
)
})
}
-
+
}
-
diff --git a/src/forge/Main/Index.scss b/src/forge/Main/Index.scss
index cb006f67..d6331066 100644
--- a/src/forge/Main/Index.scss
+++ b/src/forge/Main/Index.scss
@@ -1,56 +1,53 @@
+.recommandOri.slick-slider{
+ width: 1300px;
+ margin:20px auto 40px;
+ .slick-track{
+ margin-left: 0px;
+ }
+ .slick-slide{
+ li > a{
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ }
+}
/* recommandProjects */
-.recommandProjects{
- display: flex;
- max-width: 1200px;
- margin:20px auto;
-}
-.recommandProjects >div{
- background-color: #fff;
- border-radius: 10px;
- width: 220px;
- margin-right: 25px;
- cursor: pointer;
- &:last-child{
- margin-right: 0px;
+.recommandProjects.slick-slider{
+ width: 1230px;
+ margin:20px auto 40px;
+ .slick-track{
+ margin-left: 0px;
}
-}
-.recommandProjects > div:hover{
- box-shadow: 0px 2px 20px 0px rgba(0, 0, 0, 0.1);
-}
-.recommandProjects > div .mainInfo{
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- min-height: 160px;
- border-bottom: 1px solid #eee;
- padding:20px;
- box-sizing: border-box;
- img{
- height: 50px;
- width:50px;
- border-radius: 50%;
+ .slick-arrow.slick-prev,.slick-arrow.slick-next{
+ &:before{
+ color: #999;
+ }
+ li.slick-active button:before{
+ color: #999;
+ }
}
- .name{
- font-size: 13px;
- color: #666;
- height: 18px;
- line-height: 18px;
- margin-top:12px;
+ .slick-dots{
+ bottom: -29px;
+ li button:before{
+ color: #909090;
+ }
}
- .school{
- margin-top:12px;
- color: #333;
- font-size: 16px;
- height: 22px;
- line-height: 22px;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- max-width:100%;
+ .slick-slide{
+ padding:0px 15px;
+ box-sizing: border-box;
+ & > div{
+ background-color: #fff;
+ border-radius: 10px;
+ width: 100%;
+ cursor: pointer;
+ border: 1px solid #eee;
+ &:hover{
+ box-shadow: 0px 2px 20px 0px rgba(0, 0, 0, 0.1);
+ }
+ }
}
-}
-.recommandProjects{
.baseInfo{
padding:18px 15px;
display: flex;
@@ -71,4 +68,355 @@
text-align: right;
}
}
+ .mainInfo{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ min-height: 160px;
+ border-bottom: 1px solid #eee;
+ padding:20px;
+ box-sizing: border-box;
+ img{
+ height: 50px;
+ width:50px;
+ border-radius: 50%;
+ }
+ .name{
+ font-size: 13px;
+ color: #666;
+ height: 18px;
+ line-height: 18px;
+ margin-top:12px;
+ }
+ .school{
+ margin-top:12px;
+ color: #333;
+ font-size: 16px;
+ height: 22px;
+ line-height: 22px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ max-width:100%;
+ }
+ }
+}
+// coderDepot
+.Panels{
+ max-width: 1200px;
+ margin: 0 auto;
+ .panelmenu{
+ padding-top:30px;
+ .depotBtn{
+ .mr-5{
+ margin-right: -5px;
+ }
+ .ant-btn{
+ height: 36px;
+ line-height: 34px;
+ width: 83px;
+ text-align: center;
+ padding:0px ;
+ font-weight: 500;
+ font-size: 14px;
+ }
+ .ant-btn-default{
+ color: #333;
+ border-color: #d0d0d0;
+ &:hover{
+ background: #F3F4F6;
+ }
+ }
+ .ant-btn-primary{
+ color: #fff;
+ background-color: #2A61FF;
+ }
+ }
+ }
+ .addOptionBtn{
+ height: 32px;
+ line-height: 30px;
+ display: flex;
+ border:1px solid #d9d9d9;
+ border-radius: 2px;
+ a{
+ padding:0px 13px;
+ color: rgba(0, 0, 0, 0.65);
+ cursor: pointer;
+ }
+ & > a:first-child{
+ border-right: 1px solid #d9d9d9;
+ }
+ & > a:last-child{
+ border-right: none;
+ }
+ }
+ .infoCount{
+ display: inline-block;
+ width: 24px;
+ text-align: center;
+ height: 24px;
+ line-height: 24px;
+ background-color:rgba(153, 153, 153, 0.13);;
+ color:#666;
+ border-radius: 12px;
+ margin-left: 6px;
+ font-size: 12px;
+ }
+ .attrPerson{
+ padding-top: 12px;
+ display: flex;
+ flex-wrap: wrap;
+ padding-bottom: 2px;
+ a{
+ margin: 0px 17px 0px 0px;
+ img{
+ border-radius: 50%;
+ width: 40px;
+ height: 40px;
+ }
+ &:nth-child(6){
+ margin-right: 0px;
+ }
+ }
+ }
+ .progress{
+ display: flex;
+ border-radius: 10px;
+ height: 7px;
+ margin-top: 12px;
+ span{
+ &:first-child{
+ border-radius: 10px 0px 0px 10px;
+ }
+ &:last-child{
+ border-radius: 0px 10px 10px 0px;
+ }
+ }
+ }
+ .progresstip{
+ margin-top: 15px;
+ flex-wrap: wrap;
+ i.zero{
+ position: absolute;
+ display: block;
+ border-radius: 50%;
+ height: 8px;
+ width: 8px;
+ left: 0px;
+ top:10px
+ }
+ &>span{
+ padding-left: 15px;
+ position: relative;
+ min-width: 33.5%;
+ font-size: 12px;
+ font-weight: 400;
+ color: #666;
+ span{
+ &:last-child{
+ margin-left: 5px;
+ }
+ }
+ }
+ }
+ .listtable{
+ margin-top: 20px;
+ .listtablehead{
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ border-bottom: 1px solid #d9d9d9;
+ padding:13px 20px;
+ border-radius: 4px 4px 0px 0px;
+ border: 1px solid rgba(42, 97, 255, 0.23);
+ background-color: #FAFCFF;
+ .ellipsistxt{
+ margin-top: 6px;
+ #ptxt{
+ margin-bottom: 0px;
+ word-break: break-all;
+ overflow: unset;
+ white-space:pre-wrap; /* css3.0 */
+ white-space:-moz-pre-wrap; /* Firefox */
+ white-space:-pre-wrap; /* Opera 4-6 */
+ white-space:-o-pre-wrap; /* Opera 7 */
+ word-wrap:break-word;
+ }
+ margin-left: 13px;
+ line-height:18px;
+ flex:1;
+ width: 0;
+ color: #666;
+ &.hidetxt{
+ height: 18px;
+ overflow: hidden;
+ position: relative;
+ padding-right:8px;
+ // &::after{
+ // position: absolute;
+ // right: 0px;
+ // bottom: 0px;
+ // content:"...";
+ // }
+ }
+ }
+ .ellipsis{
+ margin-left: 8px;
+ cursor: pointer;
+ border-radius: 2px;
+ height: 16px;
+ background: rgba(153, 153, 153, 0.2);
+ border-radius: 2px;
+ padding:0px 4px;
+ height: 14px;
+ line-height: 14px;
+ margin-top: 9px;
+ i{
+ font-size: 15px!important;
+ color: #333;
+ height: 14px;
+ line-height: 14px;
+ }
+ }
+ }
+ .listtablebody{
+ border-radius:0px 0px 4px 4px ;
+ border: 1px solid #D0D0D0;
+ border-top: none;
+ li.listtablepath{
+ a{color: #40a9ff;}
+ p{
+ margin-bottom: 0px!important;
+ }
+ }
+ & > li{
+ height: 44px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1px solid #d9d9d9;
+ padding:0px 20px 0px 24px;
+ &:hover{
+ background-color: #F3F4F6;
+ }
+ & > span:first-child{
+ width: 30%;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+ & > span:nth-child(2){
+ width: 60%;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+ & > span:nth-child(3){
+ width: 10%;
+ text-align: right;
+ }
+ }
+ &> li:last-child{
+ border-bottom: none;
+ }
+ }
+ }
+}
+.drawerBtn{
+ position: fixed;
+ left: -13px;
+ width: 33px;
+ background: #FFFFFF;
+ box-shadow: 0px 0px 8px 3px rgba(0, 0, 0, 0.09);
+ border: 1px solid #666666;
+ border-radius: 0px 12px 12px 0px;
+ height: 70px;
+ top:50%;
+ margin-top: -35px;
+ cursor: pointer;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding-left: 7px;
+ &:hover{
+ box-shadow: 0px 0px 8px 3px rgba(0, 0, 0, 0.09);
+ }
+ span{
+ writing-mode: vertical-lr;
+ color: #333;
+ width: 25px;
+ font-size: 14px;
+ }
+ i{
+ color: #333;
+ height: 14px;
+ line-height: 14px;
+ width: 14px;
+ margin-left: 2px;
+ margin-bottom: 3px;
+ }
+}
+.downMenu{
+ width: 329px;
+ background-color: #fff;
+ box-shadow: 0px 1px 8px 1px rgba(212, 212, 212, 0.5);
+ padding-bottom: 14px;
+ .ant-menu-item{
+ height: 50px;
+ line-height: 50px;
+ }
+}
+
+.catelogue{
+ cursor: pointer;
+ background: #FAFBFC;
+ border-radius: 4px;
+ border: 1px solid #D0D0D0;
+ font-size: 15px;
+ font-weight: normal;
+ margin-right: 12px;
+ padding:0px 10px;
+ height: 30px;
+ line-height: 30px;
+ color: #666!important;
+ display: flex;
+ align-items: center;
+ &:hover{
+ background-color: #F3F4F6;
+ }
+ span{
+ margin-top: 1px;
+ }
+}
+.submoduleStyle{
+ cursor: default;
+ i{
+ cursor: default;
+ }
+ &:hover{
+ color: #05101a;
+ }
+}
+.pinfos{
+ i,a{color: #666;}
+ &:hover i,&:hover a{
+ color: #2A61FF;
+ }
+}
+.graph{
+ flex:1;
+ margin:0px 12px;
+ .ant-typography{
+ white-space: pre-wrap;
+ margin-bottom: 0px;
+ }
+}
+.ant-anchor-wrapper{
+ padding-left: 2px;
+ .ant-anchor-ink::before{
+ background-color: #fff;
+ }
}
\ No newline at end of file
diff --git a/src/forge/Main/IndexItem.js b/src/forge/Main/IndexItem.js
index 87f336b1..4f9740c1 100644
--- a/src/forge/Main/IndexItem.js
+++ b/src/forge/Main/IndexItem.js
@@ -1,10 +1,11 @@
import React, { Component } from 'react';
import { Tooltip } from 'antd';
-import { getImageUrl , getImage } from 'educoder';
+import { getImageUrl } from 'educoder';
+import { AlignCenter } from '../Component/layout';
import { Link } from 'react-router-dom';
import '../css/index.scss';
import Nodata from '../Nodata';
-import './list.css';
+import './list.scss';
import img_parise from '../Images/parise.png';
class IndexItem extends Component {
@@ -16,65 +17,75 @@ class IndexItem extends Component {
}
render() {
const { projects } = this.props;
- const renderList = (
- projects && projects.length > 0 ? projects.map((item, key) => {
- return (
-
- {
- item.platform === "educoder" ?
-
-
-
- :
-
-
-
- }
-
-
-
- {item.author.name}/{item.name}
- {
- item.forked_from_project_id ?
-
-
-
- : ""
- }
- {
- item.type && item.type !== 0 ?
- item.type === 2 ?
-
-
- :
-
-
- :""
- }
+ return (
+
+ { projects && projects.length > 0 ? projects.map((item, key) => {
+ return (
+
+ {
+ item.platform === "educoder" ?
+
+
+
+ :
+
+
-
-
赞 {item.praises_count}
- fork {item.forked_count}
-
-
- {item.description}
+ }
+
+
+
+
+ {item.author.name}/{item.name}
+
+ { !item.is_public && 私有 }
+ {
+ item.forked_from_project_id ?
+
+
+
+ : ""
+ }
+ {
+ item.type && item.type === 2 ?
+
+
+ :""
+ }
+ {
+ item.type && item.type === 1 ?
+
+
+ :""
+ }
+
+
+ {
+ item.praises_count && item.praises_count>0 ?
+
+
赞 {item.praises_count}
+ :""
+ }
+ {
+ item.forked_count && item.forked_count>0 ?
+
+ fork {item.forked_count}
+ :""
+ }
+
+
+ {item.description}
-
-
- {/* {item.visits} */}
- {/* {item.category && item.category.id && {item.category.name}} */}
- {item.last_update_time ? {item.time_ago} : ""}
- {item.language && item.language.id ? {item.language.name} : ""}
-
+
+
+ {item.last_update_time ? {item.time_ago} : ""}
+ {item.language && item.language.id ? {item.language.name} : ""}
+
+
-
- )
- }) :
- )
- return (
-
- {renderList}
+ )
+ }) : }
)
}
diff --git a/src/forge/Main/NullData.js b/src/forge/Main/NullData.js
index a550b5bc..1621d657 100644
--- a/src/forge/Main/NullData.js
+++ b/src/forge/Main/NullData.js
@@ -1,5 +1,5 @@
import React, { Component } from 'react';
-import "../Branch/branch.css"
+import "../Branch/branch.scss"
diff --git a/src/forge/Main/list.css b/src/forge/Main/list.scss
similarity index 80%
rename from src/forge/Main/list.css
rename to src/forge/Main/list.scss
index 272583d1..b4a966b2 100644
--- a/src/forge/Main/list.css
+++ b/src/forge/Main/list.scss
@@ -18,10 +18,17 @@
box-sizing: border-box;
margin-bottom: 20px;
}
+.list-left > div{
+ border:1px solid #eee;
+}
+.list-left > div.bgcF{
+ border:none;
+}
.list-right{
width:74%;
background: #fff;
padding:10px;
+ border:1px solid #eee;
}
@@ -84,6 +91,7 @@
display: flex;
border-bottom:1px solid rgba(238,238,238,1);
padding:22px 0px;
+ justify-content: flex-start;
}
.boxShandow{
box-shadow:0px 2px 20px 10px rgba(0,0,0,0.03);
@@ -93,6 +101,7 @@
height: 60px;
border-radius: 50%;
margin-right: 22px;
+ margin-top: 8px;
}
.p-r-Infos{
flex: 1;
@@ -101,6 +110,7 @@
.p-r-name{
display: flex;
justify-content: space-between;
+ align-items: center;
}
.p-r-name > p{
flex: 1;
@@ -208,73 +218,93 @@
}
/* -----------详情------------ */
.detailHeader-wrapper{
- background-color:#FAFBFC;
- /* background: url(../Images/forgeBanner.jpg) no-repeat center; */
- /* background-size:cover; */
+ background-color:#FBFCFF;
+ border-bottom:1px solid #e2e2e2;
}
.headerMenu-wrapper{
- font-size: 16px;
display: flex;
flex-direction: row;
-}
-.headerMenu-wrapper li{
- position: relative;
- text-align: center;
- height: 40px;
- line-height: 28px;
- margin-right: 40px;
-}
-.headerMenu-wrapper li a{
- color: #666;
-}
-.headerMenu-wrapper li a > img{
- margin-right: 8px;
-}
-.headerMenu-wrapper li a > span.num{
- height: 28px;
- line-height: 29px;
- margin-left: 8px;
- font-size: 12px;
- color: #2878FF;
- float: right;
-}
-.headerMenu-wrapper li.active::after{
- position: absolute;
- bottom:0px;
- height:2px;
- background-color: #5091FF;
- content:'';
- left: 0px;
- width:100%;
+ cursor: pointer;
+ li{
+ font-size: 14px;
+ position: relative;
+ text-align: center;
+ height: 40px;
+ line-height: 28px;
+ padding:0px 20px;
+ & > a{
+ color: #666;
+ &> img{
+ margin-right: 8px;
+ }
+ &> span.num{
+ line-height: 24px;
+ margin-left: 5px;
+ margin-top: 2px;
+ font-size: 12px;
+ float: right;
+ color: #666!important;
+ background-color: rgba(153, 153, 153, 0.13);;
+ border-radius: 50%;
+ width: 24px;
+ height: 24px;
+ }
+ }
+ &.active a,&.active a i{
+ color: #2A61FF!important;
+ }
+ &.active::after,&:hover::after{
+ position: absolute;
+ bottom:0px;
+ height:2px;
+ background-color: #2A61FF;
+ content:'';
+ left: 0px;
+ width:100%;
+ }
+ &:hover::after{
+ background-color: rgba(153, 153, 153, 0.2);;
+ }
+ }
}
.detail_tag_btn{
- height:26px;
- line-height: 26px;
+ height:34px;
+ line-height: 32px;
border-radius:5px;
- border:1px solid #f1f1f1;
+ border:1px solid #D0D0D0;
display: flex;
align-items: center;
- margin-left: 30px
+ margin-left: 10px;
+ padding:0px;
+ background-color:#FAFBFC;
+ box-shadow: none;
+ &:hover{
+ background-color: #F3F4F6;
+ }
+ .detail_tag_btn_name{
+ padding:0px 18px;
+ min-width: 82px;
+ text-align: center;
+ &:hover>span{
+ color: #333!important;
+ }
+ img{
+ margin-right: 10px;
+ }
+ }
+ .detail_tag_btn_count{
+ width: 42px;
+ text-align: center;
+ background: #fff;
+ border-radius: 0px 4px 4px 0px;
+ height:100%;
+ border-left: 1px solid #D0D0D0;
+ }
}
.ant-tooltip {
max-width: fit-content!important;
}
-.detail_tag_btn_name{
- padding:0px 10px;
- color: #666!important;
-}
-.detail_tag_btn_name img{
- margin-right: 10px;
-}
-.detail_tag_btn_count{
- padding:0px 10px;
- background: #fff;
- border-radius: 0px 4px 4px 0px;
- font-size: 12px;
- height:100%;
-}
.files-md{
- border:1px solid #eee;
padding:20px;
}
/* 详情-代码 */
@@ -324,6 +354,7 @@
.gitAddressClone{
+ margin:0px 20px 14px 20px!important;
display: flex;
height: 40px;
align-items: center;
@@ -424,18 +455,11 @@
max-width: 100%;
}
/* 分支 */
-.branchTable{
- border:1px solid #f7f7f7;
- border-radius: 4px;
-}
.branchTitle{
- padding:12px 10px;
+ padding:8px 10px;
color: #333;
font-size: 16px;
- background:rgba(241,248,255,1);
-}
-.branchUl{
- padding:0px 30px;
+ border-bottom: 1px solid #d9d9d9;
}
.branchUl li{
display: flex;
@@ -494,7 +518,7 @@
}
.addFile a{
display: block;
- background-color: rgb(76, 172, 255,0.8);
+ background-color: rgba(76, 172, 255,0.8);
color: #fff;
cursor: pointer;
height: 32px;
@@ -509,7 +533,7 @@
border-left: 1px solid rgba(247, 247, 247, 0.3);
}
.addFile a:active{
- background-color: rgb(76, 172, 255,1);
+ background-color: rgba(76, 172, 255,1);
}
@@ -548,22 +572,42 @@
}
.commonBox{
border:1px solid #ddd;
- margin-top: 25px;
+ margin-top: 30px;
+ border-radius: 4px;
}
.commonBox .commonBox-title{
- padding:0px 15px;
+ padding:0px 20px;
box-sizing: border-box;
font-size: 16px;
- background: #F1F8FF;
+ background: #FAFBFC;/* F1F8FF */
font-weight: bold;
- height: 50px;
- line-height: 50px;
- border-bottom: 1px solid #ddd;
+ height: 45px;
+ line-height: 45px;
+ border-bottom: 1px solid #d9d9d9;
+ border-radius: 4px 4px 0px 0px;
+}
+.readBox{
+ border:none;
+ &.commonBox .commonBox-info{
+ border:1px solid #D0D0D0;
+ border-top: none;
+ border-radius: 0px 0px 4px 4px;
+ padding:20px 38px;
+ }
+}
+.commonBox .commonBox-title.boxTitle{
+ display: flex;
+ justify-content: space-between;
+ height: 65px;
+ line-height: 65px;
+ background: #FAFCFF;
+ border-radius: 4px 4px 0px 0px;
+ border: 1px solid rgba(42, 97, 255, 0.23);
}
.synchronism{
display: block;
- height: 26px;
- line-height: 26px;
+ height: 34px;
+ line-height: 34px;
padding:0px 15px;
color: #fff!important;
background-color: #28BD6C;
@@ -572,10 +616,16 @@
.files_info{
cursor: pointer;
}
-.commonBox .commonBox-info{
- padding:20px 15px;
+.commonBox {
+ .commonBox-info{
+ padding:20px 15px;
+ }
+}
+.commonBox-title-read{
+ vertical-align: middle;
+ color: #666;
+ font-size: 14px;
}
-.commonBox-title-read{vertical-align: middle;}
@media screen and (max-width: 370px){
.p-r-tags,.p-r-btn{
@@ -616,9 +666,7 @@
.item:last-child{
border-bottom:none;
}
-.gitAddressClone{
- margin: 0 !important;
-}
+
.item_title small{
font-weight: 400;
margin-left: 10px;
@@ -665,6 +713,7 @@ a.color-grey-ccc:hover{
.commitList{
padding:0px 30px;
+ min-height: 400px;
}
.commitList > div{
border-bottom: 1px solid #EEEEEE;
@@ -720,4 +769,13 @@ a.color-grey-ccc:hover{
text-align: center;
display: flex;
justify-content: center;
+}
+.depotNum{
+ color: #666!important;
+ span:last-child{
+ color: #333;
+ }
+ &:hover span:last-child{
+ color: #2A61FF;
+ }
}
\ No newline at end of file
diff --git a/src/forge/Main/sub/Contribute.jsx b/src/forge/Main/sub/Contribute.jsx
new file mode 100644
index 00000000..f65b4524
--- /dev/null
+++ b/src/forge/Main/sub/Contribute.jsx
@@ -0,0 +1,80 @@
+import React, { useEffect, useState } from 'react';
+import { WhiteBack , AlignCenter } from '../../Component/layout';
+import "./sub.scss";
+import axios from 'axios';
+import { Pagination , Spin } from 'antd';
+import NoData from '../../Nodata';
+import { getImageUrl } from 'educoder';
+import { Link } from 'react-router-dom';
+
+function Contribute(props){
+ const [ list , setList ] = useState(undefined);
+ const [ page , setPage ] = useState(1);
+ const [ total , setTotal ] = useState(0);
+ const [ isSpin , setIsSpin ] = useState(true);
+
+ const owner = props.match.params.owner;
+ const projectsId = props.match.params.projectsId;
+ const LIMIT = 20;
+ useEffect(()=>{
+ if(owner && projectsId){
+ getData();
+ }
+ },[owner,projectsId,page]);
+
+ function getData(){
+ setIsSpin(true);
+ const url = `/${owner}/${projectsId}/contributors.json`;
+ axios.get(url,{
+ params:{
+ limit:LIMIT,page,
+ }
+ }).then(result=>{
+ if(result){
+ setList(result.data.contributors);
+ setTotal(result.data.total_count);
+ setIsSpin(false);
+ }
+ }).catch(error=>{})
+ }
+
+ return(
+
+
+
+ 贡献者列表
+ {
+ list && list.length > 0 ?
+
+ {
+ list.map((item,key)=>{
+ return(
+
+
+
+ {item.name}
+ 提交{item.contributions}次
+
+
+ )
+ })
+ }
+
+ :""
+ }
+ {
+ list && list.length === 0 ? :""
+ }
+ {
+ total > LIMIT ?
+
+ {setPage(p)}} current={page} total={total}/>
+
+ :""
+ }
+
+
+
+ )
+}
+export default Contribute;
\ No newline at end of file
diff --git a/src/forge/Main/sub/DetailBanner.jsx b/src/forge/Main/sub/DetailBanner.jsx
new file mode 100644
index 00000000..1a6bd4f6
--- /dev/null
+++ b/src/forge/Main/sub/DetailBanner.jsx
@@ -0,0 +1,137 @@
+import React, { useEffect, useState } from 'react';
+import { Skeleton , Tooltip} from 'antd';
+import { Link } from 'react-router-dom';
+import { numFormat } from 'educoder';
+
+function DetailBanner({ history,list , owner , projectsId , isManager , url , pathname , state , urlFlag , projectDetail , platform ,open_devops }){
+ const [ menuName , setMenuName ] = useState(undefined);
+ useEffect(()=>{
+ if(list){
+ // 没有资源库banner但是通过连接进资源库页面时
+ if(pathname && pathname==="source"){
+ let a = list.filter(item=>item.menu_name === "resources");
+ if(a && a.length === 0){
+ history.push(`/projects/${owner}/${projectsId}`);
+ }
+ }
+ setMenuName(list);
+ }
+ },[list]);
+ return(
+
+ {
+ menuName && projectDetail ?
+
+ {
+ Array.isArray(menuName)&& menuName.map((item,key)=>{
+ return(
+
+ {
+ item.menu_name === "home" &&
+ -
+
+
+ 主页
+
+
+ }
+ {
+ item.menu_name === "code" &&
+ -
+
+
+ 代码库
+
+
+ }
+ {
+ item.menu_name === "issues" &&
+ -
+
+
+
+ 易修
+ {projectDetail && projectDetail.issues_count ? {numFormat(projectDetail.issues_count)} : ""}
+
+
+
+ }
+ {
+ item.menu_name === "pulls" && projectDetail && parseInt(projectDetail.type) !== 2 && platform ?
+ -
+
+
+ 合并请求
+ {projectDetail && projectDetail.pull_requests_count ? {numFormat(projectDetail.pull_requests_count)} : ""}
+
+
:""
+ }
+ {
+ item.menu_name === "wiki" &&
+ -
+
+
+ Wiki
+
+
+ }
+ {
+ item.menu_name === "devops" && platform ?
+ -
+
+ 工作流(beta版)
+ {projectDetail && projectDetail.ops_count ? {numFormat(projectDetail.ops_count)} : ""}
+
+
+ :""
+ }
+ {
+ item.menu_name === "resources" &&
+ -
+
+
+ 资源库
+ {projectDetail && projectDetail.source_count ? {numFormat(projectDetail.source_count)} :""}
+
+
+ }
+ {
+ item.menu_name === "versions" &&
+ -
+
+
+ 里程碑
+ {projectDetail && projectDetail.versions_count ? {numFormat(projectDetail.versions_count)} :""}
+
+
+ }
+ {
+ item.menu_name === "activity" &&
+ -
+
+
+ 动态
+
+
+ }
+ {
+ item.menu_name === "setting" &&
+ -
+
+ 0 ? "iconfont icon-cangkushezhiicon color-grey-3 mr5 font-14":"iconfont icon-cangkushezhiicon color-grey-6 font-14 mr5"}>
+ 仓库设置
+
+
+ }
+
+ )
+ })
+ }
+
+ :
+
+ }
+
+ )
+}
+export default DetailBanner;
\ No newline at end of file
diff --git a/src/forge/Main/sub/Invite.jsx b/src/forge/Main/sub/Invite.jsx
new file mode 100644
index 00000000..e621bd6d
--- /dev/null
+++ b/src/forge/Main/sub/Invite.jsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { Tooltip , message } from 'antd';
+import './sub.scss';
+
+function Invite({code,className}) {
+
+ function jsCopy(id) {
+ const copyEle = document.querySelector(id); // 获取要复制的节点
+ const range = document.createRange(); // 创造range
+ window.getSelection().removeAllRanges(); //清除页面中已有的selection
+ range.selectNode(copyEle); // 选中需要复制的节点
+ window.getSelection().addRange(range); // 执行选中元素
+ document.execCommand("Copy"); // 执行copy操作
+ message.success('复制成功');
+ }
+ return(
+
+ 邀请码
+
+ {code}
+ 可以通过邀请码邀请成员加入项目
点击复制邀请码。} placement={"bottom"}>
+ jsCopy("#devitecode")}>
+
+
+
+ )
+}
+export default Invite;
\ No newline at end of file
diff --git a/src/forge/Main/sub/ReadmeCatelogue.jsx b/src/forge/Main/sub/ReadmeCatelogue.jsx
new file mode 100644
index 00000000..d1e018bb
--- /dev/null
+++ b/src/forge/Main/sub/ReadmeCatelogue.jsx
@@ -0,0 +1,57 @@
+import React , { useState , useEffect } from 'react';
+import { Anchor , Input } from 'antd';
+import './sub.scss';
+import { Base64 } from 'js-base64';
+
+const { Link } = Anchor;
+
+function ReadmeCatelogue({ menuList , hash }) {
+ const [ goHref , setGoHref ] = useState("");
+ const [ value , setValue ] = useState("");
+ const [ menu , setMenu] = useState(menuList);
+
+
+ function onChange(link){
+ setGoHref(link);
+ };
+
+ function changeValue(e) {
+ setValue(e.target.value);
+ if(e.target.value){
+ let m = menuList.filter(i=>i.text.indexOf(e.target.value)>-1);
+ setMenu(m);
+ }else{
+ setMenu(menuList);
+ }
+ }
+ return(
+
+
+ }/>
+
+ {
+ menu && menu.length>0?
+
+
+ {
+ menu.map((item,key)=>{
+ return(
+
+
+
+ )
+ })
+ }
+
+
+ :""
+ }
+
+
+ )
+}
+export default ReadmeCatelogue;
\ No newline at end of file
diff --git a/src/forge/Main/sub/UpdateDescModal.jsx b/src/forge/Main/sub/UpdateDescModal.jsx
new file mode 100644
index 00000000..5039123a
--- /dev/null
+++ b/src/forge/Main/sub/UpdateDescModal.jsx
@@ -0,0 +1,63 @@
+import React , { forwardRef, useEffect } from 'react';
+import {Form , Modal , Input } from 'antd';
+import "./sub.scss";
+const { TextArea } = Input;
+function UpdateDescModal({form , visible , onCancel , onOk,desc,website,lesson_url}){
+ const { getFieldDecorator, validateFields , setFieldsValue } = form;
+
+ useEffect(()=>{
+ if(desc || website){
+ setFieldsValue({
+ website,desc,lesson_url
+ })
+ }
+ },[desc,website])
+
+ function onSure(){
+ validateFields((err,values)=>{
+ if(!err){
+ onCancel();
+ onOk(values.desc,values.website,values.lesson_url)
+ }
+ })
+ }
+ return(
+
+
+ {getFieldDecorator("desc",{
+ rules:[]
+ })(
+
+
+ {getFieldDecorator("website",{
+ rules:[]
+ })(
+
+ )}
+
+
+ {getFieldDecorator("lesson_url",{
+ rules:[]
+ })(
+
+ )}
+
+
+
+ )
+}
+export default Form.create()(forwardRef(UpdateDescModal));
\ No newline at end of file
diff --git a/src/forge/Main/sub/sub.scss b/src/forge/Main/sub/sub.scss
new file mode 100644
index 00000000..4e6a3d8a
--- /dev/null
+++ b/src/forge/Main/sub/sub.scss
@@ -0,0 +1,67 @@
+.boxPanel{
+ width: 1200px;
+ margin:20px auto;
+ border-radius: 4px;
+ border:1px solid #eee;
+ min-height: 500px;
+ .contrbuteList{
+ display: flex;
+ flex-wrap: wrap;
+ padding:20px;
+ & > div{
+ width: 20%;
+ }
+ align-items: flex-start;
+ }
+}
+.descmodal{
+ .ant-row.ant-form-item{
+ margin-bottom: 10px;
+ }
+ .ant-col.ant-form-item-label{
+ height: 20px;
+ line-height: 20px;
+ }
+}
+
+.menuslist{
+ z-index: 100;
+ width: 297px;
+ background: #FFFFFF;
+ box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5);
+ border-radius: 4px;
+ .searchBox{
+ padding:15px;
+ border-bottom: 1px solid #eee;
+ }
+ .ant-anchor-wrapper{
+ margin-left: 0px;
+ padding:5px 15px;
+ max-height: 255px!important;
+ .items{
+ border-radius: 4px;
+ margin-bottom: 5px;
+ cursor: pointer;
+ .ant-anchor-link-title{
+ color: #333333!important;
+ }
+ &:hover{
+ background-color: #F3F4F6;
+ }
+ &.active{
+ background-color: #2A61FF;
+ .ant-anchor-link-title{
+ color: #fff!important;
+ }
+ }
+ }
+ .ant-anchor-link{
+ padding:0px;
+ height: 30px;
+ line-height: 30px;
+ }
+ .ant-anchor-ink::before{
+ background-color: #fff;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/forge/Merge/Commits.jsx b/src/forge/Merge/Commits.jsx
index a7d12073..37c254cc 100644
--- a/src/forge/Merge/Commits.jsx
+++ b/src/forge/Merge/Commits.jsx
@@ -22,7 +22,7 @@ function Commits({ commits , projectsId , owner }){
浏览代码
- :提交于{item.time_from_now}
+ :提交于{item.time_from_now}
diff --git a/src/forge/Merge/Files.jsx b/src/forge/Merge/Files.jsx
index 08983266..40e617c2 100644
--- a/src/forge/Merge/Files.jsx
+++ b/src/forge/Merge/Files.jsx
@@ -47,7 +47,7 @@ function Files({data,history,owner,projectsId}){
{item.name}
-
+
+{item.addition}
-{item.deletion}
diff --git a/src/forge/Merge/Index.scss b/src/forge/Merge/Index.scss
new file mode 100644
index 00000000..936b868f
--- /dev/null
+++ b/src/forge/Merge/Index.scss
@@ -0,0 +1,21 @@
+.i_open{
+ color: #28BD6C!important;
+}
+.i_merged{
+ color: #4C9ED3!important;
+}
+.i_closed{
+ color: #FA6400!important;
+}
+.pr_tags_open{
+ border:1px solid #28BD6C;
+ color: #28BD6C;
+}
+.pr_tags_merged{
+ border:1px solid #4C9ED3;
+ color: #4C9ED3;
+}
+.pr_tags_closed{
+ border:1px solid #FA6400;
+ color: #FA6400;
+}
\ No newline at end of file
diff --git a/src/forge/Merge/MergeItem.js b/src/forge/Merge/MergeItem.js
index 77a8a62a..32f3f811 100644
--- a/src/forge/Merge/MergeItem.js
+++ b/src/forge/Merge/MergeItem.js
@@ -1,9 +1,16 @@
import React, { Component } from "react";
import { Link } from "react-router-dom";
-import { Popconfirm, Tag } from "antd";
+import { Tag } from "antd";
+import { AlignCenter } from '../Component/layout';
import { getImageUrl } from "educoder";
import "./merge.css";
+function turnbar(str){
+ if(str && str.length>0 && str.indexOf("/")>-1){
+ return str.replaceAll('/','%2F');
+ }
+ return str;
+}
class MergeItem extends Component {
constructor(props) {
super(props);
@@ -42,16 +49,18 @@ class MergeItem extends Component {
};
render() {
- const { issues, project_name, project_author_name } = this.props;
+ const { issues, project_name, project_author_name , user_admin_or_member} = this.props;
const { projectsId , owner } = this.props.match.params;
const { current_user } = this.props;
const renderList = () => {
if (issues && issues.length > 0) {
return issues.map((item, key) => {
+ let status = item.pull_request_staus;
return (
+
{item.name}
-
- {item.pull_request_staus === "merged"
+
+ {status === "merged"
? "已合并"
- : item.pull_request_staus === "closed"
+ : status === "closed"
? "已拒绝"
: "开启的"}
@@ -74,13 +83,13 @@ class MergeItem extends Component {
>
-
+
{item.pr_time}
-
-
- {item.is_original
- ? item.fork_project_user
- : project_author_name}
- :{item.pull_request_head}
-
-
-
-
-
-
-
- {/* {item.is_fork ? item.pull_request_base : `${item.author_name}:${item.pull_request_base}`} */}
- {project_author_name}:{item.pull_request_base}
-
-
+ {
+ item.pull_request_head &&
+
+
+ {item.is_original
+ ? item.fork_project_user
+ : project_author_name}
+ :{item.pull_request_head}
+
+
+ }
+ {
+ item.pull_request_base &&
+
+
+
+ }
+ {
+ item.pull_request_base &&
+
+
+ {/* {item.is_fork ? item.pull_request_base : `${item.author_name}:${item.pull_request_base}`} */}
+ {project_author_name}:{item.pull_request_base}
+
+
+ }
+
-
+
diff --git a/src/forge/Merge/MergeSubmit.js b/src/forge/Merge/MergeSubmit.js
index 27156f0e..8f2275d8 100644
--- a/src/forge/Merge/MergeSubmit.js
+++ b/src/forge/Merge/MergeSubmit.js
@@ -101,7 +101,7 @@ class MergeSubmit extends Component{
render: (text,item) => (
-
+
diff --git a/src/forge/Merge/MessageCount.js b/src/forge/Merge/MessageCount.js
index 87f19d38..f3e58657 100644
--- a/src/forge/Merge/MessageCount.js
+++ b/src/forge/Merge/MessageCount.js
@@ -24,6 +24,12 @@ import MergeFooter from "./merge_footer";
const Option = Select.Option;
const TextArea = Input.TextArea;
+function turnbar(str){
+ if(str && str.length>0 && str.indexOf("/")>-1){
+ return str.replaceAll('/','%2F');
+ }
+ return str;
+}
class MessageCount extends Component {
constructor(props) {
super(props);
@@ -40,6 +46,8 @@ class MessageCount extends Component {
SpinMerge: false,
edit_spin: false,
pr_status: undefined,
+ pull_request:undefined,
+ conflict_files:[],
copyVisible:false,
};
@@ -69,11 +77,13 @@ class MessageCount extends Component {
axios
.get(url)
.then((result) => {
- if (result) {
+ if (result && result.data) {
this.setState({
data: result.data,
SpinFlag: false,
- pr_status: result.data && result.data.pull_request && result.data.pull_request.status,
+ pr_status: result.data.pull_request && result.data.pull_request.status,
+ pull_request:result.data.pull_request,
+ conflict_files:result.data.conflict_files
});
} else {
this.setState({ SpinFlag: false });
@@ -100,6 +110,8 @@ class MessageCount extends Component {
isSpin: false,
pr_status: 2,
});
+ const { getDetail } = this.props;
+ getDetail && getDetail();
} else {
this.setState({
isSpin: false,
@@ -136,6 +148,8 @@ class MessageCount extends Component {
SpinMerge: false,
pr_status: 1,
});
+ const { getDetail } = this.props;
+ getDetail && getDetail();
} else {
this.setState({ SpinMerge: false });
}
@@ -209,7 +223,7 @@ class MessageCount extends Component {
};
commentCtx = (v) => {
- return ;
+ return ;
};
setCopyVisible=(e)=>{
@@ -239,6 +253,49 @@ class MessageCount extends Component {
)
}
+ // 点击按钮复制功能
+ jsCopy = () => {
+ const copyEle = document.querySelector('#descContent') // 获取要复制的节点
+ const range = document.createRange(); // 创造range
+ window.getSelection().removeAllRanges(); //清除页面中已有的selection
+ range.selectNode(copyEle); // 选中需要复制的节点
+ window.getSelection().addRange(range); // 执行选中元素
+ document.execCommand("Copy"); // 执行copy操作
+ }
+
+ mergeabledMes=()=>{
+ return(
+
+ 该分支存在冲突,无法自动合并,你可以尝试通过如下命令手动合并
+ this.jsCopy()}>
+
+ )
+ }
+ mergeabledDesc=(base,head,conflict_files)=>{
+ return(
+
+
+ - git fetch origin
+ - git checkout -b {`${base}`} origin/{`${base}`}
+ - git merge {`${head}`}
+
+ {
+ conflict_files && conflict_files.length>0 &&
+
+ 如下文件有代码冲突:
+
+ {
+ conflict_files.map((i,k)=>{
+ return
{i}
+ })
+ }
+
+
+ }
+
+ )
+ }
+
render() {
const { projectsId, mergeId , owner } = this.props.match.params;
@@ -249,7 +306,9 @@ class MessageCount extends Component {
isSpin,
ismesrge,
SpinFlag,
- copyVisible
+ copyVisible,
+ pull_request,
+ conflict_files
} = this.state;
const { current_user, projectDetail } = this.props;
const menu = (
@@ -268,9 +327,11 @@ class MessageCount extends Component {
);
-
+ const permission = projectDetail && (projectDetail.permission === "Admin" || projectDetail.permission === "Owner" || projectDetail.permission === "Manager");
+ const userLogin = current_user && current_user.login;
+ const operate = userLogin && projectDetail && pr_status === 0 && permission;
return (
-
+
{data ? (
@@ -300,10 +361,10 @@ class MessageCount extends Component {
- {data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}:{data.pull_request.head}
+ {data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}: {turnbar(data.pull_request && data.pull_request.head)}
@@ -315,10 +376,9 @@ class MessageCount extends Component {
- {/* {data.pull_request.is_fork ? data.pull_request.base : `${data.pull_request.pull_request_user}:${data.pull_request.base}`} */}
{data.issue.project_author_name}:{data.pull_request.base}
@@ -326,26 +386,14 @@ class MessageCount extends Component {
}
-
-
+
由
-
+
{data.issue.author_name}
@@ -395,15 +443,7 @@ class MessageCount extends Component {
- {/*
- this.setCopyVisible(e)}>
- 复制
-
- 下载为
- */}
- {current_user && projectDetail &&
- pr_status === 0 &&
- projectDetail.permission !=="Reporter" && (
+ {operate && (