Merge pull request '修改cloudcloudIDE加载时的logo,升级插件版本' (#432) from tongChong/forgeplus-react:feature_IDE into gitlink_server
|
@ -83,6 +83,11 @@ module.exports = {
|
|||
devtoolModuleFilenameTemplate: (info) =>
|
||||
path.resolve(info.absoluteResourcePath).replace(/\\/g, "/"),
|
||||
},
|
||||
externals: {
|
||||
"react": "React",
|
||||
"react-dom": "ReactDOM",
|
||||
"alex": "Alex",
|
||||
},
|
||||
resolve: {
|
||||
// This allows you to set a fallback for where Webpack should look for modules.
|
||||
// We placed these paths second because we want `node_modules` to "win"
|
||||
|
|
|
@ -71,6 +71,11 @@ module.exports = {
|
|||
.relative(paths.appSrc, info.absoluteResourcePath)
|
||||
.replace(/\\/g, "/"),
|
||||
},
|
||||
externals: {
|
||||
'alex': 'Alex',
|
||||
"react": "React",
|
||||
"react-dom": "ReactDOM",
|
||||
},
|
||||
resolve: {
|
||||
// This allows you to set a fallback for where Webpack should look for modules.
|
||||
// We placed these paths second because we want `node_modules` to "win"
|
||||
|
|
|
@ -4,6 +4,15 @@
|
|||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@ahooksjs/use-request": {
|
||||
"version": "2.8.15",
|
||||
"resolved": "https://registry.npmjs.org/@ahooksjs/use-request/-/use-request-2.8.15.tgz",
|
||||
"integrity": "sha512-xhVaM4fyIiAMdVFuuU5i3CFUdFa/IblF+fvITVMFaUEO3w/V5tVCAF6WIA3T03n1/RPuzRkA7Ao1PFtSGtGelw==",
|
||||
"requires": {
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.throttle": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"@ant-design/colors": {
|
||||
"version": "3.2.2",
|
||||
"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",
|
||||
|
@ -415,6 +424,11 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.0.0.tgz",
|
||||
"integrity": "sha512-q95SP4FdkmF0CwO0F2q0H6ZgudsApaY/yCtAQNRn1gduef5fGpyEphzy0YCq/N0UFvDSnLg5V8jFK/YGXlDiCw=="
|
||||
},
|
||||
"@types/js-cookie": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.7.tgz",
|
||||
"integrity": "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA=="
|
||||
},
|
||||
"@types/jss": {
|
||||
"version": "9.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/jss/-/jss-9.5.8.tgz",
|
||||
|
@ -817,6 +831,23 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"ahooks": {
|
||||
"version": "2.10.14",
|
||||
"resolved": "https://registry.npmjs.org/ahooks/-/ahooks-2.10.14.tgz",
|
||||
"integrity": "sha512-axWa7VoAgu7bxA56dDl0CXW4rvaQmDBiov/d3tAy0x1YNYywYMKokL8TdLgJ5zO/oXGiWmG7BxlGOQGkqE/zkQ==",
|
||||
"requires": {
|
||||
"@ahooksjs/use-request": "^2.8.14",
|
||||
"@types/js-cookie": "^2.2.6",
|
||||
"dayjs": "^1.9.1",
|
||||
"intersection-observer": "^0.7.0",
|
||||
"js-cookie": "^2.2.1",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"screenfull": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.12.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
|
||||
|
@ -4516,6 +4547,11 @@
|
|||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.12.0.tgz",
|
||||
"integrity": "sha512-qJgn99xxKnFgB1qL4jpxU7Q2t0LOn1p8KMIveef3UZD7kqjT3tpFNNdXJelEHhE+rUgffriXriw/sOSU+cS1Hw=="
|
||||
},
|
||||
"dayjs": {
|
||||
"version": "1.11.3",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.3.tgz",
|
||||
"integrity": "sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
|
@ -4854,7 +4890,7 @@
|
|||
},
|
||||
"dom-closest": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-closest/-/dom-closest-0.2.0.tgz",
|
||||
"resolved": "https://registry.npm.taobao.org/dom-closest/download/dom-closest-0.2.0.tgz",
|
||||
"integrity": "sha1-69n5HRvyLo1vR3h2u80+yQIWwM8=",
|
||||
"requires": {
|
||||
"dom-matches": ">=1.0.1"
|
||||
|
@ -4898,7 +4934,7 @@
|
|||
},
|
||||
"dom-matches": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-matches/-/dom-matches-2.0.0.tgz",
|
||||
"resolved": "https://registry.npm.taobao.org/dom-matches/download/dom-matches-2.0.0.tgz",
|
||||
"integrity": "sha1-0nKLQWqHUzmA6wibhI0lPPI6dYw="
|
||||
},
|
||||
"dom-scroll-into-view": {
|
||||
|
@ -5150,7 +5186,7 @@
|
|||
},
|
||||
"enquire.js": {
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz",
|
||||
"resolved": "https://registry.npm.taobao.org/enquire.js/download/enquire.js-2.1.6.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fenquire.js%2Fdownload%2Fenquire.js-2.1.6.tgz",
|
||||
"integrity": "sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ="
|
||||
},
|
||||
"entities": {
|
||||
|
@ -5675,7 +5711,7 @@
|
|||
},
|
||||
"eventlistener": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eventlistener/-/eventlistener-0.0.1.tgz",
|
||||
"resolved": "https://registry.npm.taobao.org/eventlistener/download/eventlistener-0.0.1.tgz",
|
||||
"integrity": "sha1-7Suqu4UiJ68rz4iRUscsY8pTLrg="
|
||||
},
|
||||
"events": {
|
||||
|
@ -7209,8 +7245,7 @@
|
|||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"optional": true
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
|
@ -7231,14 +7266,12 @@
|
|||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"optional": true
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
|
@ -7253,20 +7286,17 @@
|
|||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
|
||||
"optional": true
|
||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"optional": true
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
|
||||
"optional": true
|
||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
|
@ -7383,8 +7413,7 @@
|
|||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"optional": true
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
|
@ -7396,7 +7425,6 @@
|
|||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
|
||||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
|
@ -7411,7 +7439,6 @@
|
|||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
|
@ -7419,14 +7446,12 @@
|
|||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"optional": true
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
|
||||
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.0"
|
||||
|
@ -7445,7 +7470,6 @@
|
|||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz",
|
||||
"integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
|
@ -7507,8 +7531,7 @@
|
|||
"npm-normalize-package-bin": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz",
|
||||
"integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==",
|
||||
"optional": true
|
||||
"integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA=="
|
||||
},
|
||||
"npm-packlist": {
|
||||
"version": "1.4.8",
|
||||
|
@ -7536,8 +7559,7 @@
|
|||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
|
||||
"optional": true
|
||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
|
@ -7549,7 +7571,6 @@
|
|||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
|
@ -7627,8 +7648,7 @@
|
|||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"optional": true
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
|
@ -7664,7 +7684,6 @@
|
|||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
||||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
|
@ -7684,7 +7703,6 @@
|
|||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
|
@ -7728,14 +7746,12 @@
|
|||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"optional": true
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
||||
"optional": true
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -8009,7 +8025,7 @@
|
|||
},
|
||||
"hammerjs": {
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
|
||||
"resolved": "https://registry.npm.taobao.org/hammerjs/download/hammerjs-2.0.8.tgz",
|
||||
"integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE="
|
||||
},
|
||||
"handle-thing": {
|
||||
|
@ -8823,7 +8839,7 @@
|
|||
},
|
||||
"image-size": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "http://173.15.15.82:8081/repository/npm-all/image-size/-/image-size-0.5.5.tgz",
|
||||
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
|
||||
"integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==",
|
||||
"optional": true
|
||||
},
|
||||
|
@ -8842,7 +8858,7 @@
|
|||
},
|
||||
"immutable": {
|
||||
"version": "3.7.6",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz",
|
||||
"resolved": "https://registry.npm.taobao.org/immutable/download/immutable-3.7.6.tgz",
|
||||
"integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks="
|
||||
},
|
||||
"import-fresh": {
|
||||
|
@ -9056,6 +9072,11 @@
|
|||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
|
||||
"integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw=="
|
||||
},
|
||||
"intersection-observer": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.7.0.tgz",
|
||||
"integrity": "sha512-Id0Fij0HsB/vKWGeBe9PxeY45ttRiBmhFyyt/geBdDHBYNctMRTE3dC1U3ujzz3lap+hVXlEcVaB56kZP/eEUg=="
|
||||
},
|
||||
"invariant": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
|
@ -9931,6 +9952,11 @@
|
|||
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz",
|
||||
"integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ=="
|
||||
},
|
||||
"js-cookie": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
|
||||
"integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
|
@ -10287,9 +10313,15 @@
|
|||
}
|
||||
},
|
||||
"less": {
|
||||
<<<<<<< HEAD
|
||||
"version": "3.9.0",
|
||||
"resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz",
|
||||
"integrity": "sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w==",
|
||||
=======
|
||||
"version": "3.13.1",
|
||||
"resolved": "http://173.15.15.82:8081/repository/npm-all/less/-/less-3.13.1.tgz",
|
||||
"integrity": "sha512-SwA1aQXGUvp+P5XdZslUOhhLnClSLIjWvJhmd+Vgib5BFIr9lMNlQwmwUNOjXThF/A0x+MCYYPeWEfeWiLRnTw==",
|
||||
>>>>>>> 5fbac9d61caef2b1bf07294acae99fc74a2ebe1a
|
||||
"requires": {
|
||||
"copy-anything": "^2.0.1",
|
||||
"errno": "^0.1.1",
|
||||
|
@ -10302,10 +10334,17 @@
|
|||
"tslib": "^1.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
<<<<<<< HEAD
|
||||
"promise": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
|
||||
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
|
||||
=======
|
||||
"make-dir": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "http://173.15.15.82:8081/repository/npm-all/make-dir/-/make-dir-2.1.0.tgz",
|
||||
"integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
|
||||
>>>>>>> 5fbac9d61caef2b1bf07294acae99fc74a2ebe1a
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"pify": "^4.0.1",
|
||||
|
@ -10322,7 +10361,7 @@
|
|||
},
|
||||
"less-loader": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "http://173.15.15.82:8081/repository/npm-all/less-loader/-/less-loader-4.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/less-loader/-/less-loader-4.1.0.tgz",
|
||||
"integrity": "sha512-KNTsgCE9tMOM70+ddxp9yyt9iHqgmSs0yTZc5XH5Wo+g80RWRIYNqE58QJKm/yMud5wZEvz50ugRDuzVIkyahg==",
|
||||
"requires": {
|
||||
"clone": "^2.1.1",
|
||||
|
@ -10332,7 +10371,7 @@
|
|||
"dependencies": {
|
||||
"pify": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "http://173.15.15.82:8081/repository/npm-all/pify/-/pify-3.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||
"integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg=="
|
||||
}
|
||||
}
|
||||
|
@ -10479,7 +10518,7 @@
|
|||
},
|
||||
"lodash.throttle": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
|
||||
"resolved": "https://registry.npm.taobao.org/lodash.throttle/download/lodash.throttle-4.1.1.tgz",
|
||||
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
|
||||
},
|
||||
"lodash.uniq": {
|
||||
|
@ -16167,6 +16206,11 @@
|
|||
"ajv-keywords": "^3.4.1"
|
||||
}
|
||||
},
|
||||
"screenfull": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz",
|
||||
"integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA=="
|
||||
},
|
||||
"scroll": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/scroll/-/scroll-2.0.3.tgz",
|
||||
|
@ -16400,6 +16444,15 @@
|
|||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"sha1": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz",
|
||||
"integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==",
|
||||
"requires": {
|
||||
"charenc": ">= 0.0.1",
|
||||
"crypt": ">= 0.0.1"
|
||||
}
|
||||
},
|
||||
"shallow-clone": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"@monaco-editor/react": "^2.3.0",
|
||||
"@novnc/novnc": "^1.1.0",
|
||||
"actioncable": "^5.2.4-3",
|
||||
"ahooks": "^2.10.14",
|
||||
"antd": "^3.26.15",
|
||||
"array-flatten": "^2.1.2",
|
||||
"autoprefixer": "7.1.6",
|
||||
|
@ -110,6 +111,7 @@
|
|||
"sass-loader": "7.3.1",
|
||||
"save-dev": "0.0.1-security",
|
||||
"scroll-into-view": "^1.14.2",
|
||||
"sha1": "^1.1.1",
|
||||
"showdown": "^1.9.1",
|
||||
"showdown-katex": "^0.8.0",
|
||||
"slick-carousel": "^1.8.1",
|
||||
|
|
|
@ -1,31 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-CN" class="notranslate translated-ltr" translate="no">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name=”Keywords” Content=”trustie,trustieforge,forge,确实让创建更美好,协同开发平台″>
|
||||
<meta name="Keywords" Content="gitLink,GitLink,gitlink,trustie,trustieforge,forge,确实让创建更美好,协同开发平台">
|
||||
<meta name=”Keywords” Content=”TrustieOpenSourceProject″>
|
||||
<meta name=”Keywords” Content=”issue,bug,tracker,软件工程,课程实践″>
|
||||
<meta name=”Description” Content=”持续构建协同、共享、可信的软件创建生态开源创作与软件生产相结合,支持大规模群体开展软件协同创新活动”>
|
||||
<meta name="theme-color" content="#000000">
|
||||
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
|
||||
<link href="https://gw.alipayobjects.com/os/lib/alipay/alex/2.0.13/bundle/alex.all.global.min.css" rel="stylesheet"/>
|
||||
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/iconfont.css">
|
||||
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/edu-purge.css">
|
||||
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/editormd.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/merge.css">
|
||||
<%= htmlWebpackPlugin.tags.headTags %>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!--用于markdown转html -->
|
||||
<div id="md_div" style="display: none;"></div>
|
||||
<div id="root" class="page -layout-v -fit widthunit"></div>
|
||||
<div id="picture_display" style="display: none;"></div>
|
||||
<script src="%PUBLIC_URL%js/react.development.js"></script>
|
||||
<script src="%PUBLIC_URL%js/react-dom.development.js"></script>
|
||||
<script src="%PUBLIC_URL%js/jquery-1.8.3.min.js"></script>
|
||||
<script src="%PUBLIC_URL%js/js_min_all.js"></script>
|
||||
<script src="%PUBLIC_URL%js/codemirror/codemirror.js"></script>
|
||||
<script src="%PUBLIC_URL%js/editormd/editormd.min.js"></script>
|
||||
<script src="%PUBLIC_URL%js/codemirror/merge/merge.js"></script>
|
||||
<script src="https://gw.alipayobjects.com/os/lib/moment/2.29.4/moment.js"></script>
|
||||
<script src="https://gw.alipayobjects.com/os/lib/alipay/alex/2.0.13/bundle/alex.all.global.min.js"></script>
|
||||
<%= htmlWebpackPlugin.tags.bodyTags %>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -25,7 +25,7 @@ if (isDev) {
|
|||
}
|
||||
debugType = window.location.search.indexOf('debug=t') !== -1 ? 'teacher' :
|
||||
window.location.search.indexOf('debug=s') !== -1 ? 'student' :
|
||||
window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'student'
|
||||
window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin'
|
||||
}
|
||||
window._debugType = debugType;
|
||||
export function initAxiosInterceptors(props) {
|
||||
|
|
|
@ -118,7 +118,7 @@ export function timeAgo(backDate) {
|
|||
var days = Math.floor(time / (1000 * 60 * 60 * 24));
|
||||
var hours = Math.floor((time % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
var minutes = Math.floor((time % (1000 * 60 * 60)) / (1000 * 60));
|
||||
var seconds = Math.floor((time % (1000 * 60 * 60)) / 1000);
|
||||
// var seconds = Math.floor((time % (1000 * 60 * 60)) / 1000);
|
||||
if (time <= 0) {
|
||||
return "刚刚";
|
||||
}
|
||||
|
@ -129,10 +129,10 @@ export function timeAgo(backDate) {
|
|||
return hours + "小时前";
|
||||
}
|
||||
if (minutes) {
|
||||
return minutes + "分前";
|
||||
}
|
||||
if (seconds) {
|
||||
return seconds + "秒前";
|
||||
return minutes + "分钟前";
|
||||
}
|
||||
// if (seconds) {
|
||||
// return seconds + "秒前";
|
||||
// }
|
||||
return "刚刚";
|
||||
}
|
|
@ -25,4 +25,18 @@ export function IEVersion(){
|
|||
}else{
|
||||
return -1;//不是ie浏览器
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function windowsOrMac(){
|
||||
let agent = navigator.userAgent.toLowerCase();
|
||||
let isMac = /macintosh|mac os x/i.test(navigator.userAgent);
|
||||
if(agent.indexOf("win32") >= 0 || agent.indexOf("wow32") >= 0){
|
||||
return 'win32';
|
||||
}
|
||||
if(agent.indexOf("win64") >= 0 || agent.indexOf("wow64") >= 0){
|
||||
return 'win64';
|
||||
}
|
||||
if(isMac){
|
||||
return 'mac';
|
||||
}
|
||||
}
|
|
@ -11,14 +11,28 @@ export function getImageUrl(path) {
|
|||
// https://www.educoder.net
|
||||
// https://testbdweb.trustie.net
|
||||
// const local = 'http://localhost:3000'
|
||||
path && !path.startsWith('/') && !path.startsWith('http') && (path = '/'.concat(path));
|
||||
path && !path.startsWith('/') && !path.startsWith('http') && (path = '/'.concat(path));
|
||||
const local = 'https://testforgeplus.trustie.net';
|
||||
if (isDev) {
|
||||
return `${local}/${path}`
|
||||
return `${local}${path}`
|
||||
}
|
||||
return `${path}`;
|
||||
}
|
||||
|
||||
export function getImageUrlAbsolute(path) {
|
||||
// https://www.educoder.net
|
||||
// https://testbdweb.trustie.net
|
||||
// const local = 'http://localhost:3000'
|
||||
path && !path.startsWith('/') && !path.startsWith('http') && (path = '/'.concat(path));
|
||||
const local = 'https://testforgeplus.trustie.net';
|
||||
const prod = window.location.origin;
|
||||
if (isDev) {
|
||||
return `${local}${path}`
|
||||
}else{
|
||||
return `${prod}${path}`;
|
||||
}
|
||||
}
|
||||
|
||||
export function numFormat(num, digits){
|
||||
let d = digits || 1;
|
||||
var si = [
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
export {
|
||||
getUploadLogoActionUrl as getUploadLogoActionUrl,numFormat as numFormat,
|
||||
getImageUrl as getImageUrl,getImage as getImage, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
|
||||
getImageUrl as getImageUrl,getImageUrlAbsolute as getImageUrlAbsolute,getImage as getImage, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
|
||||
, getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
|
||||
, getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode, getupload_git_file as getupload_git_file, getcdnImageUrl as getcdnImageUrl,
|
||||
turnbar,returnbar
|
||||
|
@ -78,3 +78,5 @@ export { default as ImageLayer2 } from './hooks/ImageLayer2'
|
|||
|
||||
// 外部
|
||||
export { CNotificationHOC as CNotificationHOC } from '../modules/courses/common/CNotificationHOC'
|
||||
|
||||
export { IEVersion as IEVersion , windowsOrMac as windowsOrMac} from './IEVersion'
|
||||
|
|
|
@ -135,7 +135,7 @@ class Activity extends Component{
|
|||
const fourth_per =issues_count > 0 ?`${parseFloat(open_issues_count/issues_count).toFixed(2)*100}%` :"50%";
|
||||
|
||||
return(
|
||||
<div className="main">
|
||||
<div className="main mt20">
|
||||
|
||||
<div className="normalBox">
|
||||
<div class="normalBox-title">概览</div>
|
||||
|
|
|
@ -3,29 +3,22 @@ import { AlignCenter } from '../layout';
|
|||
import { Button } from 'antd';
|
||||
import Modals from '../PublicModal/Index';
|
||||
|
||||
function DeleteBox({
|
||||
visible ,
|
||||
onCancel ,
|
||||
onSuccess ,
|
||||
title ,
|
||||
subTitle,
|
||||
content
|
||||
}) {
|
||||
function DeleteBox({visible, onCancel, onSuccess, title, subTitle, content}) {
|
||||
return(
|
||||
<Modals
|
||||
title={title}
|
||||
<Modals
|
||||
title={title}
|
||||
btn={
|
||||
<div>
|
||||
<Button size={'large'} onClick={onCancel}>取消</Button>
|
||||
<Button type={"danger"} size={"large"} onClick={onSuccess}>确认删除</Button>
|
||||
</div>
|
||||
}
|
||||
onCancel={onCancel}
|
||||
}
|
||||
onCancel={onCancel}
|
||||
visible={visible}
|
||||
>
|
||||
<div className="desc">
|
||||
<AlignCenter className="descMain"><i className="iconfont icon-shanchu_tc_icon mr10"></i>{content}</AlignCenter>
|
||||
<p className="task-hide-2" style={{WebkitLineClamp:5}}>删除后未来事件将不会推送至此Webhook地址:<span title={subTitle}>{subTitle}</span></p>
|
||||
<AlignCenter className="descMain"><i className="iconfont icon-shanchu_tc_icon mr10 font-36" style={{color: '#ca0002'}}></i>{content}</AlignCenter>
|
||||
<p className="task-hide-2" style={{WebkitLineClamp:5}}><span title={subTitle}>{subTitle}</span></p>
|
||||
</div>
|
||||
</Modals>
|
||||
)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import React, {useEffect} from 'react';
|
||||
import { WhiteBack } from '../Component/layout';
|
||||
import './ops.scss';
|
||||
|
||||
import devops from '../Images/devops.png';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
import Loadable from 'react-loadable';
|
||||
import Loading from '../../Loading';
|
||||
|
@ -32,11 +32,49 @@ const Params = Loadable({
|
|||
})
|
||||
|
||||
export default ((props)=>{
|
||||
const {jianmu_devops, isManager, project} = props;
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("message", iframeHeight, false);
|
||||
return () => {
|
||||
window.removeEventListener("message", iframeHeight, false);
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
function iframeHeight(e){
|
||||
if (e && e.data && typeof(e.data) === "string") {
|
||||
let myHeight = JSON.parse(e.data);
|
||||
if (document.querySelector("#devopsIframe")) {
|
||||
document.querySelector("#devopsIframe").height = myHeight.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function iframeLoad() {
|
||||
try {
|
||||
let myIframe = document.getElementById("devopsIframe");
|
||||
if (myIframe.contentDocument) {
|
||||
myIframe.height = myIframe.contentDocument.querySelector('.el-main').clientHeight + 260;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
return(
|
||||
<WhiteBack className="opsPanel">
|
||||
<Switch {...props}>
|
||||
|
||||
<WhiteBack className={`opsPanel ${isManager ? 'main' : ''}`}>
|
||||
{/* 嵌入devops */}
|
||||
{jianmu_devops && project && isManager && <iframe title={`devopsIframe`} src={`${project.jianmu_devops_url}/oauth2/authorize?code=${jianmu_devops}`} id={`devopsIframe`} frameBorder="0" name={`devopsIframe`} width="100%" onLoad={iframeLoad} height={'auto'}></iframe>}
|
||||
{!isManager && <div className='nullJurisdictionBox'>
|
||||
<div className='jurTil font-16'>引擎配置</div>
|
||||
<div className='jurCont mt25'>
|
||||
<img src={devops} alt="" width={110}/>
|
||||
<div className='font-18 mt30'>暂无权限,仅仓库管理员可访问</div>
|
||||
</div>
|
||||
</div>}
|
||||
{/* 旧引擎页面 */}
|
||||
{/* <Switch {...props}>
|
||||
<Route path="/:owner/:projectsId/devops/params"
|
||||
render={
|
||||
(p) => (<Params {...props} {...p}/>)
|
||||
|
@ -52,7 +90,6 @@ export default ((props)=>{
|
|||
(p) => (<New {...props} {...p}/>)
|
||||
}
|
||||
></Route>
|
||||
|
||||
<Route path="/:owner/:projectsId/devops/list/:branch"
|
||||
render={
|
||||
(p) => (<Stucture {...props} {...p}/>)
|
||||
|
@ -63,14 +100,14 @@ export default ((props)=>{
|
|||
(p) => (<New {...props} {...p}/>)
|
||||
}
|
||||
></Route>
|
||||
{/* 原本的两种合为一个 */}
|
||||
// 原本的两种合为一个
|
||||
<Route path="/:owner/:projectsId/devops"
|
||||
render={
|
||||
// (p) =>{return( p.location && p.location.state && p.location.state.open_devops?<Dispose {...props} {...p}/>:<About {...props} {...p}/>)}
|
||||
(p) =>{return(<About {...props} {...p}/>)}
|
||||
}
|
||||
></Route>
|
||||
</Switch>
|
||||
</Switch> */}
|
||||
</WhiteBack>
|
||||
)
|
||||
})
|
|
@ -2,6 +2,7 @@
|
|||
{
|
||||
margin:20px auto;
|
||||
width: 1200px;
|
||||
min-height: 500px;
|
||||
// 开始激活页面
|
||||
.activatePanel{
|
||||
display: flex;
|
||||
|
@ -521,4 +522,22 @@
|
|||
border:1px solid #999;
|
||||
color:#999 ;
|
||||
}
|
||||
}
|
||||
.nullJurisdictionBox{
|
||||
color:#333333;
|
||||
.jurTil{
|
||||
width:1200px;
|
||||
padding: 15px 16px;
|
||||
background-color:#fafcff;
|
||||
border:1px solid rgba(42, 97, 255, 0.23);
|
||||
border-radius:3px 3px 0px 0px;
|
||||
}
|
||||
.jurCont{
|
||||
width:1200px;
|
||||
height:317px;
|
||||
padding-top: 45px;
|
||||
background-color:#fafcff;
|
||||
border-radius:4px 4px 0px 0px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 12 KiB |
|
@ -333,6 +333,8 @@ function CoderDepot(props){
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
let n = fileInfo && fileInfo.name;
|
||||
const mdFlag = n && n.substring(n.length-3,n.length) === ".md";
|
||||
|
||||
|
@ -443,6 +445,7 @@ function CoderDepot(props){
|
|||
issuesFlag &&
|
||||
<a onClick={createIssue}>+ 疑修</a>
|
||||
}
|
||||
|
||||
</div>
|
||||
{ fileOperate &&
|
||||
<Dropdown
|
||||
|
|
|
@ -14,7 +14,7 @@ function CoderDepotPath({treeValuePath , returnUlr , returnMain , getPathUrl , i
|
|||
</a>
|
||||
{treeValuePath.map((item, key) => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<React.Fragment key={key}>
|
||||
{
|
||||
key === treeValuePath.length-1 ?
|
||||
<span className="color-grey-6 subFileName" key={key}>{returnbar(item)}</span>
|
||||
|
|
|
@ -150,6 +150,10 @@ const Invite = Loadable({
|
|||
loader: () => import('../Invite/Index'),
|
||||
loading: Loading,
|
||||
});
|
||||
const Review = Loadable({
|
||||
loader: () => import('../Newfile/codeReview'),
|
||||
loading: Loading,
|
||||
});
|
||||
/**
|
||||
* permission:Manager:管理员,Reporter:报告人员(只有读取权限),Developer:开发人员(除不能设置仓库信息外)
|
||||
*/
|
||||
|
@ -209,7 +213,9 @@ class Detail extends Component {
|
|||
defaultBranch: undefined,
|
||||
|
||||
// 非本平台项目
|
||||
platform: false
|
||||
platform: false,
|
||||
// devops工作流code
|
||||
jianmu_devops: undefined
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,7 +259,8 @@ class Detail extends Component {
|
|||
this.setState({
|
||||
project: result.data,
|
||||
open_devops: result.data.open_devops,
|
||||
platform: result.data.platform && result.data.platform !== 'educoder'
|
||||
platform: result.data.platform && result.data.platform !== 'educoder',
|
||||
jianmu_devops: result.data.jianmu_devops && encodeURIComponent(result.data.jianmu_devops)
|
||||
})
|
||||
|
||||
if (result.data.type !== 0 && result.data.mirror_status === 1) {
|
||||
|
@ -661,6 +668,7 @@ class Detail extends Component {
|
|||
urlFlag={urlFlag}
|
||||
showNotification={this.props.showNotification}
|
||||
current_user={current_user}
|
||||
isManager={isManager}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
|
@ -817,6 +825,12 @@ class Detail extends Component {
|
|||
(props) => (<UpdateMerge {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
{/* review */}
|
||||
<Route path="/:owner/:projectsId/pulls/:mergeId/review"
|
||||
render={
|
||||
(props) => (<Review {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/:owner/:projectsId/pulls/:mergeId"
|
||||
render={
|
||||
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
|
||||
|
@ -882,6 +896,7 @@ class Detail extends Component {
|
|||
(props) => (<Invite {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
|
||||
<Route path="/:owner/:projectsId/:subIndex"
|
||||
render={
|
||||
(props) => (<CoderRootIndex {...this.props} {...props} {...this.state} {...common} />)
|
||||
|
|
|
@ -122,7 +122,7 @@
|
|||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
.panelmenu{
|
||||
padding-top:30px;
|
||||
padding-top:20px;
|
||||
.depotBtn{
|
||||
.mr-5{
|
||||
margin-right: -5px;
|
||||
|
|
|
@ -5,7 +5,7 @@ import { numFormat } from 'educoder';
|
|||
import QuitBox from './quit';
|
||||
import axios from 'axios';
|
||||
|
||||
function DetailBanner({ history,list , owner , projectsId ,showNotification , url , pathname , state , urlFlag , projectDetail , platform ,open_devops ,current_user }){
|
||||
function DetailBanner({ history,list , owner , projectsId ,showNotification , url , pathname , state , urlFlag , projectDetail , platform ,open_devops ,current_user, isManager }){
|
||||
const [ menuName , setMenuName ] = useState(undefined);
|
||||
const [ visible , setVisible ] = useState(false);
|
||||
useEffect(()=>{
|
||||
|
@ -32,15 +32,15 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
|
|||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
||||
|
||||
return(
|
||||
<div className="f-wrap-between mt25">
|
||||
<QuitBox visible={visible} onCancel={()=>setVisible(false)} name={projectDetail && projectDetail.name} onSuccess={onSuccess}/>
|
||||
{
|
||||
menuName && projectDetail ?
|
||||
menuName && projectDetail ?
|
||||
<ul className="headerMenu-wrapper">
|
||||
{
|
||||
Array.isArray(menuName)&& menuName.map((item,key)=>{
|
||||
Array.isArray(menuName)&& menuName.map((item,key)=>{
|
||||
return(
|
||||
<React.Fragment key={item.menu_name}>
|
||||
{
|
||||
|
@ -83,8 +83,9 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
|
|||
</Link>
|
||||
</li>:""
|
||||
}
|
||||
{/* 引擎仅对当前仓库管理员可见 */}
|
||||
{
|
||||
item.menu_name === "devops" ?
|
||||
item.menu_name === "devops" ?
|
||||
<li className={pathname==="devops" ? "active" : ""}>
|
||||
{/* <Link to={{ pathname: `/${owner}/${projectsId}/devops${open_devops ? `/dispose`:""}`, state }}> */}
|
||||
<Link to={{ pathname: `/${owner}/${projectsId}/devops`, state:{...state,open_devops} }}>
|
||||
|
|
|
@ -293,6 +293,12 @@ class MessageCount extends Component {
|
|||
)
|
||||
}
|
||||
|
||||
codeReview=()=>{
|
||||
const {history,match}=this.props;
|
||||
const { projectsId, mergeId , owner } =match.params;
|
||||
history.push(`/${owner}/${projectsId}/pulls/${mergeId}/review`);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { projectsId, mergeId , owner } = this.props.match.params;
|
||||
|
||||
|
@ -449,6 +455,18 @@ class MessageCount extends Component {
|
|||
编辑
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{operate && (
|
||||
<Button
|
||||
type="blue"
|
||||
ghost
|
||||
className="ml20"
|
||||
onClick={this.codeReview}
|
||||
>
|
||||
代码评审
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{operate && (
|
||||
<Button
|
||||
type="danger"
|
||||
|
|
|
@ -117,6 +117,11 @@ form .ant-cascader-picker, form .ant-select {
|
|||
border:1px solid #28BD6C;
|
||||
color: #28BD6C;
|
||||
}
|
||||
/* 绿色按钮-type="blue" */
|
||||
.ant-btn.ant-btn-blue{
|
||||
border:1px solid #466aff;
|
||||
color: #466aff;
|
||||
}
|
||||
.copyTab{
|
||||
min-width: 370px;
|
||||
padding:0px 18px 22px 18px;
|
||||
|
|
|
@ -247,7 +247,7 @@ class merge extends Component {
|
|||
</Menu>
|
||||
);
|
||||
return (
|
||||
<div className="main" style={{padding:"0px"}}>
|
||||
<div className="main mt20" style={{padding:"0px"}}>
|
||||
<div className="topWrapper" style={{borderBottom:"none",padding:"20px"}}>
|
||||
<div className="target-detail-search">
|
||||
<Search
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
const IPluginAPI = {
|
||||
commands: {}
|
||||
}
|
||||
|
||||
export class Plugin {
|
||||
PLUGIN_ID = 'ChangeThemePlugin';
|
||||
|
||||
_commands = IPluginAPI['commands'] || null;
|
||||
|
||||
get commands() {
|
||||
return this._commands;
|
||||
}
|
||||
|
||||
activate({ context, commands }) {
|
||||
this._commands = commands;
|
||||
context.subscriptions.push(
|
||||
commands.registerCommand(
|
||||
'ChangeThemePlugin.changeTheme',
|
||||
(value) => {
|
||||
commands.executeCommand(
|
||||
'alex.setDefaultPreference',
|
||||
'general.theme',
|
||||
value
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default new Plugin();
|
|
@ -0,0 +1,283 @@
|
|||
import React, { Fragment, useState, useMemo, useEffect, useRef } from 'react';
|
||||
import { Switch ,Checkbox ,Tooltip,Popover,Radio,Icon} from 'antd';
|
||||
import { EditorRenderer } from 'alex';
|
||||
import { useLocalStorageState } from 'ahooks';
|
||||
import html from './extensions/alex-ext-public.html-language-features-worker.js';
|
||||
import css from './extensions/alex-ext-public.css-language-features-worker.js';
|
||||
import json from './extensions/alex-ext-public.typescript-language-features-worker.js';
|
||||
import typescript from './extensions/alex-ext-public.json-language-features-worker.js';
|
||||
import markdown from './extensions/alex-ext-public.markdown-language-features-worker.js';
|
||||
import ideTheme from './extensions/alex-ext-public.ide-dark-theme.js';
|
||||
import CodeBlame from './extensions/alex-ext-public.editor-plugin-blame.js';
|
||||
import { getUrl, returnbar } from 'educoder';
|
||||
import changeThemePlugin from './changeTheme';
|
||||
import IDEPlugin, { ExtensionCommand } from './ide-plugin';
|
||||
// import { FileOperationArea } from './components/file-operation-area';
|
||||
import { repoService } from './codeReview/mock/repo.service';
|
||||
|
||||
|
||||
function CloudIDE({ download_url, params: { owner, projectsId, branchName }, filepath }) {
|
||||
function FileContentStore() {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [showIde, setShowIde] = useState(false);
|
||||
const [fileSize, setFileSize] = useState('0');
|
||||
const [fileName, setFileName] = useState('');
|
||||
|
||||
return {
|
||||
loading,
|
||||
setLoading,
|
||||
showIde,
|
||||
setShowIde,
|
||||
fileSize,
|
||||
setFileSize,
|
||||
fileName,
|
||||
setFileName,
|
||||
};
|
||||
}
|
||||
|
||||
const { fileSize, fileName } =
|
||||
FileContentStore();
|
||||
const fileCache = new Map();
|
||||
|
||||
const copyFile = () => {
|
||||
console.log('复制文件内容');
|
||||
};
|
||||
|
||||
const [settingTipVisible, setSettingTipVisible] = useLocalStorageState(
|
||||
'code.file.operation.tip',
|
||||
true
|
||||
);
|
||||
|
||||
const [lines, setLines] = useState(0);
|
||||
const [sloc, setSloc] = useState(0);
|
||||
const [encoding, setEncoding] = useState('UTF-8');
|
||||
// const [showMdPreview, setShowPreview] = useState(false);
|
||||
const [fileString, setFileString] = useState('');
|
||||
const curFilepath = useMemo(() => {
|
||||
// 仓库默认页是没有path的,默认解析到readme
|
||||
// 当不需要加载文件时,返回空
|
||||
// const needLoadFile = treeEntry
|
||||
// ? treeEntry.render === FileShowType.text &&
|
||||
// treeEntry.size < ReadFileSizeLimit
|
||||
// : !!fileName;
|
||||
// return needLoadFile ? path || fileName : '';
|
||||
}, [branchName, fileName]);
|
||||
|
||||
const [blameChecked, setBlameChecked] = useState(false);
|
||||
// 组件卸载时,清空缓存
|
||||
// useUnmount(() => {
|
||||
// fileCache.clear()
|
||||
// })
|
||||
// 由于 editor 组件内部有缓存,已经加载过的文件不会再次请求 readFile 方法
|
||||
// 所以当已经加载过该文件时,直接读取文件内容用于展示
|
||||
// 暂时前端缓存,文件体积有过大保护,内存溢出风险较低,暂时不做过多设计,待后续接入editor api
|
||||
useEffect(() => {
|
||||
setBlameChecked(false);
|
||||
const fileKey = `${branchName}-${curFilepath}`;
|
||||
const fileInfo = fileCache.get(fileKey);
|
||||
if (fileInfo) {
|
||||
setFileString(fileInfo.fileString);
|
||||
setLines(fileInfo.lines);
|
||||
setSloc(fileInfo.sloc);
|
||||
}
|
||||
}, [curFilepath]);
|
||||
// 插件
|
||||
const [pluginActivated, setPluginActivated] = useState(false);
|
||||
const plugin = useRef(
|
||||
new IDEPlugin(
|
||||
() => setPluginActivated(true),
|
||||
(commitId) => window.open(`/${owner}/${projectsId}/commits/${commitId}`)
|
||||
)
|
||||
);
|
||||
// blame
|
||||
const onBlame = async (e) => {
|
||||
setBlameChecked(e.target.checked);
|
||||
console.log('onBlame:', e.target.checked);
|
||||
if (!e.target.checked) {
|
||||
plugin.current.commands.executeCommand(ExtensionCommand.toggleBlame);
|
||||
} else {
|
||||
const res = await repoService.getCodeBlame(projectsId, owner, { sha: branchName, filepath })
|
||||
plugin.current.commands.executeCommand(ExtensionCommand.toggleBlame, res);
|
||||
}
|
||||
};
|
||||
const [wordWrap, setWordWrap] = useState(false);
|
||||
const onWordWrapChange = (value) => {
|
||||
const preference = value ? 'on' : 'off';
|
||||
localStorage.setItem('code.file.viewer.worlWrap', preference);
|
||||
plugin.current.setPerference('editor.wordWrap', preference, true);
|
||||
setWordWrap(value);
|
||||
};
|
||||
|
||||
async function changeStyle(v) {
|
||||
const commands = changeThemePlugin.commands;
|
||||
if (commands) {
|
||||
await commands.executeCommand(
|
||||
'ChangeThemePlugin.changeTheme',
|
||||
v ? 'opensumi-light' : 'opensumi-dark'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const content = (
|
||||
<Fragment>
|
||||
<div className="flex align-center">
|
||||
<span className="c-65">{'编码方式'}:</span>
|
||||
<span>
|
||||
<Radio.Group
|
||||
onChange={(e) => {
|
||||
setEncoding(e.target.value);
|
||||
}}
|
||||
value={encoding}
|
||||
size="small"
|
||||
>
|
||||
<Radio value="UTF-8">UTF-8</Radio>
|
||||
<Radio value="GBK">GBK</Radio>
|
||||
</Radio.Group>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex align-center">
|
||||
<span className="c-65">{'自动换行'}:</span>
|
||||
<span>
|
||||
<Radio.Group
|
||||
onChange={(e) => {
|
||||
onWordWrapChange(e.target.value);
|
||||
}}
|
||||
value={wordWrap}
|
||||
size="small"
|
||||
>
|
||||
<Radio value={false}>{'不自动换行'}</Radio>
|
||||
<Radio value={true}>{'自动换行'}</Radio>
|
||||
</Radio.Group>
|
||||
</span>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="ide-tool-bar">
|
||||
{onBlame ? (
|
||||
<Checkbox onChange={onBlame} checked={!!blameChecked}>
|
||||
Blame
|
||||
</Checkbox>
|
||||
) : null}
|
||||
<Switch checkedChildren="light" unCheckedChildren="dark" defaultChecked onChange={changeStyle}></Switch>
|
||||
|
||||
<Tooltip
|
||||
title={'更改阅读设置'}
|
||||
defaultVisible={settingTipVisible}
|
||||
onVisibleChange={setSettingTipVisible}
|
||||
>
|
||||
<Popover
|
||||
content={content}
|
||||
title={null}
|
||||
trigger="click"
|
||||
placement="bottomRight"
|
||||
arrowPointAtCenter={true}
|
||||
>
|
||||
{/* <Icon type="ellipsis" /> */}
|
||||
<Icon className="read-more" type="read" />
|
||||
</Popover>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/* <FileOperationArea
|
||||
lines={lines}
|
||||
sloc={sloc}
|
||||
size={fileSize}
|
||||
refName={branchName}
|
||||
path={curFilepath}
|
||||
encoding={encoding}
|
||||
setEncoding={setEncoding}
|
||||
onFileCopy={copyFile}
|
||||
blameChecked={blameChecked}
|
||||
onBlame={pluginActivated && onBlame}
|
||||
wordWrap={wordWrap}
|
||||
setWordWrap={onWordWrapChange}
|
||||
/> */}
|
||||
|
||||
|
||||
<EditorRenderer
|
||||
appConfig={{
|
||||
// 工作空间目录
|
||||
plugins: [changeThemePlugin, plugin.current],
|
||||
workspaceDir: `${owner}/${projectsId}`,
|
||||
defaultPreferences: {
|
||||
// 默认主题,如果暗色为 opensumi-dark
|
||||
// 'general.theme': 'opensumi-light',
|
||||
'general.theme': 'opensumi-light',
|
||||
// 编辑器只读
|
||||
'editor.forceReadOnly': true,
|
||||
// 最后一行禁止继续滚动
|
||||
'editor.scrollBeyondLastLine': false,
|
||||
},
|
||||
extensionMetadata: [
|
||||
html,
|
||||
css,
|
||||
json,
|
||||
typescript,
|
||||
markdown,
|
||||
ideTheme,
|
||||
CodeBlame],
|
||||
}}
|
||||
runtimeConfig={{
|
||||
// 业务标识
|
||||
biz: 'gitlink',
|
||||
// 在 editor 下推荐传 null,此时不会持久化缓存工作空间数据
|
||||
scenario: null,
|
||||
// 启动时显示的编辑器,editor 下传 none 即可
|
||||
startupEditor: 'none',
|
||||
// 隐藏 editor tab
|
||||
hideEditorTab: true,
|
||||
}}
|
||||
editorConfig={{
|
||||
stretchHeight: true,
|
||||
disableEditorSearch: true,
|
||||
}}
|
||||
// 文档模型,以下数据变更时会更新打开的编辑器
|
||||
documentModel={{
|
||||
// 类型,code 下为 code,保持不变
|
||||
type: 'code',
|
||||
// 分支或 tag
|
||||
ref: branchName,
|
||||
// 仓库群组和用户
|
||||
owner: owner,
|
||||
// 仓库名
|
||||
name: projectsId,
|
||||
// 仓库文件路径
|
||||
filepath: filepath,
|
||||
// 读取文件接口
|
||||
readFile: async (filepath) => {
|
||||
if (!filepath) {
|
||||
return;
|
||||
}
|
||||
// 请求接口
|
||||
// const res = await fetch('https://gist.githubusercontent.com/gaearon/0b180827c190fe4fd98b4c7f570ea4a8/raw/b9157ce933c79a4559d2aa9ff3372668cce48de7/LikeButton.js');
|
||||
const res = await fetch(`${getUrl()}/attachments/entries/get_file?download_url=${download_url}`);
|
||||
setTimeout(()=>{
|
||||
onWordWrapChange(localStorage.getItem('code.file.viewer.worlWrap') === 'on');
|
||||
},5000)
|
||||
return res.arrayBuffer();
|
||||
},
|
||||
// 文件编码,和标准工作空间支持编码类型一致,简单场景只传 utf8 或 gbk 即可
|
||||
// encoding: 'utf8',
|
||||
encoding,
|
||||
onFilepathChange: (changedFilepath) => {
|
||||
if (changedFilepath) {
|
||||
console.log(`路由跳转到 ${changedFilepath}`)
|
||||
}
|
||||
},
|
||||
// 指定当前选中多少行
|
||||
// lineNumber: [0, 1],
|
||||
onLineNumberChange: line => {
|
||||
if (typeof line === 'number') {
|
||||
console.log(`#L${line}`)
|
||||
} else {
|
||||
console.log(`#L${line[0]}-${line[1]}`)
|
||||
}
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
export default CloudIDE;
|
|
@ -0,0 +1,56 @@
|
|||
module.exports = {
|
||||
extension: {
|
||||
publisher: 'alex-ext-public',
|
||||
name: 'editor-plugin-blame',
|
||||
version: '0.2.6',
|
||||
},
|
||||
packageJSON: {
|
||||
name: 'editor-plugin-blame',
|
||||
publisher: 'alex-ext-public',
|
||||
version: '0.2.6',
|
||||
repository: {
|
||||
type: 'git',
|
||||
url: 'http://code.alipay.com/yxy167584/editor-plugin-blame.git',
|
||||
},
|
||||
displayName: 'editor-plugin-blame',
|
||||
description: ' ',
|
||||
activationEvents: ['*'],
|
||||
kaitianContributes: {
|
||||
workerMain: './out/worker/index.js',
|
||||
},
|
||||
contributes: {
|
||||
commands: [
|
||||
{
|
||||
command: 'code.blame.toggleBlame',
|
||||
title: '查看blame',
|
||||
},
|
||||
{
|
||||
command: 'code.blame.acrToggleBlame',
|
||||
title: 'blame',
|
||||
},
|
||||
{
|
||||
command: 'code.blame.linktocommit',
|
||||
title: 'hover详情跳转',
|
||||
},
|
||||
],
|
||||
views: {},
|
||||
menus: {
|
||||
'editor/title': [
|
||||
{
|
||||
command: 'code.blame.acrToggleBlame',
|
||||
type: 'checkbox',
|
||||
group: 'navigation',
|
||||
toggledWhen: 'acr_blame_context',
|
||||
when: 'resourceScheme =~ /^git$|^diff$/',
|
||||
},
|
||||
],
|
||||
},
|
||||
workerMain: './out/worker/index.js',
|
||||
},
|
||||
},
|
||||
pkgNlsJSON: {},
|
||||
nlsList: [],
|
||||
extendConfig: {},
|
||||
webAssets: ['package.json', 'out/worker/index.js'],
|
||||
mode: 'public',
|
||||
};
|
|
@ -0,0 +1,72 @@
|
|||
import { DependencyList, useEffect, useState, useMemo } from 'react';
|
||||
// @ts-ignore
|
||||
import { useEventEmitter, usePrevious } from 'ahooks';
|
||||
// @ts-ignore
|
||||
import sha1 from 'sha1';
|
||||
// @ts-ignore
|
||||
import differenceBy from 'lodash/differenceBy';
|
||||
|
||||
|
||||
export function useRequest(
|
||||
factory,
|
||||
options
|
||||
) {
|
||||
const { deps = [], initial, ready = true } = options || {};
|
||||
const [val, setVal] = useState(initial);
|
||||
useEffect(() => {
|
||||
if (!ready) return;
|
||||
let cancel = false;
|
||||
const promise = factory();
|
||||
if (promise === undefined || promise === null) return;
|
||||
promise
|
||||
.then((val) => {
|
||||
if (!cancel) {
|
||||
setVal(val);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
return () => {
|
||||
cancel = true;
|
||||
};
|
||||
}, [...deps, ready]);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
export function useFileReadMarkChange$(
|
||||
diffs,
|
||||
readMarks
|
||||
) {
|
||||
const fileReadMarkChange$ = useEventEmitter();
|
||||
const filePathShaMap = useMemo(() => {
|
||||
const map = new Map();
|
||||
for (const diff of diffs) {
|
||||
map.set(sha1(diff.newPath), diff.newPath);
|
||||
}
|
||||
return map;
|
||||
}, [diffs]);
|
||||
|
||||
const prevReadMarks = usePrevious(readMarks);
|
||||
useEffect(() => {
|
||||
const changesA = differenceBy(
|
||||
prevReadMarks,
|
||||
readMarks,
|
||||
(readMark) => readMark.filePathSha
|
||||
);
|
||||
const changesB = differenceBy(
|
||||
readMarks,
|
||||
prevReadMarks,
|
||||
(readMark) => readMark.filePathSha
|
||||
);
|
||||
for (const change of [...changesA, ...changesB]) {
|
||||
const filePath = filePathShaMap.get(change.filePathSha);
|
||||
if (filePath) {
|
||||
fileReadMarkChange$.emit(filePath);
|
||||
}
|
||||
}
|
||||
}, [readMarks, filePathShaMap]);
|
||||
|
||||
return fileReadMarkChange$;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" viewBox="0 0 200 200">
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient" y1="0.5" x2="1" y2="0.5" gradientUnits="objectBoundingBox">
|
||||
<stop offset="0" stop-color="#6dffff"/>
|
||||
<stop offset="1" stop-color="#0080ff"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g id="组_1758" data-name="组 1758" transform="translate(9483 -10311)">
|
||||
<rect id="矩形_340" data-name="矩形 340" width="200" height="200" transform="translate(-9483 10311)" fill="#fff" opacity="0"/>
|
||||
<g id="图层_2" data-name="图层 2" transform="translate(-9472 10328)">
|
||||
<g id="图层_1" data-name="图层 1">
|
||||
<path id="路径_1227" data-name="路径 1227" d="M127.508,32.458,123.06,26.4l-3.9,1.958V77.007l3.239,1.7v-5.4l5.11,8.248,4.145.648V23.03l-4.145,1.6ZM35.847,82.2l9.284-4.62V27.708L35.847,23.03Zm63.463,6.29,8.305,4.951V9.241L99.31,14.192ZM87.378,0H75.863V105.291H93.509V94.841H87.378ZM49.954,21.821l4.577,1.684V93.344l8.348-4.318V27.132l4.477,1.655V19.3L49.954,9.226ZM5.448,78.634,25.6,68.457V49.3l-9.543-1.022v6.736h3.829V61.52l-6.621,3.008V43.873L25.541,46.06V38.216L5.39,31.58ZM154.18,54.855,168.919,31.58l-11.04,1.195-7.355,9.788V36.071L142.406,38V73.006l8.118,1.684V67.982l7.845,10.076,12.7.633Z" transform="translate(2.368)" fill-rule="evenodd" fill="url(#linear-gradient)"/>
|
||||
<path id="路径_1228" data-name="路径 1228" d="M0,110.683a27.2,27.2,0,0,0,2.634-4.577q1.051-2.375,1.727-4.4a33.61,33.61,0,0,0,.979-3.527c.2-.993.317-1.612.345-1.9V92.964h-3.5V88.876H17.445v4.088H9.37V96.75q0,.158-.432,2.245a34.545,34.545,0,0,1-1.439,5.11h5.556v-.72H16.74V122.86a4.822,4.822,0,0,1-1.209,3.325,3.915,3.915,0,0,1-3.008,1.339h-8.2V110.942l-.72,1.137c-.23.389-.489.763-.763,1.152Zm8.017,12.753h4.491c.36,0,.547-.187.547-.576V108.193H8.017Zm9.471-27.521q1.209-1.6,2.073-2.879c.576-.82,1.195-1.77,1.842-2.879a28.457,28.457,0,0,0,1.727-3.267L26.4,88.7a17.271,17.271,0,0,1-.849,1.713H39.727V93.67l-3.354,4.995h2v-.777h3.685v24.758a4.808,4.808,0,0,1-1.209,3.325,3.872,3.872,0,0,1-2.98,1.353h-2.1v-4.045h2.058c.374,0,.547-.2.547-.619v-3.368h-6.29v7.2H28.4v-7.2H22.3q-.23,1.67-.518,3.109c-.187.964-.36,1.814-.533,2.562s-.317,1.353-.446,1.814a7.658,7.658,0,0,0-.187.748l-1.77-.619-1.727-.619c.4-1.6.734-3.008.979-4.318s.475-2.648.677-4.189a35.307,35.307,0,0,0,.3-4.592V98.664H31.811l2.735-4.088H23.131q-1.123,1.756-1.986,2.879l-.993,1.108ZM28.4,115.188v-4.707H22.757v4.707Zm-5.642-12.436v3.627H28.4v-3.627Zm15.617,0h-6.29v3.627h6.29Zm0,12.436v-4.707h-6.29v4.707Z" transform="translate(0 38.179)" fill="#333"/>
|
||||
<path id="路径_1229" data-name="路径 1229" d="M32.82,110.943H51.014c.518-.806.993-1.612,1.439-2.447a15.2,15.2,0,0,0,1.036-2.634V97.168h3.685V106.7a21.591,21.591,0,0,1-1.7,4.2H73.382v4.088H58.427l14.509,8.751L71.151,127.4,55.49,117.91l1.439-2.879H52.756a31.018,31.018,0,0,1-3.742,3.786,41.975,41.975,0,0,1-4.045,3.051,43.833,43.833,0,0,1-3.944,2.361c-1.267.677-2.418,1.223-3.426,1.655s-1.842.777-2.49,1.008l-1.123.417-.518-1.972-.5-1.914s.5-.173,1.439-.547,2.116-.878,3.527-1.569,2.965-1.555,4.635-2.591a32.934,32.934,0,0,0,4.908-3.685H32.82Zm.1-19.849H51.287l-1.166-2.433,3.267-1.871,2,4.318H69.251v-.734h3.685V99.86H69.251V95.182H36.606v4.865H32.921Zm4.75,10.824,9.889,4.462-1.353,3.742-9.889-4.462Zm12.681,3.325-9.831-4.62,1.439-3.786,9.831,4.649Z" transform="translate(14.421 38.135)" fill="#333"/>
|
||||
<path id="路径_1230" data-name="路径 1230" d="M105.835,108.223h-9.37v18.453h-3.7V108.223H77.307a38.49,38.49,0,0,1-2.03,7.125,62.419,62.419,0,0,1-2.634,5.758,44.3,44.3,0,0,1-2.332,3.944c-.691.979-1.065,1.526-1.123,1.626l-2.879-2.591.907-1.3a34.806,34.806,0,0,0,2.015-3.4c.763-1.439,1.54-3.109,2.346-5.023a34.877,34.877,0,0,0,1.958-6.146H64.05v-4.088H74.126V92.117H66.857V88h36.229v4.1H96.465v12.019h9.37Zm-13.07-4.088V92.117H77.955v12.019Z" transform="translate(28.143 38.666)" fill="#333"/>
|
||||
<path id="路径_1231" data-name="路径 1231" d="M98.847,127.257l-3.267-1.77,6.348-14.394,3.311,1.814Zm3.958-29.8L96,90.667l2.433-3.008,6.852,6.794Zm0,10.882L96,101.549l2.433-3.008,6.852,6.794Zm.187,16.985c.317-.59.72-1.439,1.238-2.533a29.74,29.74,0,0,0,1.439-3.6,34.757,34.757,0,0,0,1.281-3.987,14.767,14.767,0,0,0,.547-3.714V87.4h28.788v4.1H111.255V111.5a17.965,17.965,0,0,1-.36,3.4,30.226,30.226,0,0,1-.921,3.527c-.374,1.152-.777,2.26-1.209,3.311s-.82,2-1.195,2.879-.691,1.439-.964,2l-.446.849Zm7.931-.1a34.386,34.386,0,0,0,2.116-4.059c.576-1.339,1.051-2.519,1.439-3.555a30.893,30.893,0,0,0,1.022-3.527l3.6.993s-.1.461-.288,1.18-.475,1.67-.878,2.879-.921,2.461-1.569,3.93a35.5,35.5,0,0,1-2.346,4.491Zm13.617-31.451-1.022,1.871h7.787v-.936h3.742v13.7a4.836,4.836,0,0,1-1.209,3.3,3.858,3.858,0,0,1-2.994,1.439H126.1v9.586a4.736,4.736,0,0,1-1.223,3.282,3.8,3.8,0,0,1-2.98,1.439h-2.749v-4.1h2.706a.576.576,0,0,0,.4-.144.6.6,0,0,0,.158-.417v-9.586h-8.953V95.648h5.758L121.46,91.6Zm6.765,6H117.128v2.792h14.178Zm-.518,9.27q.518,0,.518-.561v-1.814H117.128v2.375ZM132,113.827l4.433,11.8-3.4,1.5-4.318-11.8Z" transform="translate(41.997 38.403)" fill="#333"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.0 KiB |
|
@ -0,0 +1,292 @@
|
|||
import React, { useEffect, useState, useMemo } from 'react';
|
||||
// import { default as AntcodeCR } from 'acr';
|
||||
import { ACR } from 'alex';
|
||||
import { Button, Switch, Spin, Icon } from 'antd';
|
||||
// blame worker扩展
|
||||
import CodeBlame from './extensions/alex-ext-public.editor-plugin-blame.js';
|
||||
// 通过在plugin内调用扩展中的命令来进行外部交互
|
||||
import CodeBlamePlugin, { ExtensionCommand } from './plugins/code-blame.plugin';
|
||||
import { usePersistFn } from "ahooks";
|
||||
import {windowsOrMac} from 'educoder';
|
||||
|
||||
import {
|
||||
Provider,
|
||||
useGlobal,
|
||||
usePr,
|
||||
useNote,
|
||||
useReadMark,
|
||||
useAcr,
|
||||
useSetting,
|
||||
} from './model';
|
||||
import {
|
||||
DiscussionItem,
|
||||
Commenting,
|
||||
Menubar,
|
||||
AnnotationEntry,
|
||||
PRMoreActionLinks,
|
||||
} from './mock/component/index';
|
||||
import { projectService } from './mock/project.service';
|
||||
import { lsifService } from './mock/lsif.service';
|
||||
import { useFileReadMarkChange$ } from './hooks';
|
||||
import { repoService } from './mock/repo.service';
|
||||
import ideLogo from './ideLogo.svg';
|
||||
|
||||
|
||||
const CodeReview = (props) => {
|
||||
const { match: { params: { owner, projectsId, mergeId } }, projectDetail, current_user } = props;
|
||||
const [visible, setVisible] = React.useState(true);
|
||||
const [count, setCount] = React.useState(0);
|
||||
const [isFullscreen, setFullscreen] = React.useState(false);
|
||||
const { locale, setLocale, gbk, setGBK } = useSetting();
|
||||
const { commentPack } = useNote();
|
||||
const { project, user, setCurrent_user, setProjectDetail } = useGlobal();
|
||||
const { pr } = usePr();
|
||||
|
||||
|
||||
const {
|
||||
getFileReadStatus: _getFileReadStatus,
|
||||
markFileAsRead,
|
||||
markFileAsUnread,
|
||||
readMarks,
|
||||
} = useReadMark();
|
||||
// todo
|
||||
const getFileReadStatus = usePersistFn(_getFileReadStatus);
|
||||
// const getFileReadStatus = _getFileReadStatus;
|
||||
const {
|
||||
diffsPack,
|
||||
getDiffById,
|
||||
getFileContent,
|
||||
IDEMode,
|
||||
toggleViewerType,
|
||||
annotationPacks,
|
||||
setAcrFlag,
|
||||
} = useAcr();
|
||||
const fileReadMarkChange$ = useFileReadMarkChange$(
|
||||
diffsPack && diffsPack.diffs || [],
|
||||
readMarks
|
||||
);
|
||||
|
||||
// 插件激活
|
||||
const [pluginActivated, setPluginActivated] = useState(false);
|
||||
const blamePlugin = useMemo(() => {
|
||||
return new CodeBlamePlugin(
|
||||
() => setPluginActivated(true),
|
||||
(commitId) => {
|
||||
window.open(
|
||||
`/${owner}/${projectsId}/commit/${commitId}`
|
||||
)
|
||||
},
|
||||
// 获取blame数据
|
||||
(projectId, commitId, filepath) =>
|
||||
repoService.getCodeBlame(projectsId, owner, { sha: commitId, filepath })
|
||||
);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!pluginActivated) {
|
||||
return;
|
||||
}
|
||||
const projectData = {
|
||||
projectId: projectsId,
|
||||
prevSha: diffsPack.fromVersion && diffsPack.fromVersion.headCommitSha || diffsPack.toVersion.baseCommitSha,
|
||||
nextSha: diffsPack.toVersion.headCommitSha,
|
||||
};
|
||||
blamePlugin.commands && blamePlugin.commands.executeCommand(
|
||||
ExtensionCommand.setProjectData,
|
||||
projectData
|
||||
);
|
||||
// 取消语言服务
|
||||
blamePlugin.commands && blamePlugin.commands.executeCommand(
|
||||
'alex.setDefaultPreference',
|
||||
'acr.lsifEnabled',
|
||||
false
|
||||
);
|
||||
}, [pluginActivated, diffsPack]);
|
||||
|
||||
if (!diffsPack) {
|
||||
return <Spin style={{ height: "100vh" }} spinning={true}></Spin>
|
||||
}
|
||||
|
||||
function EditorEmpty() {
|
||||
const system=windowsOrMac();
|
||||
console.log(system);
|
||||
return <div className='ide-logo'>
|
||||
<img className='ide-logo-img' src={ideLogo} />
|
||||
<div>
|
||||
<div className='ide-logo-text'>IDE代码体验、高效的代码编辑</div>
|
||||
{/* <span className='ide-btn'>⇧</span> */}
|
||||
<div className='ide-logo-text'>标记文件为已查看 <span className='ide-btn'>{system==='mac'?'⌥':'Alt'}</span> <span className='ide-btn'>C</span> </div>
|
||||
<div className='ide-logo-text'>快速打开变更文件 <span className='ide-btn'>^</span> <span className='ide-btn'>{system==='mac'?'⌥':'Alt'}</span> <span className='ide-btn'>P</span></div>
|
||||
<div className='ide-logo-text'>切换变更文件 <span className='ide-btn'>{system==='mac'?'⌥':'Alt'}</span> <span className='ide-btn'>↑</span> / <span className='ide-btn'>↓</span></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
// <Icon className='ide-btn-demo' type="arrow-up" /> <Icon className='ide-btn-demo' type="arrow-down" />
|
||||
const propsIDE = {
|
||||
// 评审
|
||||
noteIdToReplyIdSet: commentPack.noteIdToReplyIdSet,
|
||||
// 增加的总行数
|
||||
addLineNum: diffsPack.addLineNum,
|
||||
// 删除的总行数
|
||||
deleteLineNum: diffsPack.delLineNum,
|
||||
// 上一个sha
|
||||
prevSha:
|
||||
diffsPack.fromVersion && diffsPack.fromVersion.headCommitSha || diffsPack.toVersion.baseCommitSha,
|
||||
// 下一个 sha
|
||||
nextSha: diffsPack.toVersion.headCommitSha,
|
||||
toggleViewerType,
|
||||
DiscussionItem,
|
||||
Commenting,
|
||||
getFileContent,
|
||||
lineToNoteIdSet: commentPack.lineToNoteIdSet,
|
||||
noteIdToNote: commentPack.noteIdToNote,
|
||||
noteUpdateFlag: commentPack.updateFlag,
|
||||
getDiffById,
|
||||
diffs: diffsPack.diffs,
|
||||
latestCommitSha: pr.diff.headCommitSha,
|
||||
projectId: projectsId,
|
||||
projectPath: `${owner}/${projectsId}`,
|
||||
pullRequestId: mergeId,
|
||||
pr,
|
||||
// 获取主语言
|
||||
getLanguages: () =>
|
||||
projectService
|
||||
.getLanguages(projectsId, {
|
||||
aggBy: 'file_extension',
|
||||
// 按照语言文件个数排序
|
||||
orderBy: 'count',
|
||||
size: 20,
|
||||
})
|
||||
.then((res) => res && Object.keys(res)),
|
||||
getFileReadStatus,
|
||||
fileReadMarkChange$,
|
||||
markFileAsRead,
|
||||
markFileAsUnread,
|
||||
bulkChangeFiles: (actions, header) => {
|
||||
|
||||
let files = [];
|
||||
for (const item of actions) {
|
||||
files.push({
|
||||
action_type: item.actionType,
|
||||
content: item.content,
|
||||
encoding: item.encoding,
|
||||
file_path: item.filePath,
|
||||
});
|
||||
}
|
||||
let data = {
|
||||
files: files,
|
||||
author_email: current_user.email,
|
||||
author_name: current_user.login,
|
||||
committer_email: current_user.email,
|
||||
committer_name: current_user.login,
|
||||
branch: header.branch,
|
||||
message: header.commitMessage,
|
||||
};
|
||||
|
||||
if (pr && pr.forkProject) {
|
||||
projectService.bulkChangeFiles(pr.forkProject.identifier, pr.forkProject.login, data).then(res => {
|
||||
if (res) {
|
||||
// gitea底层同步commit是异步,延迟查询才能获取修改后的结果
|
||||
setTimeout(() => {
|
||||
setAcrFlag({});
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
projectService.bulkChangeFiles(projectsId, owner, data).then(res => {
|
||||
if (res) {
|
||||
// gitea底层同步commit是异步,延迟查询才能获取修改后的结果
|
||||
setTimeout(() => {
|
||||
setAcrFlag({});
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
// 菜单栏
|
||||
Menubar: () => (
|
||||
<Menubar
|
||||
initialFullscreen={isFullscreen}
|
||||
handleFullscreenChange={setFullscreen}
|
||||
toggleViewerType={toggleViewerType}
|
||||
logFullScreen={(bool) => console.log('>>>logFullScreen', bool)}
|
||||
/>
|
||||
),
|
||||
user,
|
||||
lsifService,
|
||||
defaultEncoding: project.encoding,
|
||||
// 初始化 编码
|
||||
encoding: gbk ? 'gbk' : 'utf-8',
|
||||
// 设置编码
|
||||
setEncoding: (val) => {
|
||||
setGBK(val === 'gbk');
|
||||
},
|
||||
locale,
|
||||
annotations: annotationPacks,
|
||||
AnnotationEntry,
|
||||
PRMoreActionLinks,
|
||||
EditorEmpty: EditorEmpty,
|
||||
onigWasmUri: 'https://gw.alipayobjects.com/os/lib/vscode-oniguruma/1.6.2/release/onig.wasm',
|
||||
// 全屏模式
|
||||
isFullscreen,
|
||||
appConfig: {
|
||||
// 插件 在插件中调用扩展的命令
|
||||
plugins: [blamePlugin],
|
||||
// 扩展
|
||||
extensionMetadata: [CodeBlame],
|
||||
},
|
||||
};
|
||||
|
||||
const IDEContainerStyle = {
|
||||
position: isFullscreen ? 'fixed' : 'static',
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: '100%',
|
||||
height: isFullscreen ? '100vh' : 'calc(100vh - 72px)',
|
||||
zIndex: 1002,
|
||||
};
|
||||
|
||||
console.log('propsIDE:');
|
||||
console.log(propsIDE);
|
||||
return (
|
||||
|
||||
<div style={{ height: '100%', lineHeight: '1.4' }}>
|
||||
{/* <EditorEmpty></EditorEmpty> */}
|
||||
{/* <div className="controller">
|
||||
{!IDEMode && (
|
||||
<>
|
||||
IDE 模式: <Switch checked={IDEMode} onChange={toggleViewerType} />
|
||||
</>
|
||||
)}
|
||||
</div> */}
|
||||
{/* <div className="pr-head">
|
||||
<div>{pr.description}</div>
|
||||
<div>
|
||||
评审人:
|
||||
{pr.review && pr.review.reviewers && pr.review.reviewers.map((r) => (
|
||||
<span style={{ marginRight: 4 }} key={r.id}>
|
||||
{r.name}
|
||||
</span>
|
||||
))}
|
||||
<span style={{ marginRight: 24 }}></span>
|
||||
合并人:{pr.assignee && pr.assignee.name}
|
||||
</div>
|
||||
</div> */}
|
||||
{IDEMode && (
|
||||
<div style={IDEContainerStyle}>
|
||||
{visible && <ACR {...propsIDE} key={count} />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const CodeReviewP = (props) => {
|
||||
return (
|
||||
<Provider {...props}><CodeReview {...props} /></Provider>
|
||||
)
|
||||
}
|
||||
export default CodeReviewP;
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
export const group = 'Gitlink';
|
||||
export const repo = 'forgeplus';
|
||||
export const prIid = '2';
|
||||
|
||||
export const project = `${group}/${repo}`;
|
|
@ -0,0 +1,67 @@
|
|||
import { request } from './request/index';
|
||||
|
||||
export const apiService = {
|
||||
get(
|
||||
url,
|
||||
query,
|
||||
options = {}
|
||||
) {
|
||||
return request(
|
||||
url,
|
||||
{
|
||||
method: 'GET',
|
||||
params: query,
|
||||
},
|
||||
options
|
||||
);
|
||||
},
|
||||
|
||||
post(
|
||||
url,
|
||||
query,
|
||||
body,
|
||||
options= {}
|
||||
) {
|
||||
return request(
|
||||
url,
|
||||
{
|
||||
method: 'POST',
|
||||
params: query,
|
||||
data: body,
|
||||
},
|
||||
options
|
||||
);
|
||||
},
|
||||
|
||||
put(
|
||||
url,
|
||||
query,
|
||||
body,
|
||||
options= {}
|
||||
) {
|
||||
return request(
|
||||
url,
|
||||
{
|
||||
method: 'PUT',
|
||||
params: query,
|
||||
data: body,
|
||||
},
|
||||
options
|
||||
);
|
||||
},
|
||||
|
||||
delete(
|
||||
url,
|
||||
query,
|
||||
options = {}
|
||||
) {
|
||||
return request(
|
||||
url,
|
||||
{
|
||||
method: 'DELETE',
|
||||
params: query,
|
||||
},
|
||||
options
|
||||
);
|
||||
},
|
||||
};
|
|
@ -0,0 +1,601 @@
|
|||
import React, {
|
||||
FC,
|
||||
MutableRefObject,
|
||||
memo,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
useCallback,
|
||||
Fragment,
|
||||
} from "react";
|
||||
import {
|
||||
message,
|
||||
Dropdown,
|
||||
Icon,
|
||||
Menu,
|
||||
Button,
|
||||
Tooltip,
|
||||
Avatar,
|
||||
Modal,
|
||||
Switch,
|
||||
Input,
|
||||
Popconfirm,
|
||||
Checkbox,
|
||||
} from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import { usePersistFn } from "ahooks";
|
||||
import { getImageUrl, timeAgo } from "educoder";
|
||||
import "./style.module.less";
|
||||
import { useAcr, useNote, useGlobal, usePr } from "../../model";
|
||||
const AnnotationStatus = {
|
||||
Init: 'Init',
|
||||
Ignore: 'Ignore',
|
||||
Confirm: 'Confirm',
|
||||
FalsePositive: 'FalsePositive',
|
||||
}
|
||||
const noteType = {
|
||||
comment: 'comment',
|
||||
problem: 'problem',
|
||||
}
|
||||
|
||||
export const Commenting = (props) => {
|
||||
const { user } = useGlobal();
|
||||
const { addComment } = useNote();
|
||||
const { toVersion, stDiff } = useAcr();
|
||||
const submit = usePersistFn(async (note, type) => {
|
||||
try {
|
||||
console.log(note, type);
|
||||
await addComment({
|
||||
note,
|
||||
diffId: toVersion.id,
|
||||
line_code: props.lineCode,
|
||||
parent_id: props.id,
|
||||
path: props.path,
|
||||
type: type || 'comment',
|
||||
diff: props.id ? null : stDiff,
|
||||
});
|
||||
props.onClose && props.onClose();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
const { replyNote } = props;
|
||||
|
||||
const [note, setNote] = useState("");
|
||||
const [isProblem, setIsProblem] = useState(false);
|
||||
|
||||
const onSubmit = useCallback(() => {
|
||||
const submitNote = replyNote ? insertReplyNote(note, replyNote) : note;
|
||||
submit(submitNote, isProblem ? noteType.problem : noteType.comment);
|
||||
}, [note, replyNote, isProblem]);
|
||||
|
||||
function insertReplyNote(baseNote, replyNote) {
|
||||
if (replyNote && replyNote.note) {
|
||||
const replyLine = replyNote.note.split("\n");
|
||||
const blockquoteNote = [
|
||||
`<!-- reply id="${replyNote.id}" -->`,
|
||||
...replyLine,
|
||||
]
|
||||
.map((note) => `> ${note}`)
|
||||
.join("\n");
|
||||
return blockquoteNote + "\n\n" + baseNote;
|
||||
} else {
|
||||
return baseNote;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
// <div className="arc-container">
|
||||
<div
|
||||
className={`arc-commenting-container ${props.noPadding ? "no-padding" : ""}`}>
|
||||
<div className="avatar">
|
||||
<Tooltip title={user.name}>
|
||||
<Avatar src={user && user.image_url
|
||||
? getImageUrl(`/${user.image_url}`)
|
||||
: "images/avatars/User/b"} size={24} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Input.TextArea
|
||||
autoFocus
|
||||
placeholder="请输入评论信息"
|
||||
value={note}
|
||||
onChange={(e) => setNote(e.target.value)}
|
||||
style={{ height: 150 }}
|
||||
/>
|
||||
<div className="action">
|
||||
<div>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={onSubmit}
|
||||
disabled={!note.trim()}
|
||||
style={{ marginRight: 8 }}
|
||||
>
|
||||
评论
|
||||
</Button>
|
||||
{note.trim() ? (
|
||||
<Popconfirm
|
||||
title="你确定要取消?"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
onConfirm={props.onClose}
|
||||
>
|
||||
<Button>取消</Button>
|
||||
</Popconfirm>
|
||||
) : (
|
||||
<Button onClick={props.onClose}>取消</Button>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{replyNote && (
|
||||
<div className="reply-note">Reply to {replyNote.author.name}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
// </div>
|
||||
);
|
||||
};
|
||||
|
||||
const ReplyItem = memo(({ note, isChild }) => {
|
||||
const { user } = useGlobal();
|
||||
const { deleteComment } = useNote();
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
return <div className={`reply-item ${isChild ? 'reply-item-child' : ''}`}>
|
||||
<div className="reply-item-head">
|
||||
<Link
|
||||
to={`/${note.user && note.user.login}`}
|
||||
className="show-user-link"
|
||||
>
|
||||
<Avatar src={note.user && note.user.imageUrl
|
||||
? getImageUrl(`/${note.user.imageUrl}`)
|
||||
: "images/avatars/User/b"} size={24} />
|
||||
</Link>
|
||||
<Link
|
||||
to={`/${note.user && note.user.login}`}
|
||||
className="show-user-link color-black ml10 fwb"
|
||||
>
|
||||
{note.user && note.user.username}
|
||||
</Link> 于 <span className="show-user-link color-black">{timeAgo(note.createdAt)}</span> 发表评论:
|
||||
<span className="btn-right">
|
||||
{user &&
|
||||
(user.admin ||
|
||||
user.login === note.user.login) ? (
|
||||
<Popconfirm
|
||||
placement="bottom"
|
||||
title={"确定要删除当前评论吗?"}
|
||||
okText="是"
|
||||
cancelText="否"
|
||||
onConfirm={() => deleteComment(note.id)}
|
||||
>
|
||||
<Button type="link">
|
||||
<i className="iconfont icon-shanchu3 font-15 color-grey-6 mr5 ver-middle"></i>
|
||||
<span className="font-12 color-grey-6">删除</span>
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
{!isChild ? <Button
|
||||
type="link"
|
||||
className="ml-10"
|
||||
onClick={() => setVisible(true)}
|
||||
>
|
||||
<i className="iconfont icon-huifu1 font-15 color-grey-6 mr5 ver-middle"></i>
|
||||
<span className="font-12 color-grey-6">回复</span>
|
||||
</Button> : ''}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="reply-item-content">{note.note}</div>
|
||||
{visible && <Commenting style={{ paddingLeft: '20px' }} onClose={() => { setVisible(false) }} {...note} />}
|
||||
</div>
|
||||
})
|
||||
|
||||
export const DiscussionItem = memo((props) => {
|
||||
const { noteId } = props;
|
||||
const { commentPack, deleteComment } = useNote();
|
||||
|
||||
// const [commenting, setCommenting] = useState(false);
|
||||
// const [commentReply, setCommentReply] = useState();
|
||||
|
||||
const replyIdSet = commentPack.noteIdToReplyIdSet.get(noteId);
|
||||
const replyIds = replyIdSet
|
||||
? Array.from(replyIdSet).sort((a, b) => a - b)
|
||||
: null;
|
||||
|
||||
// const pending = (function () {
|
||||
// if (!commentPack.hasPendingReview) {
|
||||
// return false;
|
||||
// }
|
||||
// const reviewId = commentPack.noteIdToReviewId.get(noteId);
|
||||
// if (!reviewId) return false;
|
||||
// const review = reviewId ? commentPack.reviewIdToReview.get(reviewId) : null;
|
||||
// if (!review) return false;
|
||||
// return review.pending;
|
||||
// })();
|
||||
// const hasPendingNote = (function () {
|
||||
// if (pending) return true;
|
||||
// if (replyIds) {
|
||||
// for (const replyId of replyIds) {
|
||||
// const reviewId = commentPack.noteIdToReviewId.get(replyId);
|
||||
// if (reviewId && commentPack.reviewIdToReview.get(reviewId) && commentPack.reviewIdToReview.get(reviewId).pending) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// })();
|
||||
|
||||
// const handleReply = (replyNote) => {
|
||||
// if (replyNote) {
|
||||
// setCommentReply(replyNote);
|
||||
// }
|
||||
// setCommenting(true);
|
||||
// };
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!commenting) {
|
||||
// setCommentReply(undefined);
|
||||
// }
|
||||
// }, [commenting]);
|
||||
|
||||
|
||||
const note = commentPack.noteIdToNote.get(noteId);
|
||||
if (!note) return null;
|
||||
|
||||
// console.log('note');
|
||||
// console.log(note);
|
||||
return (
|
||||
<div className="arc-container">
|
||||
{/* <div>
|
||||
{note.type === noteType.problem && (
|
||||
<Fragment>
|
||||
{note.state === "resolved" && !pending && "已解决"}
|
||||
{note.state === "opened" && !pending && "待解决"}
|
||||
{pending && "需要回应"}
|
||||
</Fragment>
|
||||
)}
|
||||
</div> */}
|
||||
<ReplyItem note={note} />
|
||||
|
||||
{replyIds && (
|
||||
<div style={{ paddingLeft: 50 }}>
|
||||
{replyIds.reverse().map((replyId) => {
|
||||
const note = commentPack.noteIdToNote.get(replyId);
|
||||
if (!note) return null;
|
||||
return <ReplyItem note={note} key={replyId} isChild={true} />
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export const Menubar = memo((props) => {
|
||||
const [isFullscreen, setFullscreen] = React.useState(
|
||||
props.initialFullscreen || false
|
||||
);
|
||||
const handleChangeFullscreen = (isFullscreen) => {
|
||||
setFullscreen(isFullscreen);
|
||||
if (isFullscreen) {
|
||||
message.info("全屏模式支持直接使用 ↑/↓ 切换变更文件");
|
||||
}
|
||||
props.handleFullscreenChange(isFullscreen);
|
||||
props.logFullScreen(isFullscreen);
|
||||
};
|
||||
useEffect(() => {
|
||||
if (isFullscreen) {
|
||||
document.body.style.overflow = "hidden";
|
||||
}
|
||||
return () => {
|
||||
document.body.style.overflow = "";
|
||||
};
|
||||
}, [isFullscreen]);
|
||||
|
||||
const { versions, fromVersion, toVersion, updateQuery } = useAcr();
|
||||
|
||||
const idToVerbose = new Map();
|
||||
idToVerbose.set(0, "Base Version");
|
||||
|
||||
|
||||
versions.forEach((version, index) => {
|
||||
if (index === versions.length - 1) {
|
||||
idToVerbose.set(version.id, `Latest Version`);
|
||||
} else {
|
||||
idToVerbose.set(version.id, `Version ${versions.length - index - 1}`);
|
||||
}
|
||||
});
|
||||
|
||||
const fromId = fromVersion && fromVersion.id || 0;
|
||||
const toId = toVersion && toVersion.id || 0;
|
||||
|
||||
const filterCleared = fromId === 0 && toId === versions[0] && versions[0].id;
|
||||
|
||||
function renderMenuItem(version, selectedId) {
|
||||
const verbose = idToVerbose.get(version.id);
|
||||
return (
|
||||
<Menu.Item
|
||||
className={`arc-menuItem ${version.id === selectedId ? "selected" : ""
|
||||
}`}
|
||||
key={version.id}
|
||||
>
|
||||
<div className='headRow'>
|
||||
<span>{verbose}</span>
|
||||
<span>{version.headCommitSha.slice(0, 8)}</span>
|
||||
</div>
|
||||
<div className='desc'>
|
||||
包含 {version.commitsCount}次提交,{version.filesCount} 份文件变更
|
||||
</div>
|
||||
</Menu.Item>
|
||||
);
|
||||
}
|
||||
|
||||
const menuFrom = (
|
||||
<Menu
|
||||
onClick={(e) => {
|
||||
const val = parseInt(e.key);
|
||||
updateQuery({
|
||||
from: val === 0 ? undefined : val,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{versions.slice(1).map((version) => renderMenuItem(version, fromId))}
|
||||
<Menu.Item
|
||||
key={0}
|
||||
className={`${'menuItem'} ${fromId === 0 ? 'selected' : ""}`}
|
||||
>
|
||||
Base Version
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const menuTo = (
|
||||
<Menu
|
||||
onClick={(e) => {
|
||||
updateQuery({
|
||||
to: parseInt(e.key),
|
||||
});
|
||||
}}
|
||||
>
|
||||
{versions
|
||||
.slice(0, versions.length)
|
||||
.map((version) => renderMenuItem(version, toId))}
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const MenuStyle = {
|
||||
zIndex: 1200,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="arc-menubar">
|
||||
<div className={'group'}>
|
||||
{versions.length !== 0 && (
|
||||
<div className={'versionContainer'}>
|
||||
<Dropdown overlay={menuFrom} trigger={["click"]} overlayStyle={MenuStyle}>
|
||||
<div className={'versionItem'}>
|
||||
<span>{idToVerbose.get(fromId)}</span>
|
||||
<Icon type="down" />
|
||||
</div>
|
||||
</Dropdown>
|
||||
<div>
|
||||
<Icon type="arrow-right" />
|
||||
</div>
|
||||
<Dropdown overlay={menuTo} trigger={["click"]} overlayStyle={MenuStyle}>
|
||||
<div className={'versionItem'}>
|
||||
<span>{idToVerbose.get(toId)}</span>
|
||||
<Icon type="down" />
|
||||
</div>
|
||||
</Dropdown>
|
||||
|
||||
{!filterCleared && (
|
||||
<div>
|
||||
<a
|
||||
onClick={() => {
|
||||
updateQuery({
|
||||
from: undefined,
|
||||
to: undefined,
|
||||
});
|
||||
}}
|
||||
>
|
||||
重置
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className={'group'}>
|
||||
{/* {isFullscreen ? null : (
|
||||
<div className={'switchContainer'}>
|
||||
<span className={'ideLabel'}>IDE 模式</span>
|
||||
<Tooltip
|
||||
placement="top"
|
||||
title="提供 IDE 代码浏览体验、完善的语言服务和高效的代码编辑"
|
||||
>
|
||||
<Switch checked onChange={props.toggleViewerType} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
)} */}
|
||||
{isFullscreen ? (
|
||||
<Icon
|
||||
type="fullscreen-exit"
|
||||
onClick={() => handleChangeFullscreen(false)}
|
||||
/>
|
||||
) : (
|
||||
<Tooltip title="全屏">
|
||||
<Icon
|
||||
type="fullscreen"
|
||||
onClick={() => handleChangeFullscreen(true)}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export const AnnotationEntry = memo((props) => {
|
||||
const { annotation, checkSuite } = props;
|
||||
|
||||
// 定位
|
||||
const anchorOffsetRef = useRef(null);
|
||||
const hash = `#annotation_${annotation.id}`;
|
||||
const hashActive = hash === window.location.hash;
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
if (hashActive) {
|
||||
anchorOffsetRef.current && anchorOffsetRef.current.scrollIntoView(true);
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
|
||||
const [isIgnore, setIsIgnore] = useState(
|
||||
annotation.feedBackStatus === AnnotationStatus.Ignore
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="arc-container">
|
||||
<div
|
||||
ref={anchorOffsetRef}
|
||||
id={`annotation_${annotation.id}`}
|
||||
className="arc-annotationContainer"
|
||||
>
|
||||
<div className={'codeLine'}>
|
||||
<div>{annotation.level}</div>
|
||||
<div className={'line'}>
|
||||
{annotation.startLine === annotation.endLine ? (
|
||||
<span>
|
||||
对{annotation.endLine}
|
||||
行代码分析
|
||||
</span>
|
||||
) : (
|
||||
<span>
|
||||
对{annotation.startLine}到{annotation.endLine}
|
||||
行代码分析
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={'botRow'}>
|
||||
<Avatar
|
||||
alt={checkSuite.service.nameShow}
|
||||
size={20}
|
||||
src="https://gw-office.alipayobjects.com/bmw-prod/a9596840-928c-4603-a865-b24373ab4b4d.png"
|
||||
/>
|
||||
<div>
|
||||
<div className={'strong'}>{checkSuite.service.nameShow}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={'content'}>
|
||||
<p>{annotation.title}</p>
|
||||
<div>{annotation.message}</div>
|
||||
</div>
|
||||
<div className={'detail'}>
|
||||
<div>
|
||||
{annotation.bugId ? (
|
||||
isIgnore ? (
|
||||
<Button type="primary" style={{ marginRight: 8 }}>
|
||||
取消忽略
|
||||
</Button>
|
||||
) : (
|
||||
<Fragment>
|
||||
<Button style={{ marginRight: 8 }}>忽略</Button>
|
||||
<Button style={{ marginRight: 8 }}>误报</Button>
|
||||
<Button>确认</Button>
|
||||
</Fragment>
|
||||
)
|
||||
) : null}
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
className={'halfPlainA'}
|
||||
href={`https://codeinsightapi.alipay.com/api/v1/describe?bug_type=${annotation.bugType}&bug_id=${annotation.bugId}`}
|
||||
target="_blank"
|
||||
>
|
||||
查看问题详情 <Icon type="double-right" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export const PRMoreActionLinks = ({
|
||||
setVisible,
|
||||
}) => {
|
||||
const { pr } = usePr();
|
||||
const { project } = useGlobal();
|
||||
const [checkoutBranchVisible, setCheckoutBranchVisible] = useState(false);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div>正在丰富功能中...</div>
|
||||
<div style={{display:'none'}}>
|
||||
<Switch checked />
|
||||
</div>
|
||||
{/* <div
|
||||
className="arc-checkoutBranch"
|
||||
onClick={() => {
|
||||
setCheckoutBranchVisible(true);
|
||||
setVisible(false);
|
||||
}}
|
||||
>
|
||||
检出分支
|
||||
</div>
|
||||
<a
|
||||
className="arc-flexA"
|
||||
download
|
||||
href={`http://code.test.alipay.net/${project.pathWithNamespace}/pull_requests/${pr.iid}.patch`}
|
||||
>
|
||||
<span onClick={() => setVisible(false)}>下载 patch 文件</span>
|
||||
</a>
|
||||
<a
|
||||
className="arc-flexA"
|
||||
download
|
||||
href={`http://code.test.alipay.net/${project.pathWithNamespace}/pull_requests/${pr.iid}.diff`}
|
||||
>
|
||||
<span onClick={() => setVisible(false)}>下载 diff 文件</span>
|
||||
</a>
|
||||
<Modal
|
||||
title="检出,评审,并在本地执行合并"
|
||||
visible={checkoutBranchVisible}
|
||||
footer={null}
|
||||
onCancel={() => setCheckoutBranchVisible(false)}
|
||||
>
|
||||
<div className="arc-checkout">
|
||||
<p>
|
||||
<span className="fw">Step 1.</span> Fetch and check out the branch
|
||||
for this pull request
|
||||
</p>
|
||||
<pre>
|
||||
git fetch origin
|
||||
<br />
|
||||
{`git checkout -b ${pr.sourceBranch} origin/${pr.sourceBranch}`}
|
||||
</pre>
|
||||
<p>
|
||||
<span className="fw">Step 2.</span> Review the changes locally
|
||||
</p>
|
||||
<p>
|
||||
<span className="fw">Step 3.</span> Merge the branch and fix any
|
||||
conflicts that come up
|
||||
</p>
|
||||
<pre>
|
||||
git fetch origin
|
||||
<br />
|
||||
{`git checkout origin/${pr.targetBranch}`}
|
||||
<br />
|
||||
git merge --no-ff master
|
||||
</pre>
|
||||
<p>
|
||||
<span className="fw">Step 4.</span> Push the result of the merge
|
||||
</p>
|
||||
<pre>{`git push origin ${pr.targetBranch}`}</pre>
|
||||
</div>
|
||||
</Modal> */}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,219 @@
|
|||
|
||||
.arc-container {
|
||||
padding:5px 0 10px;
|
||||
border-bottom: solid 1px #eee;
|
||||
.reply-item{
|
||||
padding:6px 16px 10px;
|
||||
|
||||
&.reply-item-child{
|
||||
margin-top:-10px;
|
||||
padding:5px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.reply-item-head{
|
||||
line-height: 30px;
|
||||
color: #666;
|
||||
}
|
||||
.btn-right{
|
||||
float: right;
|
||||
}
|
||||
.reply-item-content{
|
||||
padding-left:35px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.show-user-link{
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.arc-menubar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> * {
|
||||
margin-right: 12px;
|
||||
transition: 300ms all ease-in-out;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.versionContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
> *:not(:last-child) {
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.versionItem {
|
||||
cursor: pointer;
|
||||
padding: 4px 6px;
|
||||
.anticon {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.switchContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ideLabel {
|
||||
line-height: 1;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.arc-menuItem {
|
||||
background: #ffffff;
|
||||
width: 350px;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
&.selected {
|
||||
background: #f0f5ff;
|
||||
}
|
||||
|
||||
.headRow {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.desc {
|
||||
margin-top: 2px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
}
|
||||
|
||||
.arc-annotationContainer {
|
||||
border-bottom: solid 1px #eee;
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.codeLine {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.line {
|
||||
padding-top: 8px;
|
||||
padding-left: 8px;
|
||||
font-size: 12px;
|
||||
&.active {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
}
|
||||
|
||||
.botRow {
|
||||
padding: 8px 12px 0 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
> *:not(:first-child) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 8px 12px 12px 48px;
|
||||
p {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.strong {
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
|
||||
.detail {
|
||||
height: 50px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
padding: 0 21px;
|
||||
border-top: 1px solid #ebedf0;
|
||||
}
|
||||
|
||||
.halfPlainA {
|
||||
color: inherit;
|
||||
&:hover {
|
||||
color: #2f54eb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.arc-checkoutBranch {
|
||||
font-size: 14px;
|
||||
color: #2f54eb;
|
||||
cursor: pointer;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.arc-flexA {
|
||||
display: flex !important;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
line-height: 32px;
|
||||
color: #2f54eb;
|
||||
|
||||
i {
|
||||
color: #2f54eb;
|
||||
}
|
||||
&:hover {
|
||||
color: #2f54eb;
|
||||
}
|
||||
}
|
||||
|
||||
.arc-checkout {
|
||||
pre {
|
||||
margin-bottom: 8px;
|
||||
padding: 8px 12px;
|
||||
background-color: #fbfbfb;
|
||||
border: 1px solid #ebedf0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.arc-commenting-container {
|
||||
position: relative;
|
||||
padding: 8px 12px 0 44px;
|
||||
|
||||
&.no-padding {
|
||||
padding: 0 0 0 32px;
|
||||
|
||||
.avatar {
|
||||
top: 2px;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 12px;
|
||||
}
|
||||
|
||||
.action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 0;
|
||||
|
||||
.reply-note {
|
||||
padding: 1px 5px;
|
||||
color: #8c8c8c;
|
||||
line-height: 20px;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
import { apiService } from './api.service';
|
||||
|
||||
// 语言服务接口
|
||||
export const lsifService = {
|
||||
async lsifExists(projectPath, sha) {
|
||||
return !!(await apiService.post(
|
||||
`/webapi/projects/${encodeURIComponent(
|
||||
projectPath
|
||||
)}/repository/lsif/exists`,
|
||||
{
|
||||
sha,
|
||||
}
|
||||
)) ;
|
||||
},
|
||||
|
||||
async lsifHover(
|
||||
projectId,
|
||||
data
|
||||
) {
|
||||
return (await apiService.post(
|
||||
`/webapi/projects/42422/repository/lsif/hover`,
|
||||
undefined,
|
||||
{
|
||||
...data,
|
||||
method: 'hover',
|
||||
}
|
||||
))
|
||||
},
|
||||
|
||||
async lsifDefinitions(
|
||||
projectId,
|
||||
data
|
||||
) {
|
||||
return (await apiService.post(
|
||||
`/webapi/projects/42422/repository/lsif/definitions`,
|
||||
undefined,
|
||||
data
|
||||
))
|
||||
},
|
||||
|
||||
async lsifReferences(
|
||||
projectId,
|
||||
data
|
||||
) {
|
||||
return (await apiService.post(
|
||||
`/webapi/projects/42422/repository/lsif/references`,
|
||||
undefined,
|
||||
data,
|
||||
{
|
||||
disableBodyConvert: true,
|
||||
}
|
||||
))
|
||||
},
|
||||
|
||||
async lsifReferencesV2(
|
||||
projectId,
|
||||
data
|
||||
) {
|
||||
return (await apiService.post(
|
||||
`/webapi/projects/42422/repository/lsif/reference/v2`,
|
||||
undefined,
|
||||
data,
|
||||
{
|
||||
disableBodyConvert: true,
|
||||
}
|
||||
))
|
||||
},
|
||||
};
|
|
@ -0,0 +1,197 @@
|
|||
import { apiService } from './api.service';
|
||||
import { message } from 'antd';
|
||||
import { getImageUrlAbsolute } from "educoder";
|
||||
import { calcChangeLineNum } from './utils/calc-change-line-num';
|
||||
import { underscoreToCamelcase } from './utils/camelcase-convert';
|
||||
import axios from 'axios';
|
||||
import sha1 from 'sha1';
|
||||
|
||||
export const prService = {
|
||||
async getPRByIid(projectsId, owner, mergeId) {
|
||||
const res = await axios.get(`/v1/${owner}/${projectsId}/pulls/${mergeId}.json`);
|
||||
let data = underscoreToCamelcase(res.data);
|
||||
let newData = {
|
||||
...data,
|
||||
checkSuites: [],
|
||||
iid: data.index,
|
||||
sourceBranch: data.head,
|
||||
sourceProjectId: projectsId,
|
||||
// state: "opened",
|
||||
// targetBranch: "master",
|
||||
// targetProjectId: 42422,
|
||||
diff: {
|
||||
baseCommitSha: data.baseCommitSha,
|
||||
commitsCount: data.commitNum,
|
||||
headCommitSha: data.headCommitSha,
|
||||
startCommitSha: data.mergeBase,
|
||||
// delLineNum: 379,
|
||||
// addLineNum: 753,
|
||||
// createdAt: "2021-05-20T14:27:46+0800",
|
||||
// filesCount: 22,
|
||||
// overflow: false,
|
||||
// startCommitSha: "2566c6dec7756e51f7f16267d9a2a63116ac015b",
|
||||
// updatedAt: "2021-05-20T14:27:46+0800",
|
||||
},
|
||||
|
||||
};
|
||||
return newData;
|
||||
},
|
||||
|
||||
async getDiffVersions(projectsId, owner, mergeId) {
|
||||
const res = await axios.get(`/v1/${owner}/${projectsId}/pulls/${mergeId}/versions.json`);
|
||||
return Array.isArray(res.data.versions) ? underscoreToCamelcase(res.data.versions) : [];
|
||||
},
|
||||
|
||||
async getDiffs(
|
||||
projectId,
|
||||
owner,
|
||||
from,
|
||||
to,
|
||||
) {
|
||||
const res = await axios.get(`/v1/${owner}/42422/compare.json`, { params: { from, to } })
|
||||
const changeLineNum = calcChangeLineNum(res.diffs);
|
||||
return {
|
||||
...res,
|
||||
...changeLineNum,
|
||||
};
|
||||
},
|
||||
|
||||
async getDiffOverviews(projectsId, owner, mergeId, versionId) {
|
||||
const res = await axios.get(`/v1/${owner}/${projectsId}/pulls/${mergeId}/versions/${versionId}/diff.json`);
|
||||
let files = res.data.files;
|
||||
for (const [i, item] of files.entries()) {
|
||||
// item.aMode= "100644";
|
||||
// item.bMode= "0";
|
||||
// item.markAsRead= true;
|
||||
// item.tooLarge= false;
|
||||
// item.updatedAfterRead= false;
|
||||
|
||||
item.compareDiffId = versionId;
|
||||
item.id = item.name;
|
||||
item.addLineNum = item.addition;
|
||||
item.binaryFile = item.is_bin;
|
||||
item.delLineNum = item.deletion;
|
||||
item.deletedFile = item.is_deleted;
|
||||
item.newFile = item.is_created;
|
||||
item.newPath = item.name;
|
||||
item.oldPath = item.oldname;
|
||||
item.renamedFile = item.is_renamed;
|
||||
}
|
||||
return Array.isArray(res.data.files) ? underscoreToCamelcase(res.data.files) : []
|
||||
},
|
||||
|
||||
async getCommentPack(projectsId, owner, mergeId,params) {
|
||||
const res = await axios.get(`/v1/${owner}/${projectsId}/pulls/${mergeId}/journals.json`,{params});
|
||||
let journals=underscoreToCamelcase(res.data.journals);
|
||||
for(const item of journals){
|
||||
item.author=item.user;
|
||||
item.author.avatarUrl=item.user.imageUrl?getImageUrlAbsolute(item.user.imageUrl):'';
|
||||
item.author.username=item.user.name;
|
||||
item.type='Common';
|
||||
item.stDiff=item.diff;
|
||||
item.discussionId=item.parentId
|
||||
// item.lineType='old';
|
||||
}
|
||||
return journals;
|
||||
},
|
||||
|
||||
async editPRComment(projectsId, owner, mergeId, noteId, data) {
|
||||
const res = await axios.patch(`/v1/${owner}/${projectsId}/pulls/${mergeId}/journals/${noteId}.json`, data);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async getDiffById(
|
||||
projectsId, owner, mergeId, versionId,
|
||||
params = {}
|
||||
) {
|
||||
const res = await axios.get(`/v1/${owner}/${projectsId}/pulls/${mergeId}/versions/${versionId}/diff.json`, { params });
|
||||
|
||||
let data = res.data;
|
||||
data.compareDiffId = versionId;
|
||||
data.id = data.name;
|
||||
data.addLineNum = data.addition;
|
||||
data.binaryFile = data.is_bin;
|
||||
data.delLineNum = data.deletion;
|
||||
data.deletedFile = data.is_deleted;
|
||||
data.newFile = data.is_created;
|
||||
data.newPath = data.name;
|
||||
data.oldPath = data.oldname;
|
||||
data.renamedFile = data.is_renamed;
|
||||
return data;
|
||||
},
|
||||
|
||||
async getFileReadMarks(projectsId, owner, mergeId,) {
|
||||
const res = await axios.get(`/${owner}/${projectsId}/pulls/${mergeId}/diffs/mark_files.json`);
|
||||
let data=[];
|
||||
for (const item of res.data.files) {
|
||||
if(item.mark_as_read){
|
||||
item.newPath = item.name;
|
||||
item.file_path_sha2 = item.file_path_sha;
|
||||
item.file_path_sha = sha1(item.newPath);
|
||||
data.push(item);
|
||||
}
|
||||
}
|
||||
return underscoreToCamelcase(data);
|
||||
},
|
||||
|
||||
async markFileAsRead(projectsId, owner, mergeId, data) {
|
||||
const res = await axios.put(`/${owner}/${projectsId}/pulls/${mergeId}/diffs/mark_file_as_read.json`, data);
|
||||
return res.data;
|
||||
},
|
||||
async markFileAsUnread(projectsId, owner, mergeId, data) {
|
||||
const res = await axios.put(`/${owner}/${projectsId}/pulls/${mergeId}/diffs/mark_file_as_unread.json`, data);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async addComment(projectsId, owner, mergeId, data) {
|
||||
const res = await axios.post(`/v1/${owner}/${projectsId}/pulls/${mergeId}/journals.json`, data);
|
||||
let commentData=underscoreToCamelcase(res.data);
|
||||
commentData.author=commentData.user;
|
||||
commentData.author.avatarUrl=commentData.user.imageUrl?getImageUrlAbsolute(commentData.user.imageUrl):'';
|
||||
commentData.author.username=commentData.user.name;
|
||||
commentData.type='Common';
|
||||
commentData.stDiff=commentData.diff;
|
||||
commentData.discussionId=commentData.parentId
|
||||
return commentData;
|
||||
},
|
||||
|
||||
async deleteComment(projectsId, owner, mergeId,id){
|
||||
const res = await axios.delete(`/v1/${owner}/${projectsId}/pulls/${mergeId}/journals/${id}.json`);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async createReview(projectsId, owner, mergeId, data) {
|
||||
const res = await axios.post(`/v1/${owner}/${projectsId}/pulls/${mergeId}/reviews.json`, data);
|
||||
console.log('createReview--data');
|
||||
if (res.data.id) {
|
||||
return res.data;
|
||||
} else {
|
||||
message.error(res.data && res.data.message);
|
||||
}
|
||||
},
|
||||
|
||||
async getReviews(projectsId, owner, mergeId,) {
|
||||
const res = await axios.get(`/v1/${owner}/${projectsId}/pulls/${mergeId}/reviews.json`,);
|
||||
let reviews=underscoreToCamelcase(res.data.reviews);
|
||||
for(const item of reviews){
|
||||
item.author=item.reviewer;
|
||||
item.author.avatarUrl=getImageUrlAbsolute(item.reviewer.imageUrl);
|
||||
item.author.username=item.reviewer.name;
|
||||
item.author.webUrl='';
|
||||
item.body=item.content;
|
||||
item.pending=false;
|
||||
item.pullRequestId=mergeId;
|
||||
}
|
||||
return reviews;
|
||||
},
|
||||
|
||||
async commitReview(projectsId, owner, mergeId, body) {
|
||||
return await apiService.put(
|
||||
`/api/v3/projects/42422/pull_requests/13055/reviews`,
|
||||
undefined,
|
||||
{
|
||||
body,
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
|
@ -0,0 +1,41 @@
|
|||
import { apiService } from './api.service';
|
||||
import { underscoreToCamelcase } from './utils/camelcase-convert';
|
||||
import axios from 'axios';
|
||||
|
||||
export const projectService = {
|
||||
async getUser() {
|
||||
return apiService.get(`/api/v3/user`);
|
||||
},
|
||||
|
||||
async getProject(namespace, projectName) {
|
||||
return (await apiService.get(
|
||||
`/webapi/projects/${namespace}/${projectName}/`
|
||||
))
|
||||
},
|
||||
|
||||
async getFileBlob(projectsId, owner,options={}) {
|
||||
const res = await axios.get(`/${owner}/${projectsId}/sub_entries.json`,{params:options});
|
||||
return res.data.entries.content;
|
||||
},
|
||||
|
||||
|
||||
async getLanguages(
|
||||
projectId,
|
||||
params
|
||||
) {
|
||||
return (await apiService.get(
|
||||
`/api/v4/projects/42422/languages`,
|
||||
params,
|
||||
{
|
||||
disableResponseConvert: true,
|
||||
}
|
||||
))
|
||||
},
|
||||
|
||||
async bulkChangeFiles(
|
||||
projectsId, owner,data
|
||||
) {
|
||||
const res = await axios.post(`/v1/${owner}/${projectsId}/contents/batch`,data);
|
||||
return res;
|
||||
},
|
||||
};
|
|
@ -0,0 +1,78 @@
|
|||
import { apiService } from './api.service';
|
||||
import { underscoreToCamelcase } from './utils/camelcase-convert';
|
||||
import axios from 'axios';
|
||||
import moment from 'moment';
|
||||
|
||||
const format = "YYYY-MM-DD HH:mm:ss";
|
||||
|
||||
export const repoService = {
|
||||
async getFileList(
|
||||
projectId,
|
||||
refName,
|
||||
path,
|
||||
withCommit
|
||||
) {
|
||||
return (await apiService.get(
|
||||
`/webapi/projects/42422/repository/tree`,
|
||||
{
|
||||
refName,
|
||||
path,
|
||||
withCommit,
|
||||
}
|
||||
))
|
||||
},
|
||||
|
||||
async getTreeEntry(projectId, refName, path) {
|
||||
return (await apiService.get(
|
||||
`/api/v3/projects/42422/repository/tree_entry`,
|
||||
{
|
||||
refName,
|
||||
path,
|
||||
}
|
||||
))
|
||||
},
|
||||
|
||||
async getCodeSymbols(projectId, ref, filepath) {
|
||||
return await apiService.get(
|
||||
`/api/v3/projects/42422/repository/file_symbols/${encodeURIComponent(
|
||||
ref
|
||||
)}/`,
|
||||
{
|
||||
filepath,
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
async getCodeBlame(projectsId, owner, params) {
|
||||
const res = await axios.get(`/v1/${owner}/${projectsId}/blame.json`, { params });
|
||||
let blame_parts = underscoreToCamelcase(res.data.blame_parts);
|
||||
let blameParts = [];
|
||||
for (const item of blame_parts) {
|
||||
let blamePart = {
|
||||
commit: {
|
||||
author: item.commit.author,
|
||||
// authorEmail: "taian.lta@test.com",
|
||||
authorName: item.commit.author.name,
|
||||
authoredDate: moment(new Date(item.commit.authoredTime * 1000)).format(format),
|
||||
committedDate: moment(new Date(item.commit.committedTime * 1000)).format(format),
|
||||
committer: item.commit.committer,
|
||||
// committerEmail: "taian.lta@test.com",
|
||||
committerName: item.commit.committer.name,
|
||||
createdAt: moment(new Date(item.commit.createdTime * 1000)).format(format),
|
||||
id: item.commit.sha,
|
||||
message: item.commit.commitMessage,
|
||||
// parentIds: null,
|
||||
// shortId: "7c501a19",
|
||||
title: item.commit.commitMessage,
|
||||
// treeHash: null,
|
||||
},
|
||||
lines: [{
|
||||
currentNumber: item.currentNumber,
|
||||
effectLine: item.effectLine,
|
||||
}]
|
||||
};
|
||||
blameParts.push(blamePart);
|
||||
}
|
||||
return blameParts;
|
||||
},
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
import { mockService } from './mock';
|
||||
import { underscoreToCamelcase } from '../utils/camelcase-convert';
|
||||
|
||||
|
||||
|
||||
|
||||
export async function request(
|
||||
url,
|
||||
options,
|
||||
extraOptions
|
||||
) {
|
||||
const data = underscoreToCamelcase(mockService[url]);
|
||||
console.log('request ==== ', url);
|
||||
console.log(data)
|
||||
if (data) {
|
||||
return data;
|
||||
} else {
|
||||
return '文件展示内容只mock了 aaa/package.json';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { message as messageTip } from 'antd';
|
||||
|
||||
|
||||
export function createApiError(message = '请求出错', response) {
|
||||
const err = new Error(message);
|
||||
err.isApiError = true;
|
||||
err.response = response;
|
||||
return err;
|
||||
}
|
||||
|
||||
export function isApiError(e) {
|
||||
return e&&e.isApiError;
|
||||
}
|
||||
/**
|
||||
* 目前存在一些请求成功也报错的情况
|
||||
* 返回值可能情况
|
||||
* 1. success === true 此时只提示有 errorMessage 的情况
|
||||
* 2. success === false 此时提示包括 message 的信息
|
||||
* todo: 目前由于intl使用的是react component注入的方式,这里暂时无法做到国际化,后续等移除 konjac 之后采用全局api方式即可支持国际化
|
||||
* @param responseData 返回值,各种可能
|
||||
*/
|
||||
export function successErrorMessage(responseData) {
|
||||
if (responseData) {
|
||||
const errorMessage = responseData.error || responseData.errorMessage;
|
||||
const message = errorMessage || responseData.message;
|
||||
if (responseData.success === false && message) {
|
||||
messageTip.error(message);
|
||||
} else if (errorMessage) {
|
||||
messageTip.error(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
export function calcChangeLineNum(diffs) {
|
||||
let addLineNum = 0;
|
||||
let delLineNum = 0;
|
||||
for (const diff of diffs) {
|
||||
if (diff.tooLarge) {
|
||||
continue;
|
||||
}
|
||||
const addition = diff.diff.match(/^\+/gm)&&diff.diff.match(/^\+/gm).length || 0;
|
||||
const deletion = diff.diff.match(/^-/gm)&&diff.diff.match(/^-/gm).length || 0;
|
||||
diff.addLineNum = addition;
|
||||
diff.delLineNum = deletion;
|
||||
addLineNum += addition;
|
||||
delLineNum += deletion;
|
||||
}
|
||||
return {
|
||||
addLineNum,
|
||||
delLineNum,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
export function underscoreToCamelcase(obj){
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => underscoreToCamelcase(item))
|
||||
}
|
||||
if (typeof obj !== 'object' || obj === null || obj === undefined) {
|
||||
return obj;
|
||||
}
|
||||
const ret = {};
|
||||
for (const key in obj) {
|
||||
if (obj.hasOwnProperty && !obj.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
const newKey = key.replace(/_([a-z])/g, (m) => m[1].toUpperCase());
|
||||
ret[newKey] = underscoreToCamelcase(obj[key]);
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
export function camelcaseToUnderscore(obj) {
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => camelcaseToUnderscore(item))
|
||||
}
|
||||
if (typeof obj !== 'object' || obj === null || obj === undefined) {
|
||||
return obj;
|
||||
}
|
||||
const ret= {};
|
||||
for (const key in obj) {
|
||||
if (obj.hasOwnProperty && !obj.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
const newKey = key.replace(/([a-z][A-Z])/g, (m) => m[0] + '_' + m[1].toLowerCase());
|
||||
ret[newKey] = camelcaseToUnderscore(obj[key]);
|
||||
}
|
||||
return ret
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export const getLocale = () =>
|
||||
document.cookie.indexOf('LOCALE=en_US') > -1 ? 'en-US' : 'zh-CN';
|
|
@ -0,0 +1,8 @@
|
|||
export function mapGetSet(map, key, fallback) {
|
||||
let ret = map.get(key);
|
||||
if (!ret) {
|
||||
ret = fallback();
|
||||
map.set(key, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,682 @@
|
|||
import React, {
|
||||
useState,
|
||||
useMemo,
|
||||
useRef,
|
||||
useContext,
|
||||
useEffect,
|
||||
useCallback,
|
||||
createContext,
|
||||
createElement,
|
||||
FC,
|
||||
} from 'react';
|
||||
import { getLocale } from './mock/utils/locale';
|
||||
// @ts-ignore
|
||||
import sha1 from 'sha1';
|
||||
// @ts-ignore
|
||||
import memoize from 'lodash/memoize';
|
||||
import jCookie from 'js-cookie';
|
||||
import { useRequest } from './hooks';
|
||||
// import { group, repo, prIid, project } from './meta';
|
||||
import { prService } from './mock/pr.service.js';
|
||||
import { projectService } from './mock/project.service.js';
|
||||
import { mapGetSet } from './mock/utils/map-get-set.js';
|
||||
import { isApiError } from './mock/utils/api-error.js';
|
||||
import { mockService } from './mock/request/mock';
|
||||
import { Base64 } from 'js-base64';
|
||||
import './style.less';
|
||||
|
||||
|
||||
|
||||
const NoteType = {
|
||||
comment: 'Comment',
|
||||
problem: 'Problem',
|
||||
}
|
||||
|
||||
const NoteState = {
|
||||
opened: 'opened',
|
||||
resolved: 'resolved',
|
||||
invalid: 'invalid',
|
||||
}
|
||||
|
||||
const CharsetName = {
|
||||
gbk: 'GBK',
|
||||
utf8: 'UTF-8',
|
||||
};
|
||||
|
||||
|
||||
function createContainer(useHook, checkNull = false) {
|
||||
let Context = createContext(null);
|
||||
const Provider = ({ children }) => {
|
||||
const value = useHook();
|
||||
if (checkNull && !value) return null;
|
||||
return <Context.Provider value={value}>{children}</Context.Provider>;
|
||||
};
|
||||
const useContainer = () => React.useContext(Context);
|
||||
return [Provider, useContainer];
|
||||
}
|
||||
|
||||
let ContextProps = createContext(null);
|
||||
const useGlobal = () => React.useContext(ContextProps);
|
||||
|
||||
|
||||
const [PrProvider, usePr] = createContainer(() => {
|
||||
const { params } = useGlobal();
|
||||
const { projectsId, owner, mergeId } = params;
|
||||
const data = useRequest(async () => {
|
||||
const pr = await prService.getPRByIid(projectsId, owner, mergeId);
|
||||
return { pr }
|
||||
})
|
||||
return data;
|
||||
}, true);
|
||||
|
||||
|
||||
const [SettingProvider, useSetting] = createContainer(() => {
|
||||
const { project } = useGlobal();
|
||||
const [gbk, setGBK] = useState(() => project.encoding === 'GBK');
|
||||
const charsetName = gbk ? CharsetName.gbk : CharsetName.utf8;
|
||||
const [locale, setLocal] = useState(() => getLocale());
|
||||
const setLocale = React.useCallback(() => {
|
||||
jCookie.set('LOCALE', locale === 'en-US' ? 'zh_CN' : 'en_US');
|
||||
window.location.reload();
|
||||
}, [locale]);
|
||||
|
||||
|
||||
return {
|
||||
gbk,
|
||||
setGBK,
|
||||
charsetName,
|
||||
locale,
|
||||
setLocale,
|
||||
};
|
||||
});
|
||||
|
||||
// 评论数据
|
||||
/* 评论数据返回数据分为 note 和 review 参照 /webapi/projects/42422/pull_requests/13055/comments mock接口
|
||||
* note格式 参照 types/note.ts
|
||||
* review 参照 types/review.ts
|
||||
* review 包含 reviewNotes 内有多个note
|
||||
*
|
||||
* 需传递的数据
|
||||
* noteIdToReplyIdSet noteIdToNote lineToNoteIdSet updateFlag
|
||||
*/
|
||||
const useCommentPack = (projectId, prId) => {
|
||||
const { params } = useGlobal();
|
||||
const { projectsId, owner, mergeId } = params;
|
||||
// 这个参数理论上不需要传递到ACR组件内
|
||||
const lineToNoteIdSet = useMemo(() => new Map(), []);
|
||||
// 将note 转换成 noteid => note 形式
|
||||
const noteIdToNote = useMemo(() => new Map(), []);
|
||||
const noteIdToReviewId = useMemo(() => new Map(), []);
|
||||
// 将 review 转化成reviewid => review 形式
|
||||
const reviewIdToReview = useMemo(() => new Map(), []);
|
||||
// 代码扫描插件使用数据
|
||||
const noteIdToReplyIdSet = useMemo(() => new Map(), []);
|
||||
// 等待中的review
|
||||
const pendingNoteIdSet = useMemo(() => new Set(), []);
|
||||
const recordNoteIdSet = useMemo(() => new Set(), []);
|
||||
const topLevelCommentNoteIdSet = useMemo(() => new Set(), []);
|
||||
// 需要回应的评论
|
||||
const commentNoteIdSet = useMemo(() => new Set(), []);
|
||||
const openedProblemNoteIdSet = useMemo(() => new Set(), []);
|
||||
const [updateFlag, setUpdateFlag] = useState({});
|
||||
|
||||
const fetchingRef = useRef(false);
|
||||
const lastFetchAtRef = useRef();
|
||||
|
||||
const pendingReviewRef = useRef();
|
||||
const [hasPendingReview, setHasPendingReview] = useState(false); // TODO: 去掉这个state
|
||||
|
||||
function processNote(note, review = null) {
|
||||
noteIdToNote.set(note.id, note);
|
||||
noteIdToReviewId.set(note.id, review && review.id);
|
||||
if (note.type === NoteType.problem && note.state === NoteState.opened) {
|
||||
openedProblemNoteIdSet.add(note.id);
|
||||
} else {
|
||||
openedProblemNoteIdSet.delete(note.id);
|
||||
}
|
||||
if (!note.discussionId) {
|
||||
if (!note.lineCode && note.system) {
|
||||
recordNoteIdSet.add(note.id);
|
||||
} else {
|
||||
topLevelCommentNoteIdSet.add(note.id);
|
||||
}
|
||||
}
|
||||
if (note.discussionId || note.lineCode) {
|
||||
commentNoteIdSet.add(note.id);
|
||||
}
|
||||
if (note.lineCode) {
|
||||
const noteIdSet = mapGetSet(
|
||||
lineToNoteIdSet,
|
||||
note.lineCode,
|
||||
() => new Set()
|
||||
);
|
||||
noteIdSet.add(note.id);
|
||||
}
|
||||
if (note.discussionId) {
|
||||
const replyIdSet = mapGetSet(
|
||||
noteIdToReplyIdSet,
|
||||
note.discussionId,
|
||||
() => new Set()
|
||||
);
|
||||
replyIdSet.add(note.id);
|
||||
}
|
||||
if (review && review.pending) {
|
||||
pendingNoteIdSet.add(note.id);
|
||||
} else {
|
||||
pendingNoteIdSet.delete(note.id);
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新清空数据
|
||||
async function doRefresh(force = false, filePath) {
|
||||
if (fetchingRef.current) {
|
||||
return;
|
||||
}
|
||||
fetchingRef.current = true;
|
||||
// 获取评论内容
|
||||
const commentPack = await prService.getCommentPack(projectsId, owner, mergeId, { path: filePath, is_full: true });
|
||||
const reviews = await prService.getReviews(projectsId, owner, mergeId);
|
||||
// debugger
|
||||
for (const review of reviews) {
|
||||
review.reviewNotes = commentPack;
|
||||
}
|
||||
const pack = {
|
||||
committedReviews: reviews,
|
||||
notes: commentPack,
|
||||
pendingReview: reviews[0],
|
||||
};
|
||||
console.log('pack');
|
||||
console.log(pack);
|
||||
// debugger
|
||||
lastFetchAtRef.current = pack.currentFetchedAt;
|
||||
let updated = false;
|
||||
if (force) {
|
||||
lineToNoteIdSet.clear();
|
||||
noteIdToNote.clear();
|
||||
noteIdToReviewId.clear();
|
||||
reviewIdToReview.clear();
|
||||
noteIdToReplyIdSet.clear();
|
||||
pendingNoteIdSet.clear();
|
||||
recordNoteIdSet.clear();
|
||||
topLevelCommentNoteIdSet.clear();
|
||||
commentNoteIdSet.clear();
|
||||
openedProblemNoteIdSet.clear();
|
||||
updated = true;
|
||||
}
|
||||
|
||||
for (const note of pack.notes) {
|
||||
processNote(note);
|
||||
updated = true;
|
||||
}
|
||||
for (const review of pack.committedReviews) {
|
||||
reviewIdToReview.set(review.id, review);
|
||||
for (const note of review.reviewNotes) {
|
||||
processNote(note, review);
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
if (pack.pendingReview) {
|
||||
reviewIdToReview.set(pack.pendingReview.id, pack.pendingReview);
|
||||
pendingReviewRef.current = pack.pendingReview;
|
||||
setHasPendingReview(true);
|
||||
for (const note of pack.pendingReview.reviewNotes) {
|
||||
processNote(note, pack.pendingReview);
|
||||
updated = true;
|
||||
}
|
||||
} else {
|
||||
setHasPendingReview(false);
|
||||
}
|
||||
if (updated) {
|
||||
setUpdateFlag({});
|
||||
}
|
||||
fetchingRef.current = false;
|
||||
}
|
||||
|
||||
function manualUpdateReview(review) {
|
||||
reviewIdToReview.set(review.id, review);
|
||||
if (review.pending) {
|
||||
pendingReviewRef.current = review;
|
||||
setHasPendingReview(!!review);
|
||||
}
|
||||
setUpdateFlag({});
|
||||
}
|
||||
|
||||
function manualAddNote(note, review = null) {
|
||||
processNote(note, review);
|
||||
setUpdateFlag({});
|
||||
}
|
||||
|
||||
function manualRemoveNote(id) {
|
||||
noteIdToNote.delete(id);
|
||||
setUpdateFlag({});
|
||||
}
|
||||
|
||||
function manualUpdateNote(note) {
|
||||
const reviewId = noteIdToReviewId.get(note.id);
|
||||
const review = reviewId ? reviewIdToReview.get(reviewId) : null;
|
||||
processNote(note, review);
|
||||
setUpdateFlag({});
|
||||
}
|
||||
|
||||
function getRelatedFilePathByNoteId(noteId) {
|
||||
const note = noteIdToNote.get(noteId);
|
||||
if (!note) return;
|
||||
let path = note.path;
|
||||
if (note.discussionId) {
|
||||
const parent = noteIdToNote.get(note.discussionId);
|
||||
path = parent && parent.path;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
// 重新编辑
|
||||
async function editNote(
|
||||
noteId, data
|
||||
) {
|
||||
const newNote = await prService.editPRComment(projectsId, owner, mergeId, noteId, data);
|
||||
manualUpdateNote(newNote);
|
||||
newNote.discussions && newNote.discussions.forEach((note) => manualUpdateNote(note));
|
||||
}
|
||||
|
||||
const pathShaToNoteCount = (function () {
|
||||
const ret = new Map();
|
||||
|
||||
function handleNote(note) {
|
||||
if (!note || !note.lineCode) return;
|
||||
const key = note.lineCode.split('_')[0];
|
||||
ret.set(key, (ret.get(key) || 0) + 1);
|
||||
}
|
||||
|
||||
topLevelCommentNoteIdSet.forEach((noteId) => {
|
||||
const note = noteIdToNote.get(noteId);
|
||||
handleNote(note);
|
||||
});
|
||||
return ret;
|
||||
})();
|
||||
|
||||
return {
|
||||
lineToNoteIdSet,
|
||||
noteIdToNote,
|
||||
noteIdToReviewId,
|
||||
reviewIdToReview,
|
||||
noteIdToReplyIdSet,
|
||||
pendingNoteIdSet,
|
||||
recordNoteIdSet,
|
||||
topLevelCommentNoteIdSet,
|
||||
openedProblemNoteIdSet,
|
||||
hasPendingReview,
|
||||
hasOpenedProblem: openedProblemNoteIdSet.size > 0,
|
||||
doRefresh,
|
||||
manualUpdateReview,
|
||||
manualAddNote,
|
||||
manualRemoveNote,
|
||||
manualUpdateNote,
|
||||
pendingReviewRef,
|
||||
getRelatedFilePathByNoteId,
|
||||
editNote,
|
||||
updateFlag,
|
||||
pathShaToNoteCount,
|
||||
setUpdateFlag,
|
||||
};
|
||||
};
|
||||
|
||||
// note 评论相关数据
|
||||
const [NoteProvider, useNote] = createContainer(() => {
|
||||
|
||||
const { params } = useGlobal();
|
||||
const { projectsId, owner, mergeId } = params;
|
||||
const { pr: { id: prId } } = usePr();
|
||||
const commentPack = useCommentPack(projectsId, mergeId);
|
||||
// useEffect(() => {
|
||||
// commentPack.doRefresh();
|
||||
// }, []);
|
||||
|
||||
async function addComment(data) {
|
||||
if (!commentPack.hasPendingReview) {
|
||||
let reviewData = {
|
||||
content: data.note,
|
||||
status: 'common',
|
||||
}
|
||||
const review = await prService.createReview(projectsId, owner, mergeId, reviewData);
|
||||
commentPack.manualUpdateReview(review);
|
||||
}
|
||||
const note = await prService.addComment(projectsId, owner, mergeId, data);
|
||||
commentPack.manualAddNote(note, commentPack.pendingReviewRef.current);
|
||||
}
|
||||
|
||||
async function deleteComment(id) {
|
||||
const res = await prService.deleteComment(projectsId, owner, mergeId, id);
|
||||
if (res.status == 0) {
|
||||
commentPack.manualRemoveNote(id);
|
||||
}
|
||||
}
|
||||
|
||||
async function commitReview(body) {
|
||||
if (!commentPack.hasPendingReview) {
|
||||
let reviewData = {
|
||||
content: body.note,
|
||||
status: 'common',
|
||||
}
|
||||
await prService.createReview(projectsId, owner, mergeId, reviewData);
|
||||
}
|
||||
await prService.commitReview(projectsId, owner, mergeId, body);
|
||||
await commentPack.doRefresh(true);
|
||||
}
|
||||
|
||||
const activateRef = useRef();
|
||||
|
||||
return {
|
||||
commentPack,
|
||||
...commentPack,
|
||||
addComment,
|
||||
deleteComment,
|
||||
commitReview,
|
||||
prId,
|
||||
activateRef,
|
||||
};
|
||||
});
|
||||
|
||||
const [ReadMarkProvider, useReadMark] = createContainer(() => {
|
||||
const { params } = useGlobal();
|
||||
const { projectsId, owner, mergeId } = params;
|
||||
const { pr: { id: prId } } = usePr();
|
||||
|
||||
const [flag, updateFlag] = useState({});
|
||||
|
||||
const readMarks = useRequest(
|
||||
() => prService.getFileReadMarks(projectsId, owner, mergeId,),
|
||||
{
|
||||
deps: [projectsId, owner, mergeId, flag],
|
||||
}
|
||||
);
|
||||
|
||||
const readMarkMap = useMemo(() => {
|
||||
const map = new Map();
|
||||
if (!readMarks) return map;
|
||||
for (const mark of readMarks) {
|
||||
mark.markAsRead && map.set(mark.filePathSha, mark);
|
||||
}
|
||||
return map;
|
||||
}, [readMarks]);
|
||||
|
||||
|
||||
const memoizedSha1 = useMemo(() => memoize(sha1), []);
|
||||
|
||||
async function markFileAsRead(filePath) {
|
||||
const data = await prService.markFileAsRead(
|
||||
projectsId, owner, mergeId,
|
||||
{ file_path_sha: Base64.encode(filePath) }
|
||||
);
|
||||
updateFlag({});
|
||||
return data;
|
||||
}
|
||||
|
||||
async function markFileAsUnread(filePath) {
|
||||
const data = await prService.markFileAsUnread(
|
||||
projectsId, owner, mergeId,
|
||||
{ file_path_sha: Base64.encode(filePath) }
|
||||
);
|
||||
updateFlag({});
|
||||
return data;
|
||||
}
|
||||
|
||||
const getFileReadMark = useCallback(
|
||||
(filePath) => {
|
||||
const filePathSha = memoizedSha1(filePath);
|
||||
return readMarkMap.get(filePathSha);
|
||||
},
|
||||
[readMarkMap]
|
||||
);
|
||||
|
||||
const getFileReadStatus = useCallback(
|
||||
(filePath) => {
|
||||
const readMark = getFileReadMark(filePath);
|
||||
return readMark && readMark.markAsRead && !readMark.updatedAfterRead;
|
||||
},
|
||||
[getFileReadMark]
|
||||
);
|
||||
|
||||
return {
|
||||
readMarks,
|
||||
readMarkMap,
|
||||
getFileReadMark,
|
||||
getFileReadStatus,
|
||||
markFileAsRead,
|
||||
markFileAsUnread,
|
||||
};
|
||||
});
|
||||
|
||||
const [AcrProvider, useAcr] = createContainer(() => {
|
||||
const { params } = useGlobal();
|
||||
const { pr } = usePr();
|
||||
const { charsetName } = useSetting();
|
||||
const { commentPack } = useNote();
|
||||
|
||||
const { projectsId, owner, mergeId } = params;
|
||||
const [IDEMode, setIDEMode] = useState(true);
|
||||
const toggleViewerType = useCallback(() => {
|
||||
setIDEMode((v) => !v);
|
||||
}, [setIDEMode]);
|
||||
|
||||
const [stDiff, setStDiff] = useState({});
|
||||
const [search, setSearch] = useState(window.location.search);
|
||||
const [acrflag, setAcrFlag] = useState();
|
||||
const [versions, setVersions] = useState([]);
|
||||
const query = useMemo(() => {
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const ret = {};
|
||||
if (searchParams.has('from')) {
|
||||
ret.from = parseInt(searchParams.get('from'));
|
||||
}
|
||||
if (searchParams.has('to')) {
|
||||
ret.to = parseInt(searchParams.get('to'));
|
||||
}
|
||||
return ret;
|
||||
}, [search]);
|
||||
|
||||
function updateQuery(data) {
|
||||
const searchParam = new URLSearchParams();
|
||||
if (data.from) {
|
||||
searchParam.set('from', String(data.from));
|
||||
}
|
||||
if (data.to) {
|
||||
searchParam.set('to', String(data.to));
|
||||
}
|
||||
const search = searchParam.toString();
|
||||
window.history.replaceState(
|
||||
null,
|
||||
'',
|
||||
`${window.location.pathname}${search ? '?' : ''}${search}`
|
||||
);
|
||||
setSearch(search);
|
||||
}
|
||||
|
||||
|
||||
async function getDiffVersions() {
|
||||
const data = await prService.getDiffVersions(projectsId, owner, mergeId);
|
||||
if (acrflag && data.length == versions.length) {
|
||||
setTimeout(() => {
|
||||
setAcrFlag({});
|
||||
}, 3000);
|
||||
}
|
||||
setVersions(data);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getDiffVersions()
|
||||
}, [acrflag])
|
||||
|
||||
|
||||
const versionMap = useMemo(() => {
|
||||
const map = new Map();
|
||||
for (const version of versions) {
|
||||
map.set(version.id, version);
|
||||
}
|
||||
return map;
|
||||
}, [versions]);
|
||||
const latestVersionId = versions[0] && versions[versions.length - 1].id || pr.diff.id;
|
||||
|
||||
const from = query.from;
|
||||
const to = query.to || latestVersionId;
|
||||
const fromVersion = from ? versionMap.get(from) : null;
|
||||
const toVersion = versionMap.get(to);
|
||||
|
||||
console.log('diffpack', from, to, fromVersion, toVersion);
|
||||
const ignoreWhiteSpace = false;
|
||||
// @ts-ignore
|
||||
const diffsPack = useRequest(
|
||||
async () => {
|
||||
if (!toVersion) return null;
|
||||
const isPartial = !!fromVersion || toVersion.id !== latestVersionId;
|
||||
const options = {
|
||||
ignoreWhiteSpaceChange: ignoreWhiteSpace,
|
||||
charsetName,
|
||||
};
|
||||
let res;
|
||||
if (fromVersion) {
|
||||
res = await prService.getDiffs(
|
||||
projectsId, owner,
|
||||
fromVersion.headCommitSha,
|
||||
toVersion.headCommitSha,
|
||||
options
|
||||
);
|
||||
} else {
|
||||
if (ignoreWhiteSpace) {
|
||||
res = await prService.getDiffs(
|
||||
projectsId, owner,
|
||||
toVersion.baseCommitSha,
|
||||
toVersion.headCommitSha,
|
||||
options
|
||||
);
|
||||
} else {
|
||||
const diffs = await prService.getDiffOverviews(
|
||||
projectsId, owner,
|
||||
mergeId,
|
||||
toVersion.id
|
||||
);
|
||||
res = {
|
||||
diffs,
|
||||
overflow: false,
|
||||
addLineNum: toVersion.addLineNum,
|
||||
delLineNum: toVersion.delLineNum,
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
...res,
|
||||
fromVersion,
|
||||
toVersion,
|
||||
isPartial,
|
||||
};
|
||||
},
|
||||
{
|
||||
deps: [fromVersion, toVersion, charsetName],
|
||||
}
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
commentPack.doRefresh();
|
||||
}, []);
|
||||
|
||||
async function getDiffById(diffId) {
|
||||
let thisStDiff = await prService.getDiffById(projectsId, owner, mergeId, toVersion.id,
|
||||
{
|
||||
filepath: diffId,
|
||||
});
|
||||
delete thisStDiff.sections
|
||||
setStDiff(thisStDiff);
|
||||
commentPack.doRefresh(false, diffId);
|
||||
return thisStDiff;
|
||||
}
|
||||
|
||||
async function getFileContent(path, sha, maxSize) {
|
||||
try {
|
||||
return await projectService.getFileBlob(projectsId, owner, {
|
||||
filepath: path,
|
||||
ref: sha,
|
||||
});
|
||||
} catch (e) {
|
||||
if (isApiError(e) && e.response.status === 413) {
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
const annotationPacks = [];
|
||||
let countMap = new Map();
|
||||
for (const checkSuite of pr.checkSuites) {
|
||||
if (checkSuite.checkRuns) {
|
||||
for (const checkRun of checkSuite.checkRuns) {
|
||||
if (checkRun.annotations) {
|
||||
for (const annotation of checkRun.annotations) {
|
||||
const pack = {
|
||||
annotation,
|
||||
checkSuite,
|
||||
};
|
||||
annotationPacks.push(pack);
|
||||
countMap.set(
|
||||
annotation.path,
|
||||
(countMap.get(annotation.path) || 0) + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
diffsPack,
|
||||
versions,
|
||||
fromVersion,
|
||||
toVersion,
|
||||
getDiffById,
|
||||
stDiff,
|
||||
getFileContent,
|
||||
IDEMode,
|
||||
toggleViewerType,
|
||||
updateQuery,
|
||||
setAcrFlag,
|
||||
annotationPacks,
|
||||
};
|
||||
});
|
||||
|
||||
export const Provider = (props) => {
|
||||
const match = props.match;
|
||||
let project = {};
|
||||
// let user = mockService['/api/v3/user'];
|
||||
if (props.projectDetail) {
|
||||
let details = props.projectDetail;
|
||||
project = {
|
||||
...project,
|
||||
...props.projectDetail,
|
||||
pathWithNamespace: details.full_name,
|
||||
}
|
||||
}
|
||||
let user = {};
|
||||
if (props.current_user) {
|
||||
let current_user = props.current_user;
|
||||
user = { ...current_user, avatar_url: current_user.image_url, name: current_user.username, };
|
||||
}
|
||||
|
||||
return (
|
||||
<ContextProps.Provider value={{
|
||||
project, user, params: match.params
|
||||
}}>
|
||||
{/* <GlobalProvider> */}
|
||||
<PrProvider>
|
||||
<SettingProvider>
|
||||
<NoteProvider>
|
||||
<ReadMarkProvider>
|
||||
<AcrProvider>{props.children}</AcrProvider>
|
||||
</ReadMarkProvider>
|
||||
</NoteProvider>
|
||||
</SettingProvider>
|
||||
</PrProvider>
|
||||
{/* </GlobalProvider> */}
|
||||
</ContextProps.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export { useGlobal, usePr, useNote, useReadMark, useAcr, useSetting };
|
|
@ -0,0 +1,62 @@
|
|||
export const ExtensionCommand ={
|
||||
acrToggleBlame : 'code.blame.acrToggleBlame',
|
||||
linkToCommit : 'code.blame.linktocommit',
|
||||
onActive : 'code.blame.extension.active',
|
||||
setProjectData : 'code.blame.setProjectData',
|
||||
getBlameData : 'code.blame.getBlameData',
|
||||
}
|
||||
|
||||
export default class IDEPlugin {
|
||||
/**
|
||||
* 插件 ID,用于唯一标识插件
|
||||
*/
|
||||
PLUGIN_ID = 'ACR_BLAME_PLUGIN';
|
||||
|
||||
constructor(
|
||||
onActive,
|
||||
linkToCommit,
|
||||
getBlame
|
||||
) {
|
||||
this.onActivate = onActive;
|
||||
// 跳转
|
||||
this.linkToCommit = linkToCommit;
|
||||
// 传递blame数据
|
||||
this.getBlame = getBlame;
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活插件
|
||||
*/
|
||||
activate = (ctx) => {
|
||||
const { commands, context } = ctx;
|
||||
this.commands = commands;
|
||||
context.subscriptions.push(
|
||||
commands.registerCommand(ExtensionCommand.onActive, () => {
|
||||
this.onActivate();
|
||||
}),
|
||||
commands.registerCommand(ExtensionCommand.linkToCommit, (params) => {
|
||||
const { commitId } = params;
|
||||
this.linkToCommit(commitId);
|
||||
}),
|
||||
commands.registerCommand(
|
||||
ExtensionCommand.getBlameData,
|
||||
async (sendData) => {
|
||||
const { projectId, prevSha, nextSha, filePath } = sendData;
|
||||
// kaitian内uri 和 antcode内不同 多了一个 /
|
||||
const path = filePath.startsWith('/') ? filePath.slice(1) : filePath;
|
||||
const response = await this.getBlame(projectId, nextSha, path).then(
|
||||
(res) => {
|
||||
return res;
|
||||
}
|
||||
);
|
||||
return response;
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 注销插件,可在此时机清理副作用
|
||||
*/
|
||||
deactivate() {}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
@c45: rgba(0, 0, 0, 0.45);
|
||||
@c85: rgba(0, 0, 0, 0.85);
|
||||
html,
|
||||
body,
|
||||
#main {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
#main {
|
||||
padding: 8px 24px 24px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
background-color: #f7f8fa;
|
||||
}
|
||||
|
||||
.pr-head {
|
||||
padding: 24px;
|
||||
background-color: #fff;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.controller {
|
||||
margin-bottom: 24px;
|
||||
> * {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.monaco-editor-hover {
|
||||
border: none !important;
|
||||
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12),
|
||||
0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
|
||||
transform: translate(-20px, 0px);
|
||||
}
|
||||
|
||||
.monaco-editor-hover-content .markdown-hover .hover-contents {
|
||||
padding: 16px;
|
||||
background: #fff;
|
||||
|
||||
h1 {
|
||||
color: @c85;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: @c45;
|
||||
}
|
||||
}
|
||||
|
||||
.ide-logo {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.ide-btn {
|
||||
margin: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ide-btn {
|
||||
display: inline-flex;
|
||||
box-shadow: inset 0 0 35px 5px rgba(0, 0, 0, 0.05),
|
||||
inset 0 2px 1px 1px rgba(255, 255, 255, 0.9),
|
||||
inset 0 -2px 1px 0 rgba(0, 0, 0, 0.05);
|
||||
border-radius: 8px;
|
||||
background: #fefefe;
|
||||
position: relative;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 20px;
|
||||
}
|
||||
// .ide-btn:before {
|
||||
// box-shadow: 0 0 17.5px 8.75px white;
|
||||
// border-radius: 118.3px;
|
||||
// background: white;
|
||||
// position: absolute;
|
||||
// margin-left: -50.4px;
|
||||
// margin-top: -50.4px;
|
||||
// opacity: 0.2;
|
||||
// content: "";
|
||||
// height: 100.8px;
|
||||
// width: 100.8px;
|
||||
// left: 50%;
|
||||
// top: 50%;
|
||||
// }
|
||||
}
|
||||
.ide-logo-img {
|
||||
width: 150px;
|
||||
}
|
||||
.ide-logo-text {
|
||||
color: #aaa;
|
||||
margin-top: 0.5em;
|
||||
font-size: 14px;
|
||||
|
||||
&:nth-child(2) {
|
||||
margin-left: 2em;
|
||||
}
|
||||
&:nth-child(3) {
|
||||
margin-left: 2em;
|
||||
}
|
||||
&:nth-child(4) {
|
||||
margin-left: 4em;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,30 @@
|
|||
.monaco-editor .view-overlays .current-line{
|
||||
.monaco-editor .view-overlays .current-line {
|
||||
border: none !important;
|
||||
background-color: rgba(48,232,132,0.15);
|
||||
background-color: rgba(48, 232, 132, 0.15);
|
||||
}
|
||||
.monaco-editor .margin-view-overlays .current-line{
|
||||
background-color: rgba(48,232,132,0.15);
|
||||
.monaco-editor .margin-view-overlays .current-line {
|
||||
background-color: rgba(48, 232, 132, 0.15);
|
||||
}
|
||||
.branchTable .margin-view-overlays {
|
||||
border-right: none !important;
|
||||
background-color: #fcfcfc !important;
|
||||
}
|
||||
.editorBorderBox {
|
||||
position: relative;
|
||||
}
|
||||
.ide-tool-bar {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
right: 114px;
|
||||
top: -37px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.ant-switch-checked {
|
||||
background-color: #466aff;
|
||||
}
|
||||
.read-more{
|
||||
font-size: 18px;
|
||||
margin:0 10px 0 15px;
|
||||
color: #666;
|
||||
}
|
||||
.branchTable .margin-view-overlays{border-right: none !important; background-color: #fcfcfc !important;}
|
|
@ -0,0 +1,724 @@
|
|||
module.exports = {
|
||||
extension: {
|
||||
publisher: 'alex-ext-public',
|
||||
name: 'css-language-features-worker',
|
||||
version: '1.53.0-patch.1',
|
||||
},
|
||||
packageJSON: {
|
||||
name: 'css-language-features-worker',
|
||||
publisher: 'alex',
|
||||
version: '1.53.0-patch.1',
|
||||
displayName: '%displayName%',
|
||||
description: '%description%',
|
||||
icon: 'icons/css.png',
|
||||
activationEvents: [
|
||||
'onLanguage:css',
|
||||
'onLanguage:less',
|
||||
'onLanguage:scss',
|
||||
'onCommand:_css.applyCodeAction',
|
||||
],
|
||||
kaitianContributes: {
|
||||
workerMain: 'client/dist/browser/cssClientMain.js',
|
||||
},
|
||||
contributes: {
|
||||
configuration: [
|
||||
{
|
||||
order: 22,
|
||||
id: 'css',
|
||||
title: '%css.title%',
|
||||
properties: {
|
||||
'css.customData': {
|
||||
type: 'array',
|
||||
markdownDescription: '%css.customData.desc%',
|
||||
default: [],
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
scope: 'resource',
|
||||
},
|
||||
'css.completion.triggerPropertyValueCompletion': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description:
|
||||
'%css.completion.triggerPropertyValueCompletion.desc%',
|
||||
},
|
||||
'css.completion.completePropertyWithSemicolon': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description:
|
||||
'%css.completion.completePropertyWithSemicolon.desc%',
|
||||
},
|
||||
'css.validate': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description: '%css.validate.desc%',
|
||||
},
|
||||
'css.lint.compatibleVendorPrefixes': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%css.lint.compatibleVendorPrefixes.desc%',
|
||||
},
|
||||
'css.lint.vendorPrefix': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
description: '%css.lint.vendorPrefix.desc%',
|
||||
},
|
||||
'css.lint.duplicateProperties': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%css.lint.duplicateProperties.desc%',
|
||||
},
|
||||
'css.lint.emptyRules': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
description: '%css.lint.emptyRules.desc%',
|
||||
},
|
||||
'css.lint.importStatement': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%css.lint.importStatement.desc%',
|
||||
},
|
||||
'css.lint.boxModel': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
markdownDescription: '%css.lint.boxModel.desc%',
|
||||
},
|
||||
'css.lint.universalSelector': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
markdownDescription: '%css.lint.universalSelector.desc%',
|
||||
},
|
||||
'css.lint.zeroUnits': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%css.lint.zeroUnits.desc%',
|
||||
},
|
||||
'css.lint.fontFaceProperties': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
markdownDescription: '%css.lint.fontFaceProperties.desc%',
|
||||
},
|
||||
'css.lint.hexColorLength': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'error',
|
||||
description: '%css.lint.hexColorLength.desc%',
|
||||
},
|
||||
'css.lint.argumentsInColorFunction': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'error',
|
||||
description: '%css.lint.argumentsInColorFunction.desc%',
|
||||
},
|
||||
'css.lint.unknownProperties': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
description: '%css.lint.unknownProperties.desc%',
|
||||
},
|
||||
'css.lint.validProperties': {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
scope: 'resource',
|
||||
default: [],
|
||||
description: '%css.lint.validProperties.desc%',
|
||||
},
|
||||
'css.lint.ieHack': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%css.lint.ieHack.desc%',
|
||||
},
|
||||
'css.lint.unknownVendorSpecificProperties': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%css.lint.unknownVendorSpecificProperties.desc%',
|
||||
},
|
||||
'css.lint.propertyIgnoredDueToDisplay': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
markdownDescription:
|
||||
'%css.lint.propertyIgnoredDueToDisplay.desc%',
|
||||
},
|
||||
'css.lint.important': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
markdownDescription: '%css.lint.important.desc%',
|
||||
},
|
||||
'css.lint.float': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
markdownDescription: '%css.lint.float.desc%',
|
||||
},
|
||||
'css.lint.idSelector': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%css.lint.idSelector.desc%',
|
||||
},
|
||||
'css.lint.unknownAtRules': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
description: '%css.lint.unknownAtRules.desc%',
|
||||
},
|
||||
'css.trace.server': {
|
||||
type: 'string',
|
||||
scope: 'window',
|
||||
enum: ['off', 'messages', 'verbose'],
|
||||
default: 'off',
|
||||
description: '%css.trace.server.desc%',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'scss',
|
||||
order: 24,
|
||||
title: '%scss.title%',
|
||||
properties: {
|
||||
'scss.completion.triggerPropertyValueCompletion': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description:
|
||||
'%scss.completion.triggerPropertyValueCompletion.desc%',
|
||||
},
|
||||
'scss.completion.completePropertyWithSemicolon': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description:
|
||||
'%scss.completion.completePropertyWithSemicolon.desc%',
|
||||
},
|
||||
'scss.validate': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description: '%scss.validate.desc%',
|
||||
},
|
||||
'scss.lint.compatibleVendorPrefixes': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%scss.lint.compatibleVendorPrefixes.desc%',
|
||||
},
|
||||
'scss.lint.vendorPrefix': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
description: '%scss.lint.vendorPrefix.desc%',
|
||||
},
|
||||
'scss.lint.duplicateProperties': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%scss.lint.duplicateProperties.desc%',
|
||||
},
|
||||
'scss.lint.emptyRules': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
description: '%scss.lint.emptyRules.desc%',
|
||||
},
|
||||
'scss.lint.importStatement': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%scss.lint.importStatement.desc%',
|
||||
},
|
||||
'scss.lint.boxModel': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
markdownDescription: '%scss.lint.boxModel.desc%',
|
||||
},
|
||||
'scss.lint.universalSelector': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
markdownDescription: '%scss.lint.universalSelector.desc%',
|
||||
},
|
||||
'scss.lint.zeroUnits': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%scss.lint.zeroUnits.desc%',
|
||||
},
|
||||
'scss.lint.fontFaceProperties': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
markdownDescription: '%scss.lint.fontFaceProperties.desc%',
|
||||
},
|
||||
'scss.lint.hexColorLength': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'error',
|
||||
description: '%scss.lint.hexColorLength.desc%',
|
||||
},
|
||||
'scss.lint.argumentsInColorFunction': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'error',
|
||||
description: '%scss.lint.argumentsInColorFunction.desc%',
|
||||
},
|
||||
'scss.lint.unknownProperties': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
description: '%scss.lint.unknownProperties.desc%',
|
||||
},
|
||||
'scss.lint.validProperties': {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
scope: 'resource',
|
||||
default: [],
|
||||
description: '%scss.lint.validProperties.desc%',
|
||||
},
|
||||
'scss.lint.ieHack': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%scss.lint.ieHack.desc%',
|
||||
},
|
||||
'scss.lint.unknownVendorSpecificProperties': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%scss.lint.unknownVendorSpecificProperties.desc%',
|
||||
},
|
||||
'scss.lint.propertyIgnoredDueToDisplay': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
markdownDescription:
|
||||
'%scss.lint.propertyIgnoredDueToDisplay.desc%',
|
||||
},
|
||||
'scss.lint.important': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
markdownDescription: '%scss.lint.important.desc%',
|
||||
},
|
||||
'scss.lint.float': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
markdownDescription: '%scss.lint.float.desc%',
|
||||
},
|
||||
'scss.lint.idSelector': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%scss.lint.idSelector.desc%',
|
||||
},
|
||||
'scss.lint.unknownAtRules': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
description: '%scss.lint.unknownAtRules.desc%',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'less',
|
||||
order: 23,
|
||||
type: 'object',
|
||||
title: '%less.title%',
|
||||
properties: {
|
||||
'less.completion.triggerPropertyValueCompletion': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description:
|
||||
'%less.completion.triggerPropertyValueCompletion.desc%',
|
||||
},
|
||||
'less.completion.completePropertyWithSemicolon': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description:
|
||||
'%less.completion.completePropertyWithSemicolon.desc%',
|
||||
},
|
||||
'less.validate': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description: '%less.validate.desc%',
|
||||
},
|
||||
'less.lint.compatibleVendorPrefixes': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%less.lint.compatibleVendorPrefixes.desc%',
|
||||
},
|
||||
'less.lint.vendorPrefix': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
description: '%less.lint.vendorPrefix.desc%',
|
||||
},
|
||||
'less.lint.duplicateProperties': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%less.lint.duplicateProperties.desc%',
|
||||
},
|
||||
'less.lint.emptyRules': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
description: '%less.lint.emptyRules.desc%',
|
||||
},
|
||||
'less.lint.importStatement': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%less.lint.importStatement.desc%',
|
||||
},
|
||||
'less.lint.boxModel': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
markdownDescription: '%less.lint.boxModel.desc%',
|
||||
},
|
||||
'less.lint.universalSelector': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
markdownDescription: '%less.lint.universalSelector.desc%',
|
||||
},
|
||||
'less.lint.zeroUnits': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%less.lint.zeroUnits.desc%',
|
||||
},
|
||||
'less.lint.fontFaceProperties': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
markdownDescription: '%less.lint.fontFaceProperties.desc%',
|
||||
},
|
||||
'less.lint.hexColorLength': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'error',
|
||||
description: '%less.lint.hexColorLength.desc%',
|
||||
},
|
||||
'less.lint.argumentsInColorFunction': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'error',
|
||||
description: '%less.lint.argumentsInColorFunction.desc%',
|
||||
},
|
||||
'less.lint.unknownProperties': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
description: '%less.lint.unknownProperties.desc%',
|
||||
},
|
||||
'less.lint.validProperties': {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
scope: 'resource',
|
||||
default: [],
|
||||
description: '%less.lint.validProperties.desc%',
|
||||
},
|
||||
'less.lint.ieHack': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%less.lint.ieHack.desc%',
|
||||
},
|
||||
'less.lint.unknownVendorSpecificProperties': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%less.lint.unknownVendorSpecificProperties.desc%',
|
||||
},
|
||||
'less.lint.propertyIgnoredDueToDisplay': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
markdownDescription:
|
||||
'%less.lint.propertyIgnoredDueToDisplay.desc%',
|
||||
},
|
||||
'less.lint.important': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
markdownDescription: '%less.lint.important.desc%',
|
||||
},
|
||||
'less.lint.float': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
markdownDescription: '%less.lint.float.desc%',
|
||||
},
|
||||
'less.lint.idSelector': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'ignore',
|
||||
description: '%less.lint.idSelector.desc%',
|
||||
},
|
||||
'less.lint.unknownAtRules': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
enum: ['ignore', 'warning', 'error'],
|
||||
default: 'warning',
|
||||
description: '%less.lint.unknownAtRules.desc%',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
configurationDefaults: {
|
||||
'[css]': {
|
||||
'editor.suggest.insertMode': 'replace',
|
||||
},
|
||||
'[scss]': {
|
||||
'editor.suggest.insertMode': 'replace',
|
||||
},
|
||||
'[less]': {
|
||||
'editor.suggest.insertMode': 'replace',
|
||||
},
|
||||
},
|
||||
jsonValidation: [
|
||||
{
|
||||
fileMatch: '*.css-data.json',
|
||||
url: 'https://raw.githubusercontent.com/microsoft/vscode-css-languageservice/master/docs/customData.schema.json',
|
||||
},
|
||||
{
|
||||
fileMatch: 'package.json',
|
||||
url: './schemas/package.schema.json',
|
||||
},
|
||||
],
|
||||
workerMain: 'client/dist/browser/cssClientMain.js',
|
||||
},
|
||||
},
|
||||
defaultPkgNlsJSON: {
|
||||
displayName: 'CSS Language Features',
|
||||
description: 'Provides rich language support for CSS, LESS and SCSS files.',
|
||||
'css.title': 'CSS',
|
||||
'css.customData.desc':
|
||||
'A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-css-languageservice/blob/master/docs/customData.md).\n\nVS Code loads custom data on startup to enhance its CSS support for the custom CSS properties, at directives, pseudo classes and pseudo elements you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.',
|
||||
'css.completion.triggerPropertyValueCompletion.desc':
|
||||
'By default, VS Code triggers property value completion after selecting a CSS property. Use this setting to disable this behavior.',
|
||||
'css.completion.completePropertyWithSemicolon.desc':
|
||||
'Insert semicolon at end of line when completing CSS properties',
|
||||
'css.lint.argumentsInColorFunction.desc': 'Invalid number of parameters.',
|
||||
'css.lint.boxModel.desc':
|
||||
'Do not use `width` or `height` when using `padding` or `border`.',
|
||||
'css.lint.compatibleVendorPrefixes.desc':
|
||||
'When using a vendor-specific prefix make sure to also include all other vendor-specific properties.',
|
||||
'css.lint.duplicateProperties.desc':
|
||||
'Do not use duplicate style definitions.',
|
||||
'css.lint.emptyRules.desc': 'Do not use empty rulesets.',
|
||||
'css.lint.float.desc':
|
||||
'Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.',
|
||||
'css.lint.fontFaceProperties.desc':
|
||||
'`@font-face` rule must define `src` and `font-family` properties.',
|
||||
'css.lint.hexColorLength.desc':
|
||||
'Hex colors must consist of three or six hex numbers.',
|
||||
'css.lint.idSelector.desc':
|
||||
'Selectors should not contain IDs because these rules are too tightly coupled with the HTML.',
|
||||
'css.lint.ieHack.desc':
|
||||
'IE hacks are only necessary when supporting IE7 and older.',
|
||||
'css.lint.important.desc':
|
||||
'Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.',
|
||||
'css.lint.importStatement.desc':
|
||||
'Import statements do not load in parallel.',
|
||||
'css.lint.propertyIgnoredDueToDisplay.desc':
|
||||
'Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect.',
|
||||
'css.lint.universalSelector.desc':
|
||||
'The universal selector (`*`) is known to be slow.',
|
||||
'css.lint.unknownAtRules.desc': 'Unknown at-rule.',
|
||||
'css.lint.unknownProperties.desc': 'Unknown property.',
|
||||
'css.lint.validProperties.desc':
|
||||
'A list of properties that are not validated against the `unknownProperties` rule.',
|
||||
'css.lint.unknownVendorSpecificProperties.desc':
|
||||
'Unknown vendor specific property.',
|
||||
'css.lint.vendorPrefix.desc':
|
||||
'When using a vendor-specific prefix, also include the standard property.',
|
||||
'css.lint.zeroUnits.desc': 'No unit for zero needed.',
|
||||
'css.trace.server.desc':
|
||||
'Traces the communication between VS Code and the CSS language server.',
|
||||
'css.validate.title': 'Controls CSS validation and problem severities.',
|
||||
'css.validate.desc': 'Enables or disables all validations.',
|
||||
'less.title': 'LESS',
|
||||
'less.completion.triggerPropertyValueCompletion.desc':
|
||||
'By default, VS Code triggers property value completion after selecting a CSS property. Use this setting to disable this behavior.',
|
||||
'less.completion.completePropertyWithSemicolon.desc':
|
||||
'Insert semicolon at end of line when completing CSS properties',
|
||||
'less.lint.argumentsInColorFunction.desc': 'Invalid number of parameters.',
|
||||
'less.lint.boxModel.desc':
|
||||
'Do not use `width` or `height` when using `padding` or `border`.',
|
||||
'less.lint.compatibleVendorPrefixes.desc':
|
||||
'When using a vendor-specific prefix make sure to also include all other vendor-specific properties.',
|
||||
'less.lint.duplicateProperties.desc':
|
||||
'Do not use duplicate style definitions.',
|
||||
'less.lint.emptyRules.desc': 'Do not use empty rulesets.',
|
||||
'less.lint.float.desc':
|
||||
'Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.',
|
||||
'less.lint.fontFaceProperties.desc':
|
||||
'`@font-face` rule must define `src` and `font-family` properties.',
|
||||
'less.lint.hexColorLength.desc':
|
||||
'Hex colors must consist of three or six hex numbers.',
|
||||
'less.lint.idSelector.desc':
|
||||
'Selectors should not contain IDs because these rules are too tightly coupled with the HTML.',
|
||||
'less.lint.ieHack.desc':
|
||||
'IE hacks are only necessary when supporting IE7 and older.',
|
||||
'less.lint.important.desc':
|
||||
'Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.',
|
||||
'less.lint.importStatement.desc':
|
||||
'Import statements do not load in parallel.',
|
||||
'less.lint.propertyIgnoredDueToDisplay.desc':
|
||||
'Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect.',
|
||||
'less.lint.universalSelector.desc':
|
||||
'The universal selector (`*`) is known to be slow.',
|
||||
'less.lint.unknownAtRules.desc': 'Unknown at-rule.',
|
||||
'less.lint.unknownProperties.desc': 'Unknown property.',
|
||||
'less.lint.validProperties.desc':
|
||||
'A list of properties that are not validated against the `unknownProperties` rule.',
|
||||
'less.lint.unknownVendorSpecificProperties.desc':
|
||||
'Unknown vendor specific property.',
|
||||
'less.lint.vendorPrefix.desc':
|
||||
'When using a vendor-specific prefix, also include the standard property.',
|
||||
'less.lint.zeroUnits.desc': 'No unit for zero needed.',
|
||||
'less.validate.title': 'Controls LESS validation and problem severities.',
|
||||
'less.validate.desc': 'Enables or disables all validations.',
|
||||
'scss.title': 'SCSS (Sass)',
|
||||
'scss.completion.triggerPropertyValueCompletion.desc':
|
||||
'By default, VS Code triggers property value completion after selecting a CSS property. Use this setting to disable this behavior.',
|
||||
'scss.completion.completePropertyWithSemicolon.desc':
|
||||
'Insert semicolon at end of line when completing CSS properties',
|
||||
'scss.lint.argumentsInColorFunction.desc': 'Invalid number of parameters.',
|
||||
'scss.lint.boxModel.desc':
|
||||
'Do not use `width` or `height` when using `padding` or `border`.',
|
||||
'scss.lint.compatibleVendorPrefixes.desc':
|
||||
'When using a vendor-specific prefix make sure to also include all other vendor-specific properties.',
|
||||
'scss.lint.duplicateProperties.desc':
|
||||
'Do not use duplicate style definitions.',
|
||||
'scss.lint.emptyRules.desc': 'Do not use empty rulesets.',
|
||||
'scss.lint.float.desc':
|
||||
'Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.',
|
||||
'scss.lint.fontFaceProperties.desc':
|
||||
'`@font-face` rule must define `src` and `font-family` properties.',
|
||||
'scss.lint.hexColorLength.desc':
|
||||
'Hex colors must consist of three or six hex numbers.',
|
||||
'scss.lint.idSelector.desc':
|
||||
'Selectors should not contain IDs because these rules are too tightly coupled with the HTML.',
|
||||
'scss.lint.ieHack.desc':
|
||||
'IE hacks are only necessary when supporting IE7 and older.',
|
||||
'scss.lint.important.desc':
|
||||
'Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.',
|
||||
'scss.lint.importStatement.desc':
|
||||
'Import statements do not load in parallel.',
|
||||
'scss.lint.propertyIgnoredDueToDisplay.desc':
|
||||
'Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect.',
|
||||
'scss.lint.universalSelector.desc':
|
||||
'The universal selector (`*`) is known to be slow.',
|
||||
'scss.lint.unknownAtRules.desc': 'Unknown at-rule.',
|
||||
'scss.lint.unknownProperties.desc': 'Unknown property.',
|
||||
'scss.lint.validProperties.desc':
|
||||
'A list of properties that are not validated against the `unknownProperties` rule.',
|
||||
'scss.lint.unknownVendorSpecificProperties.desc':
|
||||
'Unknown vendor specific property.',
|
||||
'scss.lint.vendorPrefix.desc':
|
||||
'When using a vendor-specific prefix, also include the standard property.',
|
||||
'scss.lint.zeroUnits.desc': 'No unit for zero needed.',
|
||||
'scss.validate.title': 'Controls SCSS validation and problem severities.',
|
||||
'scss.validate.desc': 'Enables or disables all validations.',
|
||||
'css.colorDecorators.enable.deprecationMessage':
|
||||
'The setting `css.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`.',
|
||||
'scss.colorDecorators.enable.deprecationMessage':
|
||||
'The setting `scss.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`.',
|
||||
'less.colorDecorators.enable.deprecationMessage':
|
||||
'The setting `less.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`.',
|
||||
},
|
||||
pkgNlsJSON: {},
|
||||
nlsList: [],
|
||||
extendConfig: {},
|
||||
mode: 'public',
|
||||
};
|
|
@ -0,0 +1,56 @@
|
|||
module.exports = {
|
||||
extension: {
|
||||
publisher: 'alex-ext-public',
|
||||
name: 'editor-plugin-blame',
|
||||
version: '0.2.6',
|
||||
},
|
||||
packageJSON: {
|
||||
name: 'editor-plugin-blame',
|
||||
publisher: 'alex-ext-public',
|
||||
version: '0.2.6',
|
||||
repository: {
|
||||
type: 'git',
|
||||
url: 'http://code.alipay.com/yxy167584/editor-plugin-blame.git',
|
||||
},
|
||||
displayName: 'editor-plugin-blame',
|
||||
description: ' ',
|
||||
activationEvents: ['*'],
|
||||
kaitianContributes: {
|
||||
workerMain: './out/worker/index.js',
|
||||
},
|
||||
contributes: {
|
||||
commands: [
|
||||
{
|
||||
command: 'code.blame.toggleBlame',
|
||||
title: '查看blame',
|
||||
},
|
||||
{
|
||||
command: 'code.blame.acrToggleBlame',
|
||||
title: 'blame',
|
||||
},
|
||||
{
|
||||
command: 'code.blame.linktocommit',
|
||||
title: 'hover详情跳转',
|
||||
},
|
||||
],
|
||||
views: {},
|
||||
menus: {
|
||||
'editor/title': [
|
||||
{
|
||||
command: 'code.blame.acrToggleBlame',
|
||||
type: 'checkbox',
|
||||
group: 'navigation',
|
||||
toggledWhen: 'acr_blame_context',
|
||||
when: 'resourceScheme =~ /^git$|^diff$/',
|
||||
},
|
||||
],
|
||||
},
|
||||
workerMain: './out/worker/index.js',
|
||||
},
|
||||
},
|
||||
pkgNlsJSON: {},
|
||||
nlsList: [],
|
||||
extendConfig: {},
|
||||
webAssets: ['package.json', 'out/worker/index.js'],
|
||||
mode: 'public',
|
||||
};
|
|
@ -0,0 +1,273 @@
|
|||
module.exports = {
|
||||
extension: {
|
||||
publisher: 'alex-ext-public',
|
||||
name: 'html-language-features-worker',
|
||||
version: '1.53.0-patch.1',
|
||||
},
|
||||
packageJSON: {
|
||||
name: 'html-language-features-worker',
|
||||
publisher: 'alex',
|
||||
version: '1.53.0-patch.1',
|
||||
displayName: '%displayName%',
|
||||
description: '%description%',
|
||||
icon: 'icons/html.png',
|
||||
activationEvents: ['onLanguage:html', 'onLanguage:handlebars'],
|
||||
kaitianContributes: {
|
||||
workerMain: 'client/dist/browser/htmlClientMain.js',
|
||||
},
|
||||
contributes: {
|
||||
configuration: {
|
||||
id: 'html',
|
||||
order: 20,
|
||||
type: 'object',
|
||||
title: 'HTML',
|
||||
properties: {
|
||||
'html.customData': {
|
||||
type: 'array',
|
||||
markdownDescription: '%html.customData.desc%',
|
||||
default: [],
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
scope: 'resource',
|
||||
},
|
||||
'html.format.enable': {
|
||||
type: 'boolean',
|
||||
scope: 'window',
|
||||
default: true,
|
||||
description: '%html.format.enable.desc%',
|
||||
},
|
||||
'html.format.wrapLineLength': {
|
||||
type: 'integer',
|
||||
scope: 'resource',
|
||||
default: 120,
|
||||
description: '%html.format.wrapLineLength.desc%',
|
||||
},
|
||||
'html.format.unformatted': {
|
||||
type: ['string', 'null'],
|
||||
scope: 'resource',
|
||||
default: 'wbr',
|
||||
markdownDescription: '%html.format.unformatted.desc%',
|
||||
},
|
||||
'html.format.contentUnformatted': {
|
||||
type: ['string', 'null'],
|
||||
scope: 'resource',
|
||||
default: 'pre,code,textarea',
|
||||
markdownDescription: '%html.format.contentUnformatted.desc%',
|
||||
},
|
||||
'html.format.indentInnerHtml': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: false,
|
||||
markdownDescription: '%html.format.indentInnerHtml.desc%',
|
||||
},
|
||||
'html.format.preserveNewLines': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description: '%html.format.preserveNewLines.desc%',
|
||||
},
|
||||
'html.format.maxPreserveNewLines': {
|
||||
type: ['number', 'null'],
|
||||
scope: 'resource',
|
||||
default: null,
|
||||
markdownDescription: '%html.format.maxPreserveNewLines.desc%',
|
||||
},
|
||||
'html.format.indentHandlebars': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: false,
|
||||
markdownDescription: '%html.format.indentHandlebars.desc%',
|
||||
},
|
||||
'html.format.endWithNewline': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: false,
|
||||
description: '%html.format.endWithNewline.desc%',
|
||||
},
|
||||
'html.format.extraLiners': {
|
||||
type: ['string', 'null'],
|
||||
scope: 'resource',
|
||||
default: 'head, body, /html',
|
||||
markdownDescription: '%html.format.extraLiners.desc%',
|
||||
},
|
||||
'html.format.wrapAttributes': {
|
||||
type: 'string',
|
||||
scope: 'resource',
|
||||
default: 'auto',
|
||||
enum: [
|
||||
'auto',
|
||||
'force',
|
||||
'force-aligned',
|
||||
'force-expand-multiline',
|
||||
'aligned-multiple',
|
||||
'preserve',
|
||||
'preserve-aligned',
|
||||
],
|
||||
enumDescriptions: [
|
||||
'%html.format.wrapAttributes.auto%',
|
||||
'%html.format.wrapAttributes.force%',
|
||||
'%html.format.wrapAttributes.forcealign%',
|
||||
'%html.format.wrapAttributes.forcemultiline%',
|
||||
'%html.format.wrapAttributes.alignedmultiple%',
|
||||
'%html.format.wrapAttributes.preserve%',
|
||||
'%html.format.wrapAttributes.preservealigned%',
|
||||
],
|
||||
description: '%html.format.wrapAttributes.desc%',
|
||||
},
|
||||
'html.format.wrapAttributesIndentSize': {
|
||||
type: ['number', 'null'],
|
||||
scope: 'resource',
|
||||
default: null,
|
||||
description: '%html.format.wrapAttributesIndentSize.desc%',
|
||||
},
|
||||
'html.format.templating': {
|
||||
type: ['boolean'],
|
||||
scope: 'resource',
|
||||
default: false,
|
||||
description: '%html.format.templating.desc%',
|
||||
},
|
||||
'html.format.unformattedContentDelimiter': {
|
||||
type: ['string'],
|
||||
scope: 'resource',
|
||||
default: '',
|
||||
markdownDescription:
|
||||
'%html.format.unformattedContentDelimiter.desc%',
|
||||
},
|
||||
'html.suggest.html5': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description: '%html.suggest.html5.desc%',
|
||||
},
|
||||
'html.validate.scripts': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description: '%html.validate.scripts%',
|
||||
},
|
||||
'html.validate.styles': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description: '%html.validate.styles%',
|
||||
},
|
||||
'html.autoClosingTags': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description: '%html.autoClosingTags%',
|
||||
},
|
||||
'html.hover.documentation': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description: '%html.hover.documentation%',
|
||||
},
|
||||
'html.hover.references': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: true,
|
||||
description: '%html.hover.references%',
|
||||
},
|
||||
'html.mirrorCursorOnMatchingTag': {
|
||||
type: 'boolean',
|
||||
scope: 'resource',
|
||||
default: false,
|
||||
description: '%html.mirrorCursorOnMatchingTag%',
|
||||
deprecationMessage:
|
||||
'%html.mirrorCursorOnMatchingTagDeprecationMessage%',
|
||||
},
|
||||
'html.trace.server': {
|
||||
type: 'string',
|
||||
scope: 'window',
|
||||
enum: ['off', 'messages', 'verbose'],
|
||||
default: 'off',
|
||||
description: '%html.trace.server.desc%',
|
||||
},
|
||||
},
|
||||
},
|
||||
configurationDefaults: {
|
||||
'[html]': {
|
||||
'editor.suggest.insertMode': 'replace',
|
||||
},
|
||||
'[handlebars]': {
|
||||
'editor.suggest.insertMode': 'replace',
|
||||
},
|
||||
},
|
||||
jsonValidation: [
|
||||
{
|
||||
fileMatch: '*.html-data.json',
|
||||
url: 'https://raw.githubusercontent.com/microsoft/vscode-html-languageservice/master/docs/customData.schema.json',
|
||||
},
|
||||
{
|
||||
fileMatch: 'package.json',
|
||||
url: './schemas/package.schema.json',
|
||||
},
|
||||
],
|
||||
workerMain: 'client/dist/browser/htmlClientMain.js',
|
||||
},
|
||||
},
|
||||
defaultPkgNlsJSON: {
|
||||
displayName: 'HTML Language Features',
|
||||
description: 'Provides rich language support for HTML and Handlebar files',
|
||||
'html.customData.desc':
|
||||
'A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-html-languageservice/blob/master/docs/customData.md).\n\nVS Code loads custom data on startup to enhance its HTML support for the custom HTML tags, attributes and attribute values you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.',
|
||||
'html.format.enable.desc': 'Enable/disable default HTML formatter.',
|
||||
'html.format.wrapLineLength.desc':
|
||||
'Maximum amount of characters per line (0 = disable).',
|
||||
'html.format.unformatted.desc':
|
||||
"List of tags, comma separated, that shouldn't be reformatted. `null` defaults to all tags listed at https://www.w3.org/TR/html5/dom.html#phrasing-content.",
|
||||
'html.format.contentUnformatted.desc':
|
||||
"List of tags, comma separated, where the content shouldn't be reformatted. `null` defaults to the `pre` tag.",
|
||||
'html.format.indentInnerHtml.desc':
|
||||
'Indent `<head>` and `<body>` sections.',
|
||||
'html.format.preserveNewLines.desc':
|
||||
'Controls whether existing line breaks before elements should be preserved. Only works before elements, not inside tags or for text.',
|
||||
'html.format.maxPreserveNewLines.desc':
|
||||
'Maximum number of line breaks to be preserved in one chunk. Use `null` for unlimited.',
|
||||
'html.format.indentHandlebars.desc':
|
||||
'Format and indent `{{#foo}}` and `{{/foo}}`.',
|
||||
'html.format.endWithNewline.desc': 'End with a newline.',
|
||||
'html.format.extraLiners.desc':
|
||||
'List of tags, comma separated, that should have an extra newline before them. `null` defaults to `"head, body, /html"`.',
|
||||
'html.format.wrapAttributes.desc': 'Wrap attributes.',
|
||||
'html.format.wrapAttributes.auto':
|
||||
'Wrap attributes only when line length is exceeded.',
|
||||
'html.format.wrapAttributes.force': 'Wrap each attribute except first.',
|
||||
'html.format.wrapAttributes.forcealign':
|
||||
'Wrap each attribute except first and keep aligned.',
|
||||
'html.format.wrapAttributes.forcemultiline': 'Wrap each attribute.',
|
||||
'html.format.wrapAttributes.alignedmultiple':
|
||||
'Wrap when line length is exceeded, align attributes vertically.',
|
||||
'html.format.wrapAttributes.preserve': 'Preserve wrapping of attributes',
|
||||
'html.format.wrapAttributes.preservealigned':
|
||||
'Preserve wrapping of attributes but align.',
|
||||
'html.format.templating.desc':
|
||||
'Honor django, erb, handlebars and php templating language tags.',
|
||||
'html.format.unformattedContentDelimiter.desc':
|
||||
'Keep text content together between this string.',
|
||||
'html.format.wrapAttributesIndentSize.desc':
|
||||
"Alignment size when using 'force aligned' and 'aligned multiple' in `#html.format.wrapAttributes#` or `null` to use the default indent size.",
|
||||
'html.suggest.html5.desc':
|
||||
'Controls whether the built-in HTML language support suggests HTML5 tags, properties and values.',
|
||||
'html.trace.server.desc':
|
||||
'Traces the communication between VS Code and the HTML language server.',
|
||||
'html.validate.scripts':
|
||||
'Controls whether the built-in HTML language support validates embedded scripts.',
|
||||
'html.validate.styles':
|
||||
'Controls whether the built-in HTML language support validates embedded styles.',
|
||||
'html.autoClosingTags': 'Enable/disable autoclosing of HTML tags.',
|
||||
'html.mirrorCursorOnMatchingTag':
|
||||
'Enable/disable mirroring cursor on matching HTML tag.',
|
||||
'html.mirrorCursorOnMatchingTagDeprecationMessage':
|
||||
'Deprecated in favor of `editor.linkedEditing`',
|
||||
'html.hover.documentation':
|
||||
'Show tag and attribute documentation in hover.',
|
||||
'html.hover.references': 'Show references to MDN in hover.',
|
||||
},
|
||||
pkgNlsJSON: {},
|
||||
nlsList: [],
|
||||
extendConfig: {},
|
||||
mode: 'public',
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
module.exports = {
|
||||
extension: {
|
||||
publisher: 'alex-ext-public',
|
||||
name: 'ide-dark-theme',
|
||||
version: '2.4.0',
|
||||
},
|
||||
packageJSON: {
|
||||
publisher: 'kaitian',
|
||||
name: 'ide-dark-theme',
|
||||
version: '2.4.0',
|
||||
displayName: 'IDE UI Theme',
|
||||
description: 'IDE UI Theme',
|
||||
contributes: {
|
||||
themes: [
|
||||
{
|
||||
id: 'opensumi-dark',
|
||||
label: 'OpenSumi Dark',
|
||||
uiTheme: 'vs-dark',
|
||||
path: './themes/dark/plus.json',
|
||||
},
|
||||
{
|
||||
id: 'opensumi-light',
|
||||
label: 'OpenSumi Light',
|
||||
uiTheme: 'vs',
|
||||
path: './themes/light/plus.json',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
pkgNlsJSON: {},
|
||||
nlsList: [],
|
||||
extendConfig: {},
|
||||
webAssets: [],
|
||||
mode: 'public',
|
||||
};
|
|
@ -0,0 +1,147 @@
|
|||
module.exports = {
|
||||
extension: {
|
||||
publisher: 'alex-ext-public',
|
||||
name: 'json-language-features-worker',
|
||||
version: '1.53.0-patch.1',
|
||||
},
|
||||
packageJSON: {
|
||||
name: 'json-language-features-worker',
|
||||
publisher: 'alex',
|
||||
version: '1.53.0-patch.1',
|
||||
displayName: '%displayName%',
|
||||
description: '%description%',
|
||||
icon: 'icons/json.png',
|
||||
activationEvents: ['onLanguage:json', 'onLanguage:jsonc'],
|
||||
kaitianContributes: {
|
||||
workerMain: 'client/dist/browser/jsonClientMain.js',
|
||||
},
|
||||
contributes: {
|
||||
configuration: {
|
||||
id: 'json',
|
||||
order: 20,
|
||||
type: 'object',
|
||||
title: 'JSON',
|
||||
properties: {
|
||||
'json.schemas': {
|
||||
type: 'array',
|
||||
scope: 'resource',
|
||||
description: '%json.schemas.desc%',
|
||||
items: {
|
||||
type: 'object',
|
||||
default: {
|
||||
fileMatch: ['/myfile'],
|
||||
url: 'schemaURL',
|
||||
},
|
||||
properties: {
|
||||
url: {
|
||||
type: 'string',
|
||||
default: '/user.schema.json',
|
||||
description: '%json.schemas.url.desc%',
|
||||
},
|
||||
fileMatch: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
default: 'MyFile.json',
|
||||
description: '%json.schemas.fileMatch.item.desc%',
|
||||
},
|
||||
minItems: 1,
|
||||
description: '%json.schemas.fileMatch.desc%',
|
||||
},
|
||||
schema: {
|
||||
$ref: 'http://json-schema.org/draft-07/schema#',
|
||||
description: '%json.schemas.schema.desc%',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'json.format.enable': {
|
||||
type: 'boolean',
|
||||
scope: 'window',
|
||||
default: true,
|
||||
description: '%json.format.enable.desc%',
|
||||
},
|
||||
'json.trace.server': {
|
||||
type: 'string',
|
||||
scope: 'window',
|
||||
enum: ['off', 'messages', 'verbose'],
|
||||
default: 'off',
|
||||
description: '%json.tracing.desc%',
|
||||
},
|
||||
'json.colorDecorators.enable': {
|
||||
type: 'boolean',
|
||||
scope: 'window',
|
||||
default: true,
|
||||
description: '%json.colorDecorators.enable.desc%',
|
||||
deprecationMessage:
|
||||
'%json.colorDecorators.enable.deprecationMessage%',
|
||||
},
|
||||
'json.maxItemsComputed': {
|
||||
type: 'number',
|
||||
default: 5000,
|
||||
description: '%json.maxItemsComputed.desc%',
|
||||
},
|
||||
'json.schemaDownload.enable': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: '%json.enableSchemaDownload.desc%',
|
||||
tags: ['usesOnlineServices'],
|
||||
},
|
||||
},
|
||||
},
|
||||
configurationDefaults: {
|
||||
'[json]': {
|
||||
'editor.quickSuggestions': {
|
||||
strings: true,
|
||||
},
|
||||
'editor.suggest.insertMode': 'replace',
|
||||
},
|
||||
'[jsonc]': {
|
||||
'editor.quickSuggestions': {
|
||||
strings: true,
|
||||
},
|
||||
'editor.suggest.insertMode': 'replace',
|
||||
},
|
||||
},
|
||||
jsonValidation: [
|
||||
{
|
||||
fileMatch: '*.schema.json',
|
||||
url: 'http://json-schema.org/draft-07/schema#',
|
||||
},
|
||||
],
|
||||
workerMain: 'client/dist/browser/jsonClientMain.js',
|
||||
},
|
||||
},
|
||||
defaultPkgNlsJSON: {
|
||||
displayName: 'JSON Language Features',
|
||||
description: 'Provides rich language support for JSON files.',
|
||||
'json.schemas.desc':
|
||||
'Associate schemas to JSON files in the current project',
|
||||
'json.schemas.url.desc':
|
||||
'A URL to a schema or a relative path to a schema in the current directory',
|
||||
'json.schemas.fileMatch.desc':
|
||||
"An array of file patterns to match against when resolving JSON files to schemas. `*` can be used as a wildcard. Exclusion patterns can also be defined and start with '!'. A file matches when there is at least one matching pattern and the last matching pattern is not an exclusion pattern.",
|
||||
'json.schemas.fileMatch.item.desc':
|
||||
"A file pattern that can contain '*' to match against when resolving JSON files to schemas.",
|
||||
'json.schemas.schema.desc':
|
||||
'The schema definition for the given URL. The schema only needs to be provided to avoid accesses to the schema URL.',
|
||||
'json.format.enable.desc': 'Enable/disable default JSON formatter',
|
||||
'json.tracing.desc':
|
||||
'Traces the communication between VS Code and the JSON language server.',
|
||||
'json.colorDecorators.enable.desc': 'Enables or disables color decorators',
|
||||
'json.colorDecorators.enable.deprecationMessage':
|
||||
'The setting `json.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`.',
|
||||
'json.schemaResolutionErrorMessage': 'Unable to resolve schema.',
|
||||
'json.clickToRetry': 'Click to retry.',
|
||||
'json.maxItemsComputed.desc':
|
||||
'The maximum number of outline symbols and folding regions computed (limited for performance reasons).',
|
||||
'json.maxItemsExceededInformation.desc':
|
||||
'Show notification when exceeding the maximum number of outline symbols and folding regions.',
|
||||
'json.enableSchemaDownload.desc':
|
||||
'When enabled, JSON schemas can be fetched from http and https locations.',
|
||||
},
|
||||
pkgNlsJSON: {},
|
||||
nlsList: [],
|
||||
extendConfig: {},
|
||||
mode: 'public',
|
||||
};
|
|
@ -0,0 +1,346 @@
|
|||
module.exports = {
|
||||
extension: {
|
||||
publisher: 'alex-ext-public',
|
||||
name: 'markdown-language-features-worker',
|
||||
version: '1.53.0-patch.1',
|
||||
},
|
||||
packageJSON: {
|
||||
name: 'markdown-language-features-worker',
|
||||
publisher: 'alex',
|
||||
version: '1.53.0-patch.1',
|
||||
displayName: '%displayName%',
|
||||
description: '%description%',
|
||||
icon: 'icon.png',
|
||||
activationEvents: [
|
||||
'onLanguage:markdown',
|
||||
'onCommand:markdown.preview.toggleLock',
|
||||
'onCommand:markdown.preview.refresh',
|
||||
'onCommand:markdown.showPreview',
|
||||
'onCommand:markdown.showPreviewToSide',
|
||||
'onCommand:markdown.showLockedPreviewToSide',
|
||||
'onCommand:markdown.showSource',
|
||||
'onCommand:markdown.showPreviewSecuritySelector',
|
||||
'onCommand:markdown.api.render',
|
||||
'onWebviewPanel:markdown.preview',
|
||||
'onCustomEditor:vscode.markdown.preview.editor',
|
||||
],
|
||||
kaitianContributes: {
|
||||
workerMain: './dist/browser/extension.js',
|
||||
},
|
||||
contributes: {
|
||||
commands: [
|
||||
{
|
||||
command: 'markdown.showPreview',
|
||||
title: '%markdown.preview.title%',
|
||||
category: 'Markdown',
|
||||
icon: {
|
||||
light: './media/preview-light.svg',
|
||||
dark: './media/preview-dark.svg',
|
||||
},
|
||||
},
|
||||
{
|
||||
command: 'markdown.showPreviewToSide',
|
||||
title: '%markdown.previewSide.title%',
|
||||
category: 'Markdown',
|
||||
icon: '$(open-preview)',
|
||||
},
|
||||
{
|
||||
command: 'markdown.showLockedPreviewToSide',
|
||||
title: '%markdown.showLockedPreviewToSide.title%',
|
||||
category: 'Markdown',
|
||||
icon: '$(open-preview)',
|
||||
},
|
||||
{
|
||||
command: 'markdown.showSource',
|
||||
title: '%markdown.showSource.title%',
|
||||
category: 'Markdown',
|
||||
icon: '$(go-to-file)',
|
||||
},
|
||||
{
|
||||
command: 'markdown.showPreviewSecuritySelector',
|
||||
title: '%markdown.showPreviewSecuritySelector.title%',
|
||||
category: 'Markdown',
|
||||
},
|
||||
{
|
||||
command: 'markdown.preview.refresh',
|
||||
title: '%markdown.preview.refresh.title%',
|
||||
category: 'Markdown',
|
||||
},
|
||||
{
|
||||
command: 'markdown.preview.toggleLock',
|
||||
title: '%markdown.preview.toggleLock.title%',
|
||||
category: 'Markdown',
|
||||
},
|
||||
],
|
||||
menus: {
|
||||
'editor/title': [
|
||||
{
|
||||
command: 'markdown.showPreviewToSide',
|
||||
when: 'editorLangId == markdown && !notebookEditorFocused',
|
||||
alt: 'markdown.showPreview',
|
||||
group: 'navigation',
|
||||
},
|
||||
{
|
||||
command: 'markdown.showSource',
|
||||
when: 'markdownPreviewFocus',
|
||||
group: 'navigation',
|
||||
},
|
||||
{
|
||||
command: 'markdown.preview.refresh',
|
||||
when: 'markdownPreviewFocus',
|
||||
group: '1_markdown',
|
||||
},
|
||||
{
|
||||
command: 'markdown.preview.toggleLock',
|
||||
when: 'markdownPreviewFocus',
|
||||
group: '1_markdown',
|
||||
},
|
||||
{
|
||||
command: 'markdown.showPreviewSecuritySelector',
|
||||
when: 'markdownPreviewFocus',
|
||||
group: '1_markdown',
|
||||
},
|
||||
],
|
||||
'explorer/context': [
|
||||
{
|
||||
command: 'markdown.showPreview',
|
||||
when: 'resourceLangId == markdown',
|
||||
group: 'navigation',
|
||||
},
|
||||
],
|
||||
'editor/title/context': [
|
||||
{
|
||||
command: 'markdown.showPreview',
|
||||
when: 'resourceLangId == markdown',
|
||||
group: '1_open',
|
||||
},
|
||||
],
|
||||
commandPalette: [
|
||||
{
|
||||
command: 'markdown.showPreview',
|
||||
when: 'editorLangId == markdown && !notebookEditorFocused',
|
||||
group: 'navigation',
|
||||
},
|
||||
{
|
||||
command: 'markdown.showPreviewToSide',
|
||||
when: 'editorLangId == markdown && !notebookEditorFocused',
|
||||
group: 'navigation',
|
||||
},
|
||||
{
|
||||
command: 'markdown.showLockedPreviewToSide',
|
||||
when: 'editorLangId == markdown && !notebookEditorFocused',
|
||||
group: 'navigation',
|
||||
},
|
||||
{
|
||||
command: 'markdown.showSource',
|
||||
when: 'markdownPreviewFocus',
|
||||
group: 'navigation',
|
||||
},
|
||||
{
|
||||
command: 'markdown.showPreviewSecuritySelector',
|
||||
when: 'editorLangId == markdown && !notebookEditorFocused',
|
||||
},
|
||||
{
|
||||
command: 'markdown.showPreviewSecuritySelector',
|
||||
when: 'markdownPreviewFocus',
|
||||
},
|
||||
{
|
||||
command: 'markdown.preview.toggleLock',
|
||||
when: 'markdownPreviewFocus',
|
||||
},
|
||||
{
|
||||
command: 'markdown.preview.refresh',
|
||||
when: 'editorLangId == markdown && !notebookEditorFocused',
|
||||
},
|
||||
{
|
||||
command: 'markdown.preview.refresh',
|
||||
when: 'markdownPreviewFocus',
|
||||
},
|
||||
],
|
||||
},
|
||||
keybindings: [
|
||||
{
|
||||
command: 'markdown.showPreview',
|
||||
key: 'shift+ctrl+v',
|
||||
mac: 'shift+cmd+v',
|
||||
when: 'editorLangId == markdown && !notebookEditorFocused',
|
||||
},
|
||||
{
|
||||
command: 'markdown.showPreviewToSide',
|
||||
key: 'ctrl+k v',
|
||||
mac: 'cmd+k v',
|
||||
when: 'editorLangId == markdown && !notebookEditorFocused',
|
||||
},
|
||||
],
|
||||
configuration: {
|
||||
type: 'object',
|
||||
title: 'Markdown',
|
||||
order: 20,
|
||||
properties: {
|
||||
'markdown.styles': {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
default: [],
|
||||
description: '%markdown.styles.dec%',
|
||||
scope: 'resource',
|
||||
},
|
||||
'markdown.preview.breaks': {
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: '%markdown.preview.breaks.desc%',
|
||||
scope: 'resource',
|
||||
},
|
||||
'markdown.preview.linkify': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: '%markdown.preview.linkify%',
|
||||
scope: 'resource',
|
||||
},
|
||||
'markdown.preview.fontFamily': {
|
||||
type: 'string',
|
||||
default:
|
||||
"-apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', system-ui, 'Ubuntu', 'Droid Sans', sans-serif",
|
||||
description: '%markdown.preview.fontFamily.desc%',
|
||||
scope: 'resource',
|
||||
},
|
||||
'markdown.preview.fontSize': {
|
||||
type: 'number',
|
||||
default: 14,
|
||||
description: '%markdown.preview.fontSize.desc%',
|
||||
scope: 'resource',
|
||||
},
|
||||
'markdown.preview.lineHeight': {
|
||||
type: 'number',
|
||||
default: 1.6,
|
||||
description: '%markdown.preview.lineHeight.desc%',
|
||||
scope: 'resource',
|
||||
},
|
||||
'markdown.preview.scrollPreviewWithEditor': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: '%markdown.preview.scrollPreviewWithEditor.desc%',
|
||||
scope: 'resource',
|
||||
},
|
||||
'markdown.preview.markEditorSelection': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: '%markdown.preview.markEditorSelection.desc%',
|
||||
scope: 'resource',
|
||||
},
|
||||
'markdown.preview.scrollEditorWithPreview': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: '%markdown.preview.scrollEditorWithPreview.desc%',
|
||||
scope: 'resource',
|
||||
},
|
||||
'markdown.preview.doubleClickToSwitchToEditor': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: '%markdown.preview.doubleClickToSwitchToEditor.desc%',
|
||||
scope: 'resource',
|
||||
},
|
||||
'markdown.preview.openMarkdownLinks': {
|
||||
type: 'string',
|
||||
default: 'inPreview',
|
||||
description:
|
||||
'%configuration.markdown.preview.openMarkdownLinks.description%',
|
||||
scope: 'resource',
|
||||
enum: ['inPreview', 'inEditor'],
|
||||
enumDescriptions: [
|
||||
'%configuration.markdown.preview.openMarkdownLinks.inPreview%',
|
||||
'%configuration.markdown.preview.openMarkdownLinks.inEditor%',
|
||||
],
|
||||
},
|
||||
'markdown.links.openLocation': {
|
||||
type: 'string',
|
||||
default: 'currentGroup',
|
||||
description:
|
||||
'%configuration.markdown.links.openLocation.description%',
|
||||
scope: 'resource',
|
||||
enum: ['currentGroup', 'beside'],
|
||||
enumDescriptions: [
|
||||
'%configuration.markdown.links.openLocation.currentGroup%',
|
||||
'%configuration.markdown.links.openLocation.beside%',
|
||||
],
|
||||
},
|
||||
'markdown.trace': {
|
||||
type: 'string',
|
||||
enum: ['off', 'verbose'],
|
||||
default: 'off',
|
||||
description: '%markdown.trace.desc%',
|
||||
scope: 'window',
|
||||
},
|
||||
},
|
||||
},
|
||||
configurationDefaults: {
|
||||
'[markdown]': {
|
||||
'editor.wordWrap': 'on',
|
||||
'editor.quickSuggestions': false,
|
||||
},
|
||||
},
|
||||
jsonValidation: [
|
||||
{
|
||||
fileMatch: 'package.json',
|
||||
url: './schemas/package.schema.json',
|
||||
},
|
||||
],
|
||||
'markdown.previewStyles': [
|
||||
'./media/markdown.css',
|
||||
'./media/highlight.css',
|
||||
],
|
||||
'markdown.previewScripts': ['./media/index.js'],
|
||||
workerMain: './dist/browser/extension.js',
|
||||
},
|
||||
},
|
||||
defaultPkgNlsJSON: {
|
||||
displayName: 'Markdown Language Features',
|
||||
description: 'Provides rich language support for Markdown.',
|
||||
'markdown.preview.breaks.desc':
|
||||
"Sets how line-breaks are rendered in the markdown preview. Setting it to 'true' creates a <br> for newlines inside paragraphs.",
|
||||
'markdown.preview.linkify':
|
||||
'Enable or disable conversion of URL-like text to links in the markdown preview.',
|
||||
'markdown.preview.doubleClickToSwitchToEditor.desc':
|
||||
'Double click in the markdown preview to switch to the editor.',
|
||||
'markdown.preview.fontFamily.desc':
|
||||
'Controls the font family used in the markdown preview.',
|
||||
'markdown.preview.fontSize.desc':
|
||||
'Controls the font size in pixels used in the markdown preview.',
|
||||
'markdown.preview.lineHeight.desc':
|
||||
'Controls the line height used in the markdown preview. This number is relative to the font size.',
|
||||
'markdown.preview.markEditorSelection.desc':
|
||||
'Mark the current editor selection in the markdown preview.',
|
||||
'markdown.preview.scrollEditorWithPreview.desc':
|
||||
'When a markdown preview is scrolled, update the view of the editor.',
|
||||
'markdown.preview.scrollPreviewWithEditor.desc':
|
||||
'When a markdown editor is scrolled, update the view of the preview.',
|
||||
'markdown.preview.title': 'Open Preview',
|
||||
'markdown.previewSide.title': 'Open Preview to the Side',
|
||||
'markdown.showLockedPreviewToSide.title': 'Open Locked Preview to the Side',
|
||||
'markdown.showSource.title': 'Show Source',
|
||||
'markdown.styles.dec':
|
||||
"A list of URLs or local paths to CSS style sheets to use from the markdown preview. Relative paths are interpreted relative to the folder open in the explorer. If there is no open folder, they are interpreted relative to the location of the markdown file. All '\\' need to be written as '\\\\'.",
|
||||
'markdown.showPreviewSecuritySelector.title':
|
||||
'Change Preview Security Settings',
|
||||
'markdown.trace.desc': 'Enable debug logging for the markdown extension.',
|
||||
'markdown.preview.refresh.title': 'Refresh Preview',
|
||||
'markdown.preview.toggleLock.title': 'Toggle Preview Locking',
|
||||
'configuration.markdown.preview.openMarkdownLinks.description':
|
||||
'Controls how links to other markdown files in the markdown preview should be opened.',
|
||||
'configuration.markdown.preview.openMarkdownLinks.inEditor':
|
||||
'Try to open links in the editor',
|
||||
'configuration.markdown.preview.openMarkdownLinks.inPreview':
|
||||
'Try to open links in the markdown preview',
|
||||
'configuration.markdown.links.openLocation.description':
|
||||
'Controls where links in markdown files should be opened.',
|
||||
'configuration.markdown.links.openLocation.currentGroup':
|
||||
'Open links in the active editor group.',
|
||||
'configuration.markdown.links.openLocation.beside':
|
||||
'Open links beside the active editor.',
|
||||
},
|
||||
pkgNlsJSON: {},
|
||||
nlsList: [],
|
||||
extendConfig: {},
|
||||
mode: 'public',
|
||||
};
|
1361
src/forge/Newfile/extensions/alex-ext-public.typescript-language-features-worker.js
Executable file
|
@ -0,0 +1,59 @@
|
|||
export const ExtensionCommand={
|
||||
toggleBlame : 'code.blame.toggleBlame',
|
||||
linkToCommit : 'code.blame.linktocommit',
|
||||
onActive : 'code.blame.extension.active',
|
||||
setPerference : 'code.blame.setPerference',
|
||||
}
|
||||
|
||||
export default class IDEPlugin {
|
||||
// // @ts-ignore
|
||||
// commands: IPluginAPI['commands'];
|
||||
// onActivate: () => void;
|
||||
// linkToCommit: (commitId: string) => void;
|
||||
/**
|
||||
* 插件 ID,用于唯一标识插件
|
||||
*/
|
||||
PLUGIN_ID = 'antcode-communication';
|
||||
|
||||
constructor(onActive, linkToCommit) {
|
||||
this.onActivate = onActive;
|
||||
this.linkToCommit = linkToCommit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活插件
|
||||
*/
|
||||
activate = (ctx) => {
|
||||
const { commands, context } = ctx;
|
||||
this.commands = commands;
|
||||
context.subscriptions.push(
|
||||
commands.registerCommand(ExtensionCommand.onActive, () => {
|
||||
this.onActivate();
|
||||
}),
|
||||
commands.registerCommand(ExtensionCommand.linkToCommit, (params) => {
|
||||
const { commitId } = params;
|
||||
this.linkToCommit(commitId);
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 注销插件,可在此时机清理副作用
|
||||
*/
|
||||
deactivate() {}
|
||||
|
||||
/**
|
||||
* 修改配置项
|
||||
* @param name 配置项名称
|
||||
* @param value 值
|
||||
* @param global 是否全局生效
|
||||
*/
|
||||
setPerference(name, value, global) {
|
||||
this.commands.executeCommand(
|
||||
ExtensionCommand.setPerference,
|
||||
name,
|
||||
value,
|
||||
!!global
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
import React, { Component } from "react";
|
||||
import {UnControlled as CodeMirror} from 'react-codemirror2';
|
||||
import React, { Component, Fragment } from "react";
|
||||
import { UnControlled as CodeMirror } from 'react-codemirror2';
|
||||
import 'codemirror/addon/selection/active-line.js';
|
||||
import 'codemirror/mode/javascript/javascript.js';
|
||||
import 'codemirror/mode/clike/clike';
|
||||
import 'codemirror/mode/css/css';
|
||||
|
||||
import UserSubmitComponent from "./UserSubmitComponent";
|
||||
import CloudIDE from "./cloudIDE";
|
||||
|
||||
import "./index.css";
|
||||
import "./editor.css";
|
||||
|
@ -15,26 +15,28 @@ class m_editor extends Component {
|
|||
super(props);
|
||||
this.state = {
|
||||
editorValue: this.props.content,
|
||||
changeValue:this.props.content,
|
||||
prevHeight:0
|
||||
changeValue: this.props.content,
|
||||
prevHeight: 0,
|
||||
};
|
||||
}
|
||||
componentDidUpdate=(prevProps)=>{
|
||||
if(prevProps && this.props && this.props.content !== prevProps.content){
|
||||
componentDidUpdate = (prevProps) => {
|
||||
if (prevProps && this.props && this.props.content !== prevProps.content) {
|
||||
this.setState({
|
||||
editorValue:this.props.content
|
||||
editorValue: this.props.content
|
||||
})
|
||||
}
|
||||
}
|
||||
changeEditor = (editorValue,data) => {
|
||||
changeEditor = (editorValue, data) => {
|
||||
this.setState({
|
||||
changeValue:editorValue.getValue(),
|
||||
changeValue: editorValue.getValue(),
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { editorValue , changeValue } = this.state;
|
||||
const { readOnly, editorType, currentBranch , descName , checkName } = this.props;
|
||||
const { editorValue, changeValue } = this.state;
|
||||
const { readOnly, editorType, currentBranch, descName, checkName, detail, match: { params },filepath,ideTheme } = this.props;
|
||||
console.log('params')
|
||||
console.log(params)
|
||||
const editor_options = {
|
||||
lineNumbers: "on",
|
||||
lineWrapping: true, //强制换行
|
||||
|
@ -42,7 +44,7 @@ class m_editor extends Component {
|
|||
lineHeight: 24,
|
||||
renderLineHighlight: "line",
|
||||
revealHorizontalRightPadding: 5,
|
||||
placeholder:"请输入内容",
|
||||
placeholder: "请输入内容",
|
||||
readOnly: readOnly,
|
||||
cursorStyle: readOnly ? "underline-thin" : "line",
|
||||
folding: true,
|
||||
|
@ -50,24 +52,29 @@ class m_editor extends Component {
|
|||
automaticLayout: true, // 自适应布局
|
||||
overviewRulerBorder: false, // 不要滚动条的边框
|
||||
scrollBeyondLastLine: false, // 取消代码后面一大段空白
|
||||
styleActiveLine:true,//光标代码高亮
|
||||
styleActiveLine: true,//光标代码高亮
|
||||
minimap: {
|
||||
// 不要小地图
|
||||
enabled: false,
|
||||
},
|
||||
};
|
||||
|
||||
let download_url = detail && detail.download_url;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Fragment>
|
||||
<div className="editorBorderBox">
|
||||
<CodeMirror
|
||||
placeholder="请输入内容"
|
||||
value={editorValue}
|
||||
options={editor_options}
|
||||
onChange={this.changeEditor}
|
||||
/>
|
||||
{!readOnly ?
|
||||
<CodeMirror
|
||||
placeholder="请输入内容"
|
||||
value={editorValue}
|
||||
options={editor_options}
|
||||
onChange={this.changeEditor}
|
||||
/> :
|
||||
<CloudIDE download_url={download_url} params={params} filepath={filepath&&filepath.startsWith('/')?filepath.slice(1):filepath}/>
|
||||
}
|
||||
</div>
|
||||
{!readOnly && (
|
||||
<div className="editorBorderSubmitBox" style={{padding:"20px"}}>
|
||||
<div className="editorBorderSubmitBox" style={{ padding: "20px" }}>
|
||||
<UserSubmitComponent
|
||||
{...this.props}
|
||||
{...this.state}
|
||||
|
@ -78,9 +85,9 @@ class m_editor extends Component {
|
|||
descName={descName}
|
||||
checkName={checkName}
|
||||
></UserSubmitComponent>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,7 +168,7 @@ class Milepost extends Component {
|
|||
|
||||
return (
|
||||
<Spin spinning={spinings}>
|
||||
<div className="main" style={{minHeight:"400px"}}>
|
||||
<div className="main mt20" style={{minHeight:"400px"}}>
|
||||
<div style={{ display: this.state.display }}>
|
||||
<div className="tagdiv" >
|
||||
<span>里程碑{data && data.issue_tags_count}已创建</span>
|
||||
|
|
|
@ -651,7 +651,7 @@ class order extends Component {
|
|||
begin, end, checkedValue, all,search
|
||||
} = this.state;
|
||||
return (
|
||||
<div className="main" style={{padding:"0px"}}>
|
||||
<div className="main mt20" style={{padding:"0px"}}>
|
||||
<div style={{padding:"10px 20px 0px 20px"}}>
|
||||
<div className="topWrapper" style={{ paddingTop: "10px" }}>
|
||||
<ul className="topWrapper_type">
|
||||
|
|
|
@ -13,10 +13,20 @@ const Data = Loadable({
|
|||
loader: () => import('./data'),
|
||||
loading: Loading,
|
||||
})
|
||||
// 跨平台代码同步服务
|
||||
const Reposyncer = Loadable({
|
||||
loader: () => import('./reposyncer'),
|
||||
loading: Loading,
|
||||
})
|
||||
function ServerIndex(props){
|
||||
return(
|
||||
<div className="panels">
|
||||
<Switch {...props}>
|
||||
<Route path="/:owner/:projectsId/server/reposyncer"
|
||||
render={
|
||||
() => (<Reposyncer {...props}/>)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/:owner/:projectsId/server/:id"
|
||||
render={
|
||||
() => (<Data {...props}/>)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React,{useState , useEffect} from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import AgreementModal from './agreementModal';
|
||||
|
||||
function Main(props){
|
||||
|
@ -9,7 +10,9 @@ function Main(props){
|
|||
const { current_user , resetUserInfo, projectDetail, showNotification } = props;
|
||||
|
||||
useEffect(()=>{
|
||||
if(current_user){
|
||||
if(current_user && !current_user.login){
|
||||
props.history.push(`/login?go_page=/${owner}/${projectsId}/server`);
|
||||
}else{
|
||||
setHas_trace_user(current_user.has_trace_user);
|
||||
}
|
||||
},[current_user])
|
||||
|
@ -43,6 +46,16 @@ function Main(props){
|
|||
<a onClick={openDetail} className="btnhover">查看详情</a>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="servername">
|
||||
<img src={require('./img/logo.png')} alt=""/>
|
||||
<Link to={`/${owner}/${projectsId}/server/reposyncer`}>Reposyncer仓库同步系统</Link>
|
||||
</span>
|
||||
<p className="task-hide-2 serverdesc">支持不同开源托管平台自动同步推送/拉取相关代码,实现多平台项目同步开发功能</p>
|
||||
<span className="serverbtn">
|
||||
<Link to={`/${owner}/${projectsId}/server/reposyncer`} className="btnhover">查看详情</Link>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -3,7 +3,7 @@ import DataEmpty from './dataEmpty';
|
|||
import DetectionModal from './detectionModal';
|
||||
import { Table, Spin, message } from 'antd';
|
||||
import axios from 'axios';
|
||||
|
||||
import img from '../Images/img1.png';
|
||||
|
||||
function Data(props) {
|
||||
const [detectionVisible, setDetectionVisible] = useState(false);
|
||||
|
@ -16,6 +16,7 @@ function Data(props) {
|
|||
const [lookResultUrl, setLookResultUrl] = useState(undefined);
|
||||
const [openResultTaskId, setOpenResultTaskId] = useState(undefined);
|
||||
const [viewBase, setViewBase] = useState('https://cjntest.trustie.net/');
|
||||
const [operateTime, setOperateTime] = useState(undefined);
|
||||
|
||||
const { owner, projectsId } = props.match.params;
|
||||
const { isManager, projectDetail, history } = props;
|
||||
|
@ -37,7 +38,9 @@ function Data(props) {
|
|||
}
|
||||
}).then(result => {
|
||||
if (result) {
|
||||
if (Array.isArray(result.data.data)) {
|
||||
if(result.data.code === 501){
|
||||
setOperateTime(result.data.data.operate_time);
|
||||
}else if (Array.isArray(result.data.data)) {
|
||||
setDataSource(result.data.data);
|
||||
setRelayCount(result.data.left_tasks_count);
|
||||
setLookResultUrl(result.data.view_base);
|
||||
|
@ -59,11 +62,13 @@ function Data(props) {
|
|||
}
|
||||
|
||||
useEffect(() => {
|
||||
if(projectDetail && projectDetail.forked_from_project_id){
|
||||
history.go(-1);
|
||||
}else{
|
||||
setSpining(true);
|
||||
Init();
|
||||
if(projectDetail){
|
||||
if(projectDetail.forked_from_project_id){
|
||||
history.go(-1);
|
||||
}else{
|
||||
setSpining(true);
|
||||
Init();
|
||||
}
|
||||
}
|
||||
}, [projectDetail])
|
||||
|
||||
|
@ -76,8 +81,6 @@ function Data(props) {
|
|||
|
||||
|
||||
function iframeHeight(e){
|
||||
console.log('iframeHeight');
|
||||
console.log(e.data);
|
||||
if (e && e.data && viewBase && e.origin && viewBase.indexOf(e.origin)>-1) {
|
||||
let myHeight = JSON.parse(e.data);
|
||||
if (document.querySelector("#htmlIframe")) {
|
||||
|
@ -138,9 +141,7 @@ function Data(props) {
|
|||
function iframeLoad() {
|
||||
try {
|
||||
let myIframe = document.getElementById("htmlIframe");
|
||||
console.log('myIframe', myIframe, myIframe.contentDocument);
|
||||
if (myIframe.contentDocument) {
|
||||
console.log(myIframe.contentDocument.querySelector('.el-main'));
|
||||
myIframe.height = myIframe.contentDocument.querySelector('.el-main').clientHeight + 260;
|
||||
// myIframe.contentDocument.querySelector('.admin-body-container').style.overflow = 'hidden';
|
||||
}
|
||||
|
@ -162,12 +163,17 @@ function Data(props) {
|
|||
/>
|
||||
<div className="servertitle">
|
||||
<span className="systitle">重晴鸟代码溯源系统</span>
|
||||
{isManager && <a className="btnhover" onClick={createCheck}>新建分析</a>}
|
||||
{!operateTime && isManager && <a className="btnhover" onClick={createCheck}>新建分析</a>}
|
||||
</div>
|
||||
<Spin spinning={spining}>
|
||||
<div style={{ minHeight: "400px" }}>
|
||||
{operateTime && <div className='operateBox mt25'>
|
||||
<img src={img} alt='' width={130}/>
|
||||
<div className='font-20 mt20 mb5'>系统维护中</div>
|
||||
<div className='font-17'>预计<span className='timeBox'>{operateTime}小时后</span>代码溯源系统将恢复正常访问,给您带来不便,敬请谅解!</div>
|
||||
</div>}
|
||||
{
|
||||
dataSource && dataSource.length > 0 &&
|
||||
!operateTime && dataSource && dataSource.length > 0 &&
|
||||
<div>
|
||||
<ul className="dataUl">
|
||||
<li className="dataUlhead">
|
||||
|
@ -237,7 +243,7 @@ function Data(props) {
|
|||
</div>
|
||||
}
|
||||
{
|
||||
(dataSource === null || (dataSource && dataSource.length === 0)) &&
|
||||
!operateTime && (dataSource === null || (dataSource && dataSource.length === 0)) &&
|
||||
<DataEmpty />
|
||||
}
|
||||
</div>
|
||||
|
|
After Width: | Height: | Size: 276 B |
After Width: | Height: | Size: 262 B |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 3.2 KiB |
|
@ -0,0 +1,8 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="23.589" height="23.589" viewBox="0 0 23.589 23.589">
|
||||
<g id="gitee" transform="translate(0)">
|
||||
<g id="Group" transform="translate(0 0)">
|
||||
<ellipse id="Combined-Shape" cx="11.795" cy="11.795" rx="11.795" ry="11.795" fill="#c71d23"/>
|
||||
<path id="G" d="M32.458,25.178h-6.7a.583.583,0,0,0-.583.582v1.456a.582.582,0,0,0,.582.583h4.078a.582.582,0,0,1,.582.582h0v.146h0v.146a1.747,1.747,0,0,1-1.747,1.747H23.138a.582.582,0,0,1-.582-.582V24.3A1.747,1.747,0,0,1,24.3,22.557h8.153a.584.584,0,0,0,.583-.582V20.518a.582.582,0,0,0-.582-.583H24.3A4.368,4.368,0,0,0,19.935,24.3v8.154a.582.582,0,0,0,.582.582h8.591a3.931,3.931,0,0,0,3.931-3.931V25.76A.582.582,0,0,0,32.458,25.178Z" transform="translate(-14.693 -14.693)" fill="#fff" fill-rule="evenodd"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 822 B |
After Width: | Height: | Size: 2.5 KiB |
|
@ -0,0 +1,3 @@
|
|||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="23.585" height="23.587" viewBox="0 0 23.585 23.587">
|
||||
<path id="路径_46" data-name="路径 46" d="M11.831,0A11.914,11.914,0,0,0,.136,10.156,12.116,12.116,0,0,0,8.089,23.568c.6.111.806-.267.806-.586V20.925c-3.306.735-4-1.626-4-1.626a3.23,3.23,0,0,0-1.315-1.774c-1.068-.742.087-.742.087-.742A2.492,2.492,0,0,1,5.473,18.03,2.539,2.539,0,0,0,6.99,19.266a2.481,2.481,0,0,0,1.927-.226,2.593,2.593,0,0,1,.727-1.618c-2.63-.3-5.391-1.344-5.391-5.938A4.734,4.734,0,0,1,5.466,8.239a4.5,4.5,0,0,1,.116-3.2s1-.327,3.255,1.24a10.968,10.968,0,0,1,5.929,0c2.26-1.566,3.248-1.24,3.248-1.24a4.475,4.475,0,0,1,.145,3.177,4.734,4.734,0,0,1,1.213,3.244c0,4.647-2.768,5.664-5.406,5.938a2.893,2.893,0,0,1,.806,2.227c0,1.618,0,2.925,0,3.318s.211.7.814.579a12.12,12.12,0,0,0,7.824-13.379A11.917,11.917,0,0,0,11.831,0Z" transform="translate(0.018 0)" fill="#1a1414" fill-rule="evenodd"/>
|
||||
</svg>
|
After Width: | Height: | Size: 952 B |
After Width: | Height: | Size: 6.5 KiB |
|
@ -451,4 +451,14 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.operateBox{
|
||||
color: #333;
|
||||
text-align: center;
|
||||
background-color:#fafcff;
|
||||
border-radius:4px 4px 0px 0px;
|
||||
padding: 50px 0 80px;
|
||||
.timeBox{
|
||||
color: rgba(70, 106, 255, 1)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
import React, {useState} from 'react';
|
||||
import { Button, Modal, Input, Select, message } from 'antd';
|
||||
import axios from 'axios';
|
||||
const {Option} = Select;
|
||||
|
||||
function DeleteBox({owner, projectsId, visible, setVisible, createJobBy, branchOptions, reload}) {
|
||||
const [error, setError] = useState(undefined);
|
||||
const [errorByOther, setErrorByOther] = useState(undefined);
|
||||
const [branch, setBranch] = useState(undefined);
|
||||
const [branchByOther, setBranchByOther] = useState(undefined);
|
||||
|
||||
// 新建同步分支点击函数
|
||||
function createNew(){
|
||||
if(branch && branchByOther){
|
||||
// 新建同步分支
|
||||
const param = {
|
||||
gitlink_branch: branch,
|
||||
job_type: 'TwoWay',
|
||||
github_branch: undefined,
|
||||
gitee_branch: undefined
|
||||
}
|
||||
createJobBy === 'Github' ? (param.github_branch = branchByOther) : (param.gitee_branch = branchByOther)
|
||||
axios.post(`/${owner}/${projectsId}/synchronizes/create_jobs.json`,param).then(res=>{
|
||||
if(res && res.data.message === "success"){
|
||||
setBranch(undefined);
|
||||
setBranchByOther(undefined);
|
||||
reload && reload(Math.random());
|
||||
message.success('新建成功');
|
||||
setVisible(false);
|
||||
}
|
||||
})
|
||||
}else{
|
||||
!branch && setError('请选择仓库分支')
|
||||
!branchByOther && setErrorByOther('请输入仓库分支')
|
||||
}
|
||||
}
|
||||
|
||||
return(
|
||||
<Modal
|
||||
title="新建同步分支"
|
||||
visible={visible}
|
||||
onCancel={()=>{setVisible(false)}}
|
||||
footer={<div><Button style={{width: '104px', height:'36px'}} onClick={()=>{setVisible(false)}}>取消</Button><Button type="primary" style={{width: '104px', height:'36px', marginLeft: '40px'}} onClick={createNew}>确认</Button></div>}
|
||||
width={550}
|
||||
className="cancelBound createJobBox"
|
||||
>
|
||||
<div className="itemBox mt10">
|
||||
<label className="labelBox font-16"><i className="iconfont icon-a-bitian2x font-12"></i> {createJobBy}分支:</label>
|
||||
<Input placeholder="请输入分支名称" className="inputBox" value={branchByOther} onChange={(e)=>setBranchByOther(e.target.value)} maxLength={50}/>
|
||||
<div className="errorBox">{errorByOther}</div>
|
||||
</div>
|
||||
<div className="itemBox mt30 mb20">
|
||||
<label className="labelBox font-16"><i className="iconfont icon-a-bitian2x font-12"></i> GitLink分支:</label>
|
||||
<Select
|
||||
value={branch}
|
||||
onSelect={(e) => {setBranch(e)}}
|
||||
showSearch
|
||||
className="inputBox"
|
||||
dropdownMatchSelectWidth={false}
|
||||
dropdownClassName="overlihide"
|
||||
placeholder="请选择仓库分支"
|
||||
>
|
||||
{branchOptions && branchOptions.map((item, key) => {
|
||||
return (
|
||||
<Option key={key + 1} value={item.name}>
|
||||
{item.name}
|
||||
</Option>
|
||||
)})}
|
||||
</Select>
|
||||
<div className="errorBox">{error}</div>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export default DeleteBox;
|
|
@ -0,0 +1,97 @@
|
|||
import React, {forwardRef} from "react";
|
||||
import { Button, Form, Input, message } from "antd";
|
||||
import gitHub from '../../img/github.png';
|
||||
import gitee from '../../img/gitee.png';
|
||||
import '../index.scss';
|
||||
import axios from "axios";
|
||||
|
||||
function EditStore(props){
|
||||
const { form, history} = props;
|
||||
const { owner , projectsId } = props.match.params;
|
||||
const { getFieldDecorator, validateFields , setFieldsValue, setFields } = form;
|
||||
|
||||
function submit() {
|
||||
validateFields((error,values)=>{
|
||||
setFields({
|
||||
'github_address':{value: values.github_address, errors: null},
|
||||
'github_token':{value: values.github_token, errors: null},
|
||||
'gitee_address':{value: values.gitee_address, errors: null},
|
||||
'gitee_token':{value: values.gitee_token, errors: null}
|
||||
})
|
||||
if(!error){
|
||||
// 处理空值
|
||||
for(let i in values){
|
||||
if(!values[i]){
|
||||
delete values[i];
|
||||
}
|
||||
}
|
||||
const keysArr = Object.keys(values);
|
||||
if(keysArr.indexOf('github_address') === -1 && keysArr.indexOf('gitee_address') === -1){
|
||||
// 校验必填一个github或者gitee地址
|
||||
form.setFields({github_address: {value:values.github_address,errors:[new Error('请至少输入一个地址')]}});
|
||||
form.setFields({gitee_address: {value:values.gitee_address,errors:[new Error('请至少输入一个地址')]}});
|
||||
}else if(keysArr.indexOf('github_address') !== -1 && keysArr.indexOf('github_token') === -1){
|
||||
form.setFields({github_token: {value:values.github_token,errors:[new Error('请输入Github的授权token')]}});
|
||||
}else if(keysArr.indexOf('gitee_address') !== -1 && keysArr.indexOf('gitee_token') === -1){
|
||||
form.setFields({gitee_token: {value:values.gitee_token,errors:[new Error('请输入Gitee的授权token')]}});
|
||||
}else{
|
||||
axios.post(`/${owner}/${projectsId}/synchronizes.json`,values).then(res=>{
|
||||
if(res && res.data.message === "success"){
|
||||
message.success('绑定成功');
|
||||
window.location.href = `/${owner}/${projectsId}/server/reposyncer`;
|
||||
}else{
|
||||
// message.error('绑定失败');
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return <div className="storeListBox mt20">
|
||||
<div className="registerBox">
|
||||
<Form>
|
||||
<div className="storeTitle pb10 mb15"><img src={gitHub} alt="" className="storeLogo"/></div>
|
||||
<Form.Item label="Github同步仓库地址" className="storeFormItem">
|
||||
{getFieldDecorator("github_address",{
|
||||
rules:[]
|
||||
})(
|
||||
<Input placeholder="请输入Github目标版本库地址" className="storeInput"/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label="Github同步仓库授权验证" className="storeFormItem">
|
||||
{getFieldDecorator("github_token",{
|
||||
rules:[]
|
||||
})(
|
||||
<Input addonBefore="token" placeholder="请输入Github的授权token" className="storeInput"/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<div className="storeTitle pb10 mb15 pt20"><img src={gitee} alt="" className="storeLogo"/></div>
|
||||
<Form.Item label="Gitee同步仓库地址" className="storeFormItem">
|
||||
{getFieldDecorator("gitee_address",{
|
||||
rules:[]
|
||||
})(
|
||||
<Input placeholder="请输入Gitee目标版本库地址" className="storeInput"/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label="Gitee同步仓库授权验证" className="storeFormItem">
|
||||
{getFieldDecorator("gitee_token",{
|
||||
rules:[]
|
||||
})(
|
||||
<Input addonBefore="token" placeholder="请输入Gitee的授权token" className="storeInput"/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<div className="tipStoreBox">
|
||||
1、在开启仓库同步前,您需要绑定并授权目标同步仓库;<br/>
|
||||
2、完成仓库绑定后,需对仓库内的分支进行二次绑定。当已绑定的分支有代码提交、代码推送变更,将实时同步更新至其他仓库;<br/>
|
||||
3、目前仅提供Github与Gitee平台的仓库同步功能,每个平台支持同时同步一个仓库;
|
||||
</div>
|
||||
<Form.Item>
|
||||
<Button type="primary" style={{width: '112px', height: '36px'}} onClick={submit}>确认绑定</Button>
|
||||
<Button style={{width: '112px', height: '36px'}} className="ml40" onClick={()=>{history.goBack(-1)}}>取消</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
export default Form.create()(forwardRef(EditStore));
|
|
@ -0,0 +1,165 @@
|
|||
import React, {useState} from "react";
|
||||
import { Table, Modal, Button, message } from 'antd';
|
||||
import { Link } from "react-router-dom";
|
||||
import gitHub1 from '../../img/github2.svg';
|
||||
import gitee1 from '../../img/gitee1.svg';
|
||||
import anniu from '../../img/anniu.png';
|
||||
import anniu2 from '../../img/anniu2.png';
|
||||
import '../index.scss';
|
||||
import { useEffect } from "react";
|
||||
import axios from "axios";
|
||||
import CreateJobModal from './createJobModal';
|
||||
import Nodata from "../../../Nodata";
|
||||
|
||||
function RecordList(props){
|
||||
const { owner , projectsId, type } = props.match.params;
|
||||
const { storeDetail} = props;
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [data, setData] = useState([]);
|
||||
// table
|
||||
const [current, setCurrent] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
const [expandedRowKeys, setExpandedRowKeys] = useState([]);
|
||||
const [deleteRecordId, setDeleteRecordId] = useState(undefined);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [reload, setReload] = useState(undefined);
|
||||
const [visibleNew, setVisibleNew] = useState(false);
|
||||
const [branchOptions, setBranchOptions] = useState([]);
|
||||
const [logInfo, setLogInfo]= useState([]);
|
||||
|
||||
useEffect(()=>{
|
||||
axios.get(`/${owner}/${projectsId}/pulls/get_branches.json`, {}).then(res=>{
|
||||
res && setBranchOptions(res.data);
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(()=>{
|
||||
// 获取仓库同步记录
|
||||
axios.get(`/${owner}/${projectsId}/synchronizes/jobs.json`, {params: {type: type, limit: pageSize, page: current}}).then(res=>{
|
||||
if(res && res.data && res.data.message === "success"){
|
||||
// 处理从后往前删除
|
||||
if(current !== 1 && res.data.data.length === 0){
|
||||
setCurrent(current-1);
|
||||
}else{
|
||||
res.data.data.map(item=>{
|
||||
item.create_time = item.create_time.replace('T', ' ')
|
||||
})
|
||||
setData(res.data.data);
|
||||
setTotal(res.data.count);
|
||||
}
|
||||
}
|
||||
})
|
||||
},[reload, pageSize, current])
|
||||
|
||||
// 同步状态errorBox
|
||||
let columns = [
|
||||
{ title: '序号', dataIndex: 'index', className:"recordColumns", render: (text, item, index) => <span>{(current-1)*pageSize+index + 1}</span> },
|
||||
{ title: type === 'github' ? 'Github分支' : 'Gitee分支', dataIndex: type === 'github' ? 'github_branch': 'gitee_branch', className:"recordColumns taskName"},
|
||||
{ title: 'GitLink分支', dataIndex: 'gitlink_branch', className:"recordColumns"},
|
||||
{ title: '创建时间', dataIndex: 'create_time', className:"primaryColor recordColumns"},
|
||||
{ title: '同步状态', dataIndex: 'status', className:"recordColumns", render: ()=><span className="accomplish statusBox">开启中</span>},
|
||||
{ title: '操作', dataIndex: 'action', align: 'center', className:"primaryColor recordColumns", render: (text, item)=><span className="deleteRecord" onClick={()=>{setVisible(true);setDeleteRecordId(item.id);}}>删除</span>},
|
||||
]
|
||||
|
||||
const customExpandIcon = (props) => {
|
||||
if (props.expanded) {
|
||||
return <a className='primaryColor' onClick={e => {
|
||||
props.onExpand(props.record, e);
|
||||
}}>查看日志<img alt="" src={anniu2} style={{width: '18px'}} className="ml5"/></a>
|
||||
} else {
|
||||
return <a className='primaryColor' onClick={e => {
|
||||
axios.get(`/${owner}/${projectsId}/synchronizes/job_logs.json`, {params:{job_id: props.record.id}}).then(res=>{
|
||||
if(res && res.data){
|
||||
setLogInfo(res.data.data);
|
||||
props.onExpand(props.record, e);
|
||||
}
|
||||
})
|
||||
}}>查看日志<img alt="" src={anniu} style={{width: '18px'}} className="ml5"/></a>
|
||||
}
|
||||
}
|
||||
|
||||
const expandRow = (record) => {
|
||||
return logInfo && logInfo.length > 0 ? <div className="expandBox">
|
||||
{logInfo.map(item=>{
|
||||
return <div className="expandCont" key={item.id}>
|
||||
{item.create_time + ' [' + item.log_type + '] ' + item.log}
|
||||
</div>
|
||||
})}
|
||||
</div> : <Nodata _html="暂无数据"/>}
|
||||
|
||||
// 展开收起行回调
|
||||
function onExpand(expanded, record){
|
||||
const keys = new Set(expandedRowKeys);
|
||||
if(expanded){
|
||||
keys.add(record.id);
|
||||
}else{
|
||||
keys.delete(record.id);
|
||||
}
|
||||
setExpandedRowKeys(Array.from(keys));
|
||||
}
|
||||
|
||||
// 改变pagesize
|
||||
function onShowSizeChange(current, pageSize){
|
||||
window.scrollTo(0, 0);
|
||||
setCurrent(1);
|
||||
setPageSize(pageSize);
|
||||
}
|
||||
|
||||
// 切换页数
|
||||
function changePage(page, pageSize){
|
||||
window.scrollTo(0, 0);
|
||||
setCurrent(page);
|
||||
}
|
||||
|
||||
// 删除同步分支
|
||||
function deleteRecord(){
|
||||
deleteRecordId && axios.delete(`/${owner}/${projectsId}/synchronizes/delete_job.json`, {data: {job_id: deleteRecordId}}).then(res=>{
|
||||
if(res && res.data.message === "success"){
|
||||
setReload(Math.random());
|
||||
message.success('删除成功');
|
||||
setVisible(false);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return <div className="storeListBox">
|
||||
<div className="font-16">
|
||||
<Link to={`/${owner}/${projectsId}/server/reposyncer`} className="blueSpan">仓库绑定</Link>
|
||||
<span> > 同步分支</span>
|
||||
</div>
|
||||
<div className="headBox font-16 pl15 mt20 mb10">
|
||||
<img src={type === 'github' ? gitHub1 : gitee1} alt="" className="mr10 mb5"/>
|
||||
<span>{type === 'github' ? 'Github' : 'Gitee'}仓库地址</span>
|
||||
{storeDetail && <a className="ml15 blueSpan" href={type === 'github' ? storeDetail.github_address : storeDetail.gitee_address} target="_blank">{type === 'github' ? storeDetail.github_address : storeDetail.gitee_address}</a>}
|
||||
<Button style={{width: '94px', height:'36px', padding: 0}} className="blue_border_but createJobBut" onClick={()=>{setVisibleNew(true);}}>新建同步分支</Button>
|
||||
</div>
|
||||
<Table
|
||||
className="storeListTable"
|
||||
loading={loading}
|
||||
columns={columns}
|
||||
dataSource={data}
|
||||
expandedRowRender={expandRow}
|
||||
expandIconColumnIndex={5}
|
||||
expandIconAsCell={false}
|
||||
expandIcon={customExpandIcon}
|
||||
rowKey={'id'}
|
||||
expandedRowKeys={expandedRowKeys}
|
||||
onExpand={onExpand}
|
||||
pagination={{current: current, pageSize: pageSize, total: total, showSizeChanger: true, onShowSizeChange:onShowSizeChange, showQuickJumper: true, onChange: changePage}}
|
||||
/>
|
||||
<Modal
|
||||
title="删除同步分支"
|
||||
visible={visible}
|
||||
onCancel={()=>{setVisible(false)}}
|
||||
footer={<div><Button style={{width: '90px', height:'36px'}} onClick={()=>{setVisible(false)}}>取消</Button><Button className="okBut" style={{width: '90px', height:'36px'}} onClick={deleteRecord}>确认删除</Button></div>}
|
||||
width={535}
|
||||
className="cancelBound"
|
||||
>
|
||||
<div className="bTilModal font-16"><span className="errorRedSpan font-18 mr20 mt20 ml15">!</span>确认删除此同步分支?</div>
|
||||
<div className="sTilModal"> 删除同步分支后,系统将清除此条同步数据及日志,对应分支也将停止自动同步</div>
|
||||
</Modal>
|
||||
<CreateJobModal owner={owner} projectsId={projectsId} visible={visibleNew} setVisible={setVisibleNew} createJobBy={type === 'github' ? 'Github' : 'Gitee'} branchOptions={branchOptions} reload={setReload}/>
|
||||
</div>
|
||||
}
|
||||
export default RecordList;
|
|
@ -0,0 +1,89 @@
|
|||
import React, { useEffect, useState} from "react";
|
||||
import { Button, Modal, Icon, message, Select, Input, Tooltip } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import gitHub1 from '../../img/github2.svg';
|
||||
import gitee1 from '../../img/gitee1.svg';
|
||||
import logo from '../../img/logo2.png';
|
||||
import '../index.scss';
|
||||
import axios from "axios";
|
||||
import CreateJobModal from './createJobModal';
|
||||
|
||||
function StoreList(props){
|
||||
const { storeDetail} = props;
|
||||
const { owner , projectsId } = props.match.params;
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [visibleNew, setVisibleNew] = useState(false);
|
||||
const [createJobBy, setCreateJobBy] = useState("Github");
|
||||
const [branchOptions, setBranchOptions] = useState([]);
|
||||
|
||||
useEffect(()=>{
|
||||
axios.get(`/${owner}/${projectsId}/pulls/get_branches.json`, {}).then(res=>{
|
||||
res && setBranchOptions(res.data);
|
||||
})
|
||||
}, [])
|
||||
|
||||
// 取消仓库绑定点击函数
|
||||
function updateStore(){
|
||||
axios.delete(`/${owner}/${projectsId}/synchronizes/delete.json`).then(res=>{
|
||||
if(res && res.data.message === "success"){
|
||||
message.success('取消绑定成功');
|
||||
setVisible(false);
|
||||
props.history.push(`/${owner}/${projectsId}/server`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
return <div className="storeListBox">
|
||||
<div className="headBox font-16 pl15">Reposyncer仓库同步系统
|
||||
{storeDetail !== null && <Tooltip title="Reposyncer仓库同步系统提供跨托管平台的项目协同开发同步功能。支持用户在任何一个托管平台上的代码提交、代码推送、合并请求等操作自动同步至其他托管平台。不仅增加每个开源项目与开发者的流量,也使不同平台的开源项目维护与更新变得方便与快捷" overlayStyle={{width: 400}}><span className="helpBox1 font-12 ml10">?</span></Tooltip>}
|
||||
</div>
|
||||
{/* 空数据 */}
|
||||
{!storeDetail && <div className="nullStoreBox mt25">
|
||||
<img src={logo} alt="" className="loBox mt50"/>
|
||||
<p className="font-22 mt10">欢迎使用跨平台代码同步系统</p>
|
||||
<div className="introBox font-15">跨平台代码同步系统提供跨托管平台的项目协同开发同步功能。支持用户在任何一个托管平台上的代码提交、代码推送、合并请求等操作自动同步至其他托管平台。不仅增加每个开源项目与开发者的流量,也使不同平台的开源项目维护与更新变得方便与快捷</div>
|
||||
<div className="borBox"></div>
|
||||
<Button type="primary" style={{width: '112px', height: '36px'}}><Link to={`/${owner}/${projectsId}/server/reposyncer/store/edit`}>开始体验</Link></Button>
|
||||
</div>}
|
||||
{/* 已绑定仓库信息 */}
|
||||
{storeDetail && <div className="listStore mt20">
|
||||
<div className="storeTitle pb5 mb5 font-18">已绑定仓库地址<Icon type="exclamation-circle" style={{color: '#466aff'}} className="ml10 font-14"/><span className="ml5 font-14" style={{fontWeight: 'normal'}}>对已绑定的仓库,请添加同步分支实现分支的跨平台双向同步</span></div>
|
||||
{storeDetail && storeDetail.github_address && <div className="showStoreInfo dashedBor">
|
||||
<div className="storeInfoBox">
|
||||
<div className="font-15 sTil"><img src={gitHub1} alt="" className="mr10"/><span>Github仓库地址</span></div>
|
||||
<span>{storeDetail && storeDetail.github_address}</span>
|
||||
</div>
|
||||
<div>
|
||||
<Button style={{width: '94px', height:'36px', padding: 0}} className="blue_border_but mr20"><Link to={`/${owner}/${projectsId}/server/reposyncer/record/github`}>查看同步分支</Link></Button>
|
||||
<Button style={{width: '94px', height:'36px', padding: 0}} className="blue_border_but" onClick={()=>{setVisibleNew(true);setCreateJobBy('Github')}}>新建同步分支</Button>
|
||||
</div>
|
||||
</div>}
|
||||
{storeDetail && storeDetail.gitee_address && <div className="showStoreInfo">
|
||||
<div className="storeInfoBox">
|
||||
<div className="font-15 sTil"><img src={gitee1} alt="" className="mr10"/><span>Gitee仓库地址</span></div>
|
||||
<span>{storeDetail.gitee_address}</span>
|
||||
</div>
|
||||
<div>
|
||||
<Button style={{width: '94px', height:'36px', padding: 0}} className="blue_border_but mr20"><Link to={`/${owner}/${projectsId}/server/reposyncer/record/gitee`}>查看同步分支</Link></Button>
|
||||
<Button style={{width: '94px', height:'36px', padding: 0}} className="blue_border_but" onClick={()=>{setVisibleNew(true);setCreateJobBy('Gitee')}}>新建同步分支</Button>
|
||||
</div>
|
||||
</div>}
|
||||
{/* <Button type="primary" style={{width: '134px', height:'36px', padding: 0}} className="mt30"><Link to={`/${owner}/${projectsId}/server/reposyncer/store/edit`}>更改绑定仓库信息</Link></Button> */}
|
||||
<Button style={{width: '134px', height:'36px'}} className="red_border_but mt40" onClick={()=>{setVisible(true)}}>清空仓库绑定</Button>
|
||||
</div>}
|
||||
<Modal
|
||||
title="取消绑定"
|
||||
visible={visible}
|
||||
onCancel={()=>{setVisible(false)}}
|
||||
footer={<div><Button style={{width: '90px', height:'36px'}} onClick={()=>{setVisible(false)}}>取消</Button><Button className="okBut" style={{width: '90px', height:'36px'}} onClick={updateStore}>确认清空</Button></div>}
|
||||
width={535}
|
||||
className="cancelBound"
|
||||
>
|
||||
<div className="bTilModal font-16"><span className="errorRedSpan font-18 mr20 mt20 ml15">!</span>您确定要清空已绑定仓库?</div>
|
||||
<div className="sTilModal">此操作将清空所有绑定仓库/绑定分支及同步日志,请谨慎操作</div>
|
||||
</Modal>
|
||||
<CreateJobModal owner={owner} projectsId={projectsId} visible={visibleNew} setVisible={setVisibleNew} createJobBy={createJobBy} branchOptions={branchOptions}/>
|
||||
</div>
|
||||
}
|
||||
export default StoreList;
|
|
@ -0,0 +1,64 @@
|
|||
import React, {useState, useEffect} from "react";
|
||||
import { Button, Tooltip } from "antd";
|
||||
import './index.scss';
|
||||
import logo from '../img/logo2.png';
|
||||
import Loadable from "react-loadable";
|
||||
import { Route, Switch } from "react-router";
|
||||
import Loading from "../../../Loading";
|
||||
import { Link } from "react-router-dom";
|
||||
import axios from 'axios';
|
||||
|
||||
// 编辑同步仓库页面
|
||||
const EditStore = Loadable({
|
||||
loader: () => import("./component/editStore"),
|
||||
loading: Loading,
|
||||
});
|
||||
// 同步仓库页面
|
||||
const StoreList = Loadable({
|
||||
loader: () => import("./component/storeList"),
|
||||
loading: Loading,
|
||||
});
|
||||
// 跨平台代码同步服务-同步记录页面
|
||||
const RecordList = Loadable({
|
||||
loader: () => import("./component/recordList"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
function Reposyncer(propsF){
|
||||
const { owner , projectsId } = propsF.match.params;
|
||||
|
||||
const [storeDetail, setStoreDetail] = useState(null);
|
||||
|
||||
useEffect(()=>{
|
||||
// 获取仓库同步详情
|
||||
axios.get(`/${owner}/${projectsId}/synchronizes.json`).then(res=>{
|
||||
if(res && res.data.message === "success"){
|
||||
setStoreDetail(res.data.data);
|
||||
}
|
||||
})
|
||||
},[])
|
||||
|
||||
return <div className="reposyncerBox">
|
||||
<Switch {...propsF}>
|
||||
<Route
|
||||
path="/:owner/:projectsId/server/reposyncer/record/:type"
|
||||
render={(props) => (
|
||||
<RecordList {...propsF} {...props} storeDetail={storeDetail}/>
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/:owner/:projectsId/server/reposyncer/store/edit"
|
||||
render={(props) => (
|
||||
<EditStore {...propsF} {...props}/>
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/:owner/:projectsId/server/reposyncer"
|
||||
render={(props) => (
|
||||
<StoreList {...propsF} {...props} storeDetail={storeDetail}/>
|
||||
)}
|
||||
></Route>
|
||||
</Switch>
|
||||
</div>
|
||||
}
|
||||
export default Reposyncer;
|
|
@ -0,0 +1,295 @@
|
|||
.red_border_but, .red_border_but:focus{
|
||||
color:#f60011;
|
||||
background-color:rgba(196, 0, 14, 0.09);
|
||||
border:1px solid #f60011;
|
||||
border-radius:5px;
|
||||
&:hover{
|
||||
color:#f60011;
|
||||
background-color:rgba(196, 0, 14, 0.18);
|
||||
border-color:#ff727c;
|
||||
}
|
||||
&:active{
|
||||
color:#f60011;
|
||||
background-color:rgba(196, 0, 14, 0.22);
|
||||
border-color:#f60011;
|
||||
}
|
||||
}
|
||||
.blue_border_but, .blue_border_but:focus{
|
||||
color:$primary-color;
|
||||
background-color:rgba(70, 106, 255, 0.09);
|
||||
border:1px solid #1a47ff;
|
||||
border-radius:5px;
|
||||
&:hover{
|
||||
color:#6684fe;
|
||||
background-color:rgba(70, 106, 255, 0.09);;
|
||||
border-color:#6684fe;
|
||||
}
|
||||
&:active{
|
||||
color:#1a47ff;
|
||||
background-color:rgba(70, 106, 255, 0.09);
|
||||
border-color:#1a47ff;
|
||||
}
|
||||
}
|
||||
.reposyncerBox .headBox, .storeListBox .headBox{
|
||||
height:60px;
|
||||
line-height: 60px;
|
||||
background-color:#fafcff;
|
||||
border:1px solid rgba(42, 97, 255, 0.23);
|
||||
border-radius:3px 3px 0px 0px;
|
||||
color:#333333;
|
||||
position: relative;
|
||||
}
|
||||
.reposyncerBox{
|
||||
padding-bottom: 60px;
|
||||
.helpBox1{
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 50%;
|
||||
color: white;
|
||||
background-color: #466aff;
|
||||
line-height: normal;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: default;
|
||||
}
|
||||
.nullStoreBox{
|
||||
background-color:#fafcff;
|
||||
border-radius:4px 4px 0px 0px;
|
||||
text-align: center;
|
||||
color:#333333;
|
||||
padding-bottom: 65px;
|
||||
.loBox{width: 68px;}
|
||||
.introBox{
|
||||
color:#666666;
|
||||
width: 57%;
|
||||
margin: 15px auto;
|
||||
}
|
||||
.borBox{
|
||||
width: 45%;
|
||||
margin: 0 auto 20px;
|
||||
border-bottom: 1px solid rgba(90, 117, 193, 0.23);
|
||||
}
|
||||
}
|
||||
.rightContentBox{
|
||||
display: flex;
|
||||
.leftNav{
|
||||
width: 185px;
|
||||
margin-right: 36px;
|
||||
background-size: 100% 100%;
|
||||
background-image: url('../img/bg1.png');
|
||||
.oneBox{
|
||||
padding: 15px;
|
||||
color:#4c5b76;
|
||||
display: block;
|
||||
&.active{
|
||||
position: relative;
|
||||
background-color:rgba(70, 106, 255, 0.06);
|
||||
color: $primary-color;
|
||||
&::before{
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 4px;
|
||||
height: 86%;
|
||||
left: 0;
|
||||
top: 4px;
|
||||
background-color: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.storeListBox{
|
||||
.storeListTable{
|
||||
width: 100%;
|
||||
}
|
||||
.blueSpan{
|
||||
color: $primary-color;
|
||||
}
|
||||
.createJobBut{
|
||||
position: absolute;
|
||||
top: 11px;
|
||||
right: 40px;
|
||||
}
|
||||
.storeTitle{
|
||||
font-weight:700;
|
||||
color:#151d40;
|
||||
border-bottom: 1px solid #e0e6f5;;
|
||||
}
|
||||
.registerBox{
|
||||
width: 85%;
|
||||
.storeLogo{
|
||||
width: 75px;
|
||||
}
|
||||
.storeFormItem{
|
||||
width: 70%;
|
||||
}
|
||||
.has-error .ant-input, .has-error .ant-input:hover, .has-error .storeInput .ant-input{
|
||||
border-color:#f60011;
|
||||
}
|
||||
#gitHubToken, #giteeToken, .storeInput{
|
||||
border-color: #9eaacb;
|
||||
height: 36px;
|
||||
&:hover{border-color: $primary-color;}
|
||||
}
|
||||
.storeInput .ant-input-group-addon, .storeInput .ant-input{
|
||||
border-color: #9eaacb;
|
||||
}
|
||||
.tipStoreBox{
|
||||
color: #4c5b76;
|
||||
line-height: 30px;
|
||||
padding: 10px 0 30px;
|
||||
}
|
||||
}
|
||||
.listStore{
|
||||
.showStoreInfo{
|
||||
padding: 20px 0 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
&.dashedBor{
|
||||
border-bottom: 1px dashed #e0e6f5;
|
||||
}
|
||||
}
|
||||
.linkSpan{
|
||||
color:$primary-color;
|
||||
&:hover{color: $primary-color-hover;}
|
||||
}
|
||||
.storeInfoBox{color: #666;}
|
||||
.sTil{
|
||||
color:#202d40;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
.expandBox{
|
||||
background-color: #171b23;
|
||||
color: white;
|
||||
margin: -16px;
|
||||
padding-bottom: 16px;
|
||||
.expandCont{
|
||||
word-break: break-all;
|
||||
padding: 16px 16px 0;
|
||||
}
|
||||
}
|
||||
th.recordColumns{
|
||||
background-color: rgba(90, 117, 193, 0);
|
||||
.ant-table-column-title{
|
||||
font-family:PingFang SC;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color:#202d40;
|
||||
}
|
||||
}
|
||||
.ant-table-tbody > tr > td.recordColumns{
|
||||
color: #333;
|
||||
font-size: 15px;
|
||||
border-bottom: 1px dashed #e0e6f5;
|
||||
&.primaryColor{color: $primary-color;}
|
||||
}
|
||||
tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) td.recordColumns{
|
||||
background-color:#f8f9ff !important;
|
||||
}
|
||||
.statusBox{
|
||||
width:58px;
|
||||
height:32px;
|
||||
border-radius:4px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
&.errorBox{
|
||||
color:#ff0c0c;
|
||||
background-color:rgba(230, 0, 6, 0.1);
|
||||
border:1px solid #fcb6c2;;
|
||||
}
|
||||
&.accomplish{
|
||||
color:#009c44;
|
||||
background-color:rgba(83, 255, 163, 0.1);
|
||||
border:1px solid #00b843;;
|
||||
}
|
||||
}
|
||||
.deleteRecord{
|
||||
color:#f60011;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
padding-left: 20px;
|
||||
&::before{
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
left: 5px;
|
||||
width: 1px;
|
||||
height: 9px;
|
||||
background-color: #dfdfdf;;
|
||||
}
|
||||
}
|
||||
.primaryColor{color: $primary-color;}
|
||||
}
|
||||
.cancelBound{
|
||||
.ant-modal-header{
|
||||
padding: 10px 25px;
|
||||
background-color: #f8f8f8;
|
||||
.ant-modal-title{
|
||||
font-size: 16px;
|
||||
text-align: left;
|
||||
font-weight: normal !important;
|
||||
}
|
||||
}
|
||||
.ant-modal-close{
|
||||
top: 0 !important;
|
||||
.ant-modal-close-x{font-size: 22px;}
|
||||
}
|
||||
.bTilModal{
|
||||
color:#333333;
|
||||
.errorRedSpan{
|
||||
display: inline-block;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
color: white;
|
||||
background-color:#ca0002;
|
||||
line-height: 36px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.sTilModal{
|
||||
color:#666666;
|
||||
margin: 30px 0 40px 70px;
|
||||
}
|
||||
.ant-modal-footer{
|
||||
border-top: none;
|
||||
text-align: center;
|
||||
padding-bottom: 50px;
|
||||
.okBut, .okBut:focus{
|
||||
color:#df0002;
|
||||
border-color: #d9d9d9;
|
||||
margin-left: 43px;
|
||||
&:hover{
|
||||
border-color:#ff727c;
|
||||
}
|
||||
&:active{
|
||||
border-color:#f60011;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.createJobBox{
|
||||
.itemBox{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
.errorBox{
|
||||
position: absolute;
|
||||
top: 35px;
|
||||
left: 130px;
|
||||
color:#f60011;
|
||||
}
|
||||
}
|
||||
.labelBox{
|
||||
width: 125px;
|
||||
.icon-a-bitian2x{color: #fe1010;}
|
||||
}
|
||||
.inputBox{
|
||||
width: 80%;
|
||||
}
|
||||
}
|
|
@ -1,9 +1,8 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Banner , FlexAJ } from '../../Component/layout';
|
||||
import { Banner , AlignCenter } from '../../Component/layout';
|
||||
import DeleteBox from '../../Component/DeleteModal/Index';
|
||||
import './Index.scss';
|
||||
import { Button , List, Pagination } from 'antd';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Button , List, Pagination, Modal, Tooltip, Popover } from 'antd';
|
||||
import axios from 'axios';
|
||||
|
||||
const limit = 15;
|
||||
|
@ -13,7 +12,10 @@ function Index(props) {
|
|||
const [ total , setTotal ] = useState(1);
|
||||
const [ deleteId , setDeleteId ] = useState(undefined);
|
||||
const [ visible , setVisible ] = useState(false);
|
||||
const [ url , setUrl ] = useState(undefined);
|
||||
const [ editVisible , setEditVisible ] = useState(false);
|
||||
const [ editId , setEditId ] = useState(undefined);
|
||||
const [ deleteWebHookModTitle, setDeleteWebHookModTitle] = useState(undefined);
|
||||
const [ deleteWebHookModSubTitle, setDeleteWebHookModSubTitle] = useState(undefined);
|
||||
|
||||
const { owner , projectsId } = props.match.params;
|
||||
|
||||
|
@ -29,15 +31,21 @@ function Index(props) {
|
|||
params:{page,limit}
|
||||
}).then(result=>{
|
||||
if(result && result.data){
|
||||
const reg1 = new RegExp("https://(.*?)jianmuhub.com(.*?)");
|
||||
const reg2 = new RegExp("https://jianmu.gitlink.org.cn(.*?)");
|
||||
result.data.webhooks.map(item=>{
|
||||
item.isJianMu = reg1.test(item.url) || reg2.test(item.url);
|
||||
})
|
||||
setData(result.data.webhooks);
|
||||
setTotal(result.data.total_count);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
||||
function deleteFunc(id,url) {
|
||||
setDeleteId(id);
|
||||
setUrl(url);
|
||||
function deleteFunc(webhook) {
|
||||
setDeleteWebHookModTitle(webhook.isJianMu ? '请谨慎删除此Webhook' : '删除Webhook');
|
||||
setDeleteWebHookModSubTitle(webhook.isJianMu ? '该Webhook由流水线创建, 删除此Webhook后, 将导致本仓库相关流水线失效。确定要删除此Webhook?' : `删除后未来事件将不会推送至此Webhook地址: ${webhook.url}`);
|
||||
setDeleteId(webhook.id);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
|
@ -65,16 +73,37 @@ function Index(props) {
|
|||
props.history.push(`/${owner}/${projectsId}/settings/webhooks/new`)
|
||||
}
|
||||
|
||||
function gotoEditWebhook(webhook){
|
||||
if(webhook.isJianMu){
|
||||
setEditId(webhook.id);
|
||||
setEditVisible(true);
|
||||
}else{
|
||||
props.history.push(`/${owner}/${projectsId}/settings/webhooks/${webhook.id}`);
|
||||
}
|
||||
}
|
||||
|
||||
return(
|
||||
<div>
|
||||
<DeleteBox
|
||||
visible={visible}
|
||||
<DeleteBox
|
||||
visible={visible}
|
||||
onCancel={()=>setVisible(false)}
|
||||
onSuccess={onSuccess}
|
||||
title="删除Webhook"
|
||||
title={deleteWebHookModTitle}
|
||||
content="您确定要删除此Webhook吗?"
|
||||
subTitle={`删除后未来事件将不会推送至此Webhook地址:${url}`}
|
||||
subTitle={deleteWebHookModSubTitle}
|
||||
/>
|
||||
<Modal
|
||||
visible={editVisible}
|
||||
onCancel={()=>{setEditVisible(false)}}
|
||||
title="请谨慎编辑此Webhook"
|
||||
width={"520px"}
|
||||
wrapClassName={"deleteBox"}
|
||||
centered={true}
|
||||
onOk={()=>{props.history.push(`/${owner}/${projectsId}/settings/webhooks/${editId}`)}}
|
||||
>
|
||||
<AlignCenter className="editWebhookModalTitle font-20 mb10"><i className="iconfont icon-shanchu_tc_icon mr10 font-36" style={{color: '#ca0002'}}></i>您确定要编辑此Webhook吗?</AlignCenter>
|
||||
<p className="task-hide-2" style={{WebkitLineClamp:5}}>该Webhook由流水线创建, 编辑此Webhook后, 将大概率导致本仓库相关流水线失效。确定要修改此Webhook?</p>
|
||||
</Modal>
|
||||
<Banner>
|
||||
<span>Webhooks(网络钩子)</span>
|
||||
<Button type="primary" size="large" onClick={addFunc}>添加Webhook</Button>
|
||||
|
@ -87,12 +116,16 @@ function Index(props) {
|
|||
{data.map((i,k)=>{
|
||||
return(
|
||||
<List.Item key={k}>
|
||||
<i className="iconfont icon-a-xuanzhongwebhookicon color-grey-d mr12 font-17"></i>
|
||||
<Link to={`/${owner}/${projectsId}/settings/webhooks/${i.id}`} className="webName">{i.url}</Link>
|
||||
<span>
|
||||
<Button ghost type={"primary"} onClick={()=>{props.history.push(`/${owner}/${projectsId}/settings/webhooks/${i.id}`)}}>编辑</Button>
|
||||
<Button ghost className="ml20" type="danger" onClick={()=>{deleteFunc(i.id,i.url)}}>删除</Button>
|
||||
</span>
|
||||
<i className={`iconfont mr12 font-17 ${i.isJianMu ? 'icon-gongzuoliuicon color-grey-6' : 'icon-a-xuanzhongwebhookicon color-grey-d'}`}></i>
|
||||
<span className="webName">{i.isJianMu ? <Tooltip title="该Webhook由流水线创建,请勿编辑或删除以防流水线失效"><span className="webName spanBox">{i.url}</span></Tooltip> : i.url}</span>
|
||||
{!i.isJianMu && <span>
|
||||
<Button ghost type={"primary"} onClick={()=>{gotoEditWebhook(i)}}>编辑</Button>
|
||||
<Button ghost className="ml20" type="danger" onClick={()=>{deleteFunc(i)}}>删除</Button>
|
||||
</span>}
|
||||
{i.isJianMu && <span>
|
||||
<Popover content={"该Webhook由流水线创建, 编辑此Webhook后, 将大概率导致本仓库相关流水线失效。请在流水线中对该Webhook配置进行更改"} title="无法编辑此Webhook" overlayClassName="disabledButPopover"><Button type={"primary"} onClick={()=>{gotoEditWebhook(i)}} disabled>编辑</Button></Popover>
|
||||
<Popover content={"该Webhook由流水线创建, 删除此Webhook后, 将导致本仓库相关流水线失效。请在流水线中删除该Webhook"} title="无法删除此Webhook" overlayClassName="disabledButPopover"><Button className="ml20" type="danger" onClick={()=>{deleteFunc(i)}} disabled>删除</Button></Popover>
|
||||
</span>}
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
|
|
|
@ -15,6 +15,12 @@
|
|||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
cursor: default;
|
||||
&.spanBox{
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,4 +174,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.editWebhookModalTitle{
|
||||
justify-content: center;
|
||||
}
|
||||
.disabledButPopover{
|
||||
width: 300px;
|
||||
}
|
|
@ -71,6 +71,7 @@ function Index({onCancel,avatarImg,login}){
|
|||
width="638px"
|
||||
footer={null}
|
||||
centered
|
||||
maskClosable={false}
|
||||
title="修改头像"
|
||||
onCancel={()=>onCancel(false)}
|
||||
className="avatarBox"
|
||||
|
|
|
@ -196,15 +196,15 @@ class InfosUser extends Component {
|
|||
>
|
||||
<a className="ant-dropdown-link">
|
||||
<span className="color-blue font-16">
|
||||
<img src={img_new} alt="" width="13px" /> 新建
|
||||
<i className="iconfont icon-xinjian1 font-14"></i> 新建
|
||||
</span>
|
||||
</a>
|
||||
</Popover>
|
||||
)}
|
||||
<Popover content={this.menu()} trigger={["click"]} placement="bottom">
|
||||
<a className="ant-dropdown-link">
|
||||
<span className="color-blue font-16">
|
||||
排序 <img src={img_array} alt="" width="10px" />
|
||||
<span className="color-blue font-16" style={{display: 'inline-flex'}}>
|
||||
<span>排序</span> <i className="iconfont icon-sanjiaoxing-down"></i>
|
||||
</span>
|
||||
</a>
|
||||
</Popover>
|
||||
|
|