forked from Gitlink/forgeplus-react
Merge pull request '合并至生产分支' (#436) from gitlink_server into pre_gitlink_server
This commit is contained in:
commit
2915756e66
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
// 使用 IntelliSense 了解相关属性。
|
||||
// 悬停以查看现有属性的描述。
|
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "pwa-chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost:8080",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -150,7 +155,7 @@ module.exports = {
|
|||
{
|
||||
libraryName: "antd",
|
||||
libraryDirectory: "es",
|
||||
style: "css",
|
||||
style: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
|
|
@ -206,8 +211,34 @@ module.exports = {
|
|||
{
|
||||
loader: require.resolve("sass-loader"),
|
||||
},
|
||||
{
|
||||
loader: 'sass-resources-loader',
|
||||
options: {
|
||||
resources: ['src/global.scss']
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
use: [{
|
||||
loader: 'style-loader',
|
||||
}, {
|
||||
loader: 'css-loader', // translates CSS into CommonJS
|
||||
}, {
|
||||
loader: 'less-loader', // compiles Less to CSS
|
||||
options: {
|
||||
modifyVars: {
|
||||
'primary-color': '#466aff',
|
||||
'primary-color-hover': '#6684FE',
|
||||
'primary-color-active': '#1A47FF',
|
||||
'link-color': '#466aff',
|
||||
},
|
||||
javascriptEnabled: true,
|
||||
},
|
||||
}]
|
||||
},
|
||||
|
||||
// "file" loader makes sure those assets get served by WebpackDevServer.
|
||||
// When you `import` an asset, you get its (virtual) filename.
|
||||
// In production, they would get copied to the `build` folder.
|
||||
|
|
@ -266,7 +297,7 @@ module.exports = {
|
|||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
||||
new MonacoWebpackPlugin({
|
||||
features: ["coreCommands", "find"],
|
||||
languages: ['plaintext','apex', 'azcli', 'bat', 'clojure', 'coffee', 'cpp', 'csharp', 'csp', 'css', 'dockerfile', 'fsharp', 'go', 'handlebars', 'html', 'ini', 'java', 'javascript', 'json', 'less', 'lua', 'markdown', 'msdax', 'mysql', 'objective', 'perl', 'pgsql', 'php', 'postiats', 'powerquery', 'powershell', 'pug', 'python', 'r', 'razor', 'redis', 'redshift', 'ruby', 'rust', 'sb', 'scheme', 'scss', 'shell', 'solidity', 'sql', 'st', 'swift', 'typescript', 'vb', 'xml', 'yaml']
|
||||
languages: ['plaintext', 'apex', 'azcli', 'bat', 'clojure', 'coffee', 'cpp', 'csharp', 'csp', 'css', 'dockerfile', 'fsharp', 'go', 'handlebars', 'html', 'ini', 'java', 'javascript', 'json', 'less', 'lua', 'markdown', 'msdax', 'mysql', 'objective', 'perl', 'pgsql', 'php', 'postiats', 'powerquery', 'powershell', 'pug', 'python', 'r', 'razor', 'redis', 'redshift', 'ruby', 'rust', 'sb', 'scheme', 'scss', 'shell', 'solidity', 'sql', 'st', 'swift', 'typescript', 'vb', 'xml', 'yaml']
|
||||
}),
|
||||
],
|
||||
// Some libraries import Node modules but don't use them in the browser.
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -147,7 +152,7 @@ module.exports = {
|
|||
{
|
||||
libraryName: "antd",
|
||||
libraryDirectory: "es",
|
||||
style: "css",
|
||||
style: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
|
|
@ -208,8 +213,31 @@ module.exports = {
|
|||
{
|
||||
loader: require.resolve("sass-loader"),
|
||||
},
|
||||
{
|
||||
loader: 'sass-resources-loader',
|
||||
options: {
|
||||
resources: ['src/global.scss']
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
use: [{
|
||||
loader: 'style-loader',
|
||||
}, {
|
||||
loader: 'css-loader', // translates CSS into CommonJS
|
||||
}, {
|
||||
loader: 'less-loader', // compiles Less to CSS
|
||||
options: {
|
||||
modifyVars: {
|
||||
'primary-color': '#466aff',
|
||||
'link-color': '#466aff',
|
||||
},
|
||||
javascriptEnabled: true,
|
||||
},
|
||||
}]
|
||||
},
|
||||
// "file" loader makes sure assets end up in the `build` folder.
|
||||
// When you `import` an asset, you get its filename.
|
||||
// This loader doesn't use a "test" so it will catch all modules
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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",
|
||||
|
|
@ -51,6 +52,8 @@
|
|||
"js-base64": "^2.5.2",
|
||||
"js2wordcloud": "^1.1.12",
|
||||
"katex": "^0.11.1",
|
||||
"less": "^3.13.1",
|
||||
"less-loader": "^4.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"loglevel": "^1.6.8",
|
||||
"marked": "^1.0.0",
|
||||
|
|
@ -108,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",
|
||||
|
|
@ -205,12 +209,13 @@
|
|||
"concat": "^1.0.3",
|
||||
"happypack": "^5.0.1",
|
||||
"mockjs": "^1.1.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||
"purgecss": "^2.1.2",
|
||||
"react-json-view": "^1.21.3",
|
||||
"reqwest": "^2.0.5",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"sass-resources-loader": "^2.2.5",
|
||||
"terser-webpack-plugin": "^2.3.5",
|
||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
||||
"webpack": "^4.42.1",
|
||||
|
|
|
|||
|
|
@ -1365,12 +1365,12 @@ table {
|
|||
border: 0;
|
||||
}
|
||||
|
||||
a:link,
|
||||
a:visited {
|
||||
a:link,a:visited{
|
||||
text-decoration: none;
|
||||
color: #05101a;
|
||||
}
|
||||
|
||||
|
||||
ol,
|
||||
ul,
|
||||
li {
|
||||
|
|
@ -2466,7 +2466,7 @@ a.hoverLine:hover{
|
|||
}
|
||||
|
||||
a:hover{
|
||||
color: #466AFF !important;
|
||||
color: #6684FE;
|
||||
}
|
||||
|
||||
.color-grey-98 {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2340181 */
|
||||
src: url('iconfont.woff2?t=1652927945088') format('woff2'),
|
||||
url('iconfont.woff?t=1652927945088') format('woff'),
|
||||
url('iconfont.ttf?t=1652927945088') format('truetype');
|
||||
src: url('iconfont.woff2?t=1653550272457') format('woff2'),
|
||||
url('iconfont.woff?t=1653550272457') format('woff'),
|
||||
url('iconfont.ttf?t=1653550272457') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
|
|
@ -13,6 +13,10 @@
|
|||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-tuichuicon:before {
|
||||
content: "\e936";
|
||||
}
|
||||
|
||||
.icon-bangzhuzhongxinicon1:before {
|
||||
content: "\e935";
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -5,6 +5,13 @@
|
|||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "29934961",
|
||||
"name": "退出icon",
|
||||
"font_class": "tuichuicon",
|
||||
"unicode": "e936",
|
||||
"unicode_decimal": 59702
|
||||
},
|
||||
{
|
||||
"icon_id": "29811507",
|
||||
"name": "帮助中心icon",
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -60,8 +60,13 @@ body {
|
|||
.ant-progress-textno {
|
||||
color: #f5222d;
|
||||
}
|
||||
.CodeMirror pre.CodeMirror-line{
|
||||
font-size: 16px!important;
|
||||
.CodeMirror .CodeMirror-lines pre.CodeMirror-line{
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
font-family:"PingFang SC", "Segoe UI", Helvetica, Arial, "Apple Color Emoji", SimHei, SimSun, sans-serif, "Microsoft YaHei";
|
||||
}
|
||||
.react-codemirror2 .CodeMirror .CodeMirror-lines pre.CodeMirror-line{
|
||||
font-size: 12px;
|
||||
}
|
||||
/* md多空格 */
|
||||
.markdown-body p {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import moment from 'moment'
|
|||
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
|
||||
import SiderBar from './forge/Component/SiderBar';
|
||||
import SiderBarHelp from './glcc/siderBarHelp';
|
||||
// import GlccModal from './modules/glccModal';
|
||||
|
||||
import { SnackbarHOC } from 'educoder';
|
||||
import { initAxiosInterceptors } from './AppConfig'
|
||||
|
|
@ -292,6 +293,7 @@ class App extends Component {
|
|||
<ConfigProvider locale={zhCN}>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
|
||||
{/* <GlccModal /> */}
|
||||
{!pathName || (pathName && pathName.indexOf("glcc") === -1) ? <SiderBar /> : <SiderBarHelp/>}
|
||||
{/* <Router> */}
|
||||
<Switch>
|
||||
|
|
|
|||
|
|
@ -89,8 +89,13 @@ export function initAxiosInterceptors(props) {
|
|||
|
||||
if (response.data.status === 404) {
|
||||
let responseURL = response.request ? response.request.responseURL:'';
|
||||
// 组织和个人的拥有情况,404不跳转
|
||||
if (responseURL.indexOf('/api/users/') === -1 && responseURL.indexOf('/api/organizations/') === -1 ) {
|
||||
locationurl('/nopage');
|
||||
// 邀请页面不进行404跳转
|
||||
if( window.location.pathname.includes('/invite') && (responseURL.includes('/simple.json')||responseURL.includes('/detail.json')||responseURL.includes('/menu_list.json'))){
|
||||
}else{
|
||||
locationurl('/nopage');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,13 +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));
|
||||
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'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,117 @@
|
|||
/* eslint-disable react/jsx-no-duplicate-props */
|
||||
import React, { useState } from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { Modal, Button } from 'antd';
|
||||
import './index.scss';
|
||||
|
||||
InitModal.defaultProps = {
|
||||
okText: '确认', //确定按钮的文字
|
||||
cancelText: '取消', //取消按钮的文字
|
||||
className: '', //
|
||||
inputId: 'copyText', //要复制的文本的ID
|
||||
};
|
||||
|
||||
// 使用函数调用删除组件
|
||||
export default function DelModal(props) {
|
||||
renderModal({ ...props, type: 'delete' })
|
||||
}
|
||||
|
||||
// 使用函数调用选择模态框组件
|
||||
export function Confirm(props) {
|
||||
renderModal({ ...props, type: 'confirm' })
|
||||
}
|
||||
|
||||
function renderModal(props) {
|
||||
const { type, afterClose } = props;
|
||||
const div = document.createElement('div');
|
||||
document.body.appendChild(div);
|
||||
|
||||
function destroy() {
|
||||
afterClose && afterClose();
|
||||
const unmountResult = ReactDOM.unmountComponentAtNode(div);
|
||||
if (unmountResult && div.parentNode) {
|
||||
div.parentNode.removeChild(div);
|
||||
}
|
||||
}
|
||||
|
||||
function modalType(type) {
|
||||
if (type === 'delete') {
|
||||
return <InitModal
|
||||
title="删除"
|
||||
contentTitle="确定要删除吗?"
|
||||
okText="确认删除"
|
||||
{...props}
|
||||
|
||||
afterClose={destroy}
|
||||
contentTitle={<React.Fragment>
|
||||
<i className="red-circle iconfont icon-shanchu_tc_icon mr3"></i>
|
||||
{props.contentTitle}
|
||||
</React.Fragment>}
|
||||
/>
|
||||
} else if (type === 'confirm') {
|
||||
return <InitModal title="选择" afterClose={destroy} {...props} />
|
||||
} else {
|
||||
return <InitModal title="选择" afterClose={destroy} {...props} />
|
||||
}
|
||||
}
|
||||
|
||||
function render() {
|
||||
setTimeout(() => {
|
||||
ReactDOM.render(
|
||||
modalType(type),
|
||||
div,
|
||||
);
|
||||
});
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
// 选择模态框组件
|
||||
function InitModal({
|
||||
onCancel,
|
||||
onOk,
|
||||
title,
|
||||
contentTitle,
|
||||
content,
|
||||
okText,
|
||||
cancelText,
|
||||
afterClose,
|
||||
className,
|
||||
}) {
|
||||
|
||||
const [visible, setVisible] = useState(true);
|
||||
|
||||
function onCancelModal() {
|
||||
setVisible(false);
|
||||
onCancel && onCancel()
|
||||
}
|
||||
|
||||
function onSuccess() {
|
||||
setVisible(false);
|
||||
onOk && onOk();
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
onCancel={onCancelModal}
|
||||
afterClose={afterClose}
|
||||
title={title}
|
||||
className={`myself-modal ${className}`}
|
||||
centered
|
||||
footer={[
|
||||
<Button type="default" key="back" onClick={onCancelModal}>
|
||||
{cancelText}
|
||||
</Button>,
|
||||
<Button className="foot-submit" key="submit" onClick={onSuccess}>
|
||||
{okText}
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<div>
|
||||
{contentTitle && <p className="content-title">{contentTitle}</p>}
|
||||
<p className="content-descibe">{content}</p>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
.myself-modal {
|
||||
.ant-modal-header {
|
||||
padding: 9px 24px;
|
||||
background: #f8f8f8;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.ant-modal-title {
|
||||
text-align: left;
|
||||
}
|
||||
.ant-modal-close {
|
||||
top: 0px !important;
|
||||
}
|
||||
.ant-modal-close-x {
|
||||
font-size: 24px;
|
||||
}
|
||||
.ant-modal-body {
|
||||
text-align: center;
|
||||
}
|
||||
.content-title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 2rem 0 1rem !important;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
letter-spacing: 0;
|
||||
line-height: 29px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.red-circle {
|
||||
align-self: flex-start;
|
||||
color: #ca0002;
|
||||
font-size: 1.5rem !important;
|
||||
}
|
||||
.content-descibe {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
line-height: 33px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.ant-modal-footer {
|
||||
padding: 2rem 0;
|
||||
text-align: center;
|
||||
border: 0;
|
||||
.ant-btn {
|
||||
width: 6rem;
|
||||
}
|
||||
}
|
||||
.foot-submit {
|
||||
margin-left: 3rem;
|
||||
color: #df0002;
|
||||
&:hover {
|
||||
border-color: #df0002;
|
||||
}
|
||||
}
|
||||
.ant-btn-default:hover,
|
||||
.ant-btn-default:active,
|
||||
.ant-btn-default:focus {
|
||||
background: #f3f4f6;
|
||||
color: #333;
|
||||
border-color: #d0d0d0;
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ function AddMember({getID,login,showNotification}){
|
|||
<AutoComplete
|
||||
dataSource={source}
|
||||
value={searchKey}
|
||||
style={{ width: 300 }}
|
||||
style={{ width: 250 }}
|
||||
onChange={changeInputUser}
|
||||
onSelect={selectInputUser}
|
||||
placeholder="搜索需要添加的用户..."
|
||||
|
|
@ -92,7 +92,8 @@ function AddMember({getID,login,showNotification}){
|
|||
onClick={addCollaborator}
|
||||
className="ml15"
|
||||
>
|
||||
<Icon type="plus" size="16"></Icon>
|
||||
{/* <Icon type="plus" size="16"></Icon> */}
|
||||
<i className="iconfont icon-tianjiafangda mr3"></i>
|
||||
添加成员
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -276,36 +276,36 @@ li.ant-menu-item{
|
|||
.-task-sidebar {
|
||||
position: fixed;
|
||||
width: 40px;
|
||||
right: 10px;
|
||||
right: 30px;
|
||||
bottom: 80px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1920px){
|
||||
.-task-sidebar{
|
||||
right:220px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 1750px){
|
||||
.-task-sidebar{
|
||||
right:160px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 1650px){
|
||||
.-task-sidebar{
|
||||
right:115px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 1550px){
|
||||
.-task-sidebar{
|
||||
right:90px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 1450px){
|
||||
.-task-sidebar{
|
||||
right:45px;
|
||||
}
|
||||
}
|
||||
// @media screen and (max-width: 1920px){
|
||||
// .-task-sidebar{
|
||||
// right:220px;
|
||||
// }
|
||||
// }
|
||||
// @media screen and (max-width: 1750px){
|
||||
// .-task-sidebar{
|
||||
// right:160px;
|
||||
// }
|
||||
// }
|
||||
// @media screen and (max-width: 1650px){
|
||||
// .-task-sidebar{
|
||||
// right:115px;
|
||||
// }
|
||||
// }
|
||||
// @media screen and (max-width: 1550px){
|
||||
// .-task-sidebar{
|
||||
// right:90px;
|
||||
// }
|
||||
// }
|
||||
// @media screen and (max-width: 1450px){
|
||||
// .-task-sidebar{
|
||||
// right:45px;
|
||||
// }
|
||||
// }
|
||||
@media screen and (max-width: 1200px){
|
||||
.-task-sidebar{
|
||||
right:0px;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ function LanguagePower({owner,projectsId}){
|
|||
{
|
||||
array && array.map((item,key)=>{
|
||||
return(
|
||||
<span style={{width:item.percent,backgroundColor:item.color}}></span>
|
||||
<span key={item.id||key} style={{width:item.percent,backgroundColor:item.color}}></span>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -66,7 +66,7 @@ function LanguagePower({owner,projectsId}){
|
|||
{
|
||||
array.map((item,key)=>{
|
||||
return(
|
||||
<span><i className="zero" style={{backgroundColor:`${item.color}`}}></i><span>{item.name}</span><span>{item.percent}</span></span>
|
||||
<span key={item.id||key}><i className="zero" style={{backgroundColor:`${item.color}`}}></i><span>{item.name}</span><span>{item.percent}</span></span>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,8 +73,8 @@ export const Blueline = styled.a`{
|
|||
height:30px;
|
||||
line-height:28px;
|
||||
border-radius:2px;
|
||||
border:1px solid rgba(80,145,255,1);
|
||||
color:rgba(80,145,255,1);
|
||||
border:1px solid #466AFF;
|
||||
color:#466AFF;
|
||||
padding:0px 12px;
|
||||
display:inline-block;
|
||||
}`
|
||||
|
|
@ -117,7 +117,8 @@ export const Blueback = styled.a`{
|
|||
height:30px;
|
||||
line-height:30px;
|
||||
border-radius:2px;
|
||||
background-color:rgba(80,145,255,1);
|
||||
// background-color:rgba(80,145,255,1);
|
||||
background-color:#466AFF;
|
||||
color:#fff!important;
|
||||
padding:0px 12px;
|
||||
display:inline-block;
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ function About(props, ref) {
|
|||
params:{password:authorityVal}
|
||||
}).then(result=>{
|
||||
setIsSpining(false);
|
||||
if(result){
|
||||
if(result && result.data.status === 0){
|
||||
setStep(result.data.step);
|
||||
}
|
||||
}).catch(error=>{setIsSpining(false)});
|
||||
|
|
@ -149,7 +149,10 @@ function About(props, ref) {
|
|||
axios.post(url).then(result=>{
|
||||
setIsSpining(false);
|
||||
if(result && result.data.status === 0){
|
||||
props.history.push(`/${owner}/${projectsId}/devops`);
|
||||
props.history.push({
|
||||
pathname: `/${owner}/${projectsId}/devops`,
|
||||
state:{open_devops:true}
|
||||
});
|
||||
// 需要将顶部的open_devops修改
|
||||
let { changeOpenDevops } = props;
|
||||
changeOpenDevops && changeOpenDevops(true);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import React , { useEffect } from 'react';
|
||||
import React, {useEffect, useState} 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';
|
||||
import axios from 'axios';
|
||||
|
||||
const About = Loadable({
|
||||
loader: () => import('./About'),
|
||||
loader: () => import('./subIndex'),
|
||||
loading: Loading,
|
||||
})
|
||||
const New = Loadable({
|
||||
|
|
@ -32,11 +33,61 @@ const Params = Loadable({
|
|||
})
|
||||
|
||||
export default ((props)=>{
|
||||
const {isManager, project} = props;
|
||||
const { projectsId, owner } = props.match.params;
|
||||
const [jianmu_devops, setJianmu_devops] = useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
// 请求simple接口获取jianmu_devops
|
||||
const url = `/${owner}/${projectsId}/simple.json`;
|
||||
axios.get(url).then((result) => {
|
||||
if (result && result.data) {
|
||||
result.data.jianmu_devops && setJianmu_devops(encodeURIComponent(result.data.jianmu_devops));
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
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 +103,6 @@ export default ((props)=>{
|
|||
(p) => (<New {...props} {...p}/>)
|
||||
}
|
||||
></Route>
|
||||
|
||||
<Route path="/:owner/:projectsId/devops/list/:branch"
|
||||
render={
|
||||
(p) => (<Stucture {...props} {...p}/>)
|
||||
|
|
@ -63,13 +113,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( 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>
|
||||
)
|
||||
})
|
||||
|
|
@ -104,7 +104,7 @@ function Params(props){
|
|||
<Banner>
|
||||
<FlexAJ>
|
||||
<span className="font-18">引擎 - 参数管理</span>
|
||||
<Link to={`/${owner}/${projectsId}/devops`} className="font-14 color-grey-9 ml20">返回</Link>
|
||||
<Link to={{pathname:`/${owner}/${projectsId}/devops`,state:{open_devops:true}}} className="font-14 color-grey-9 ml20">返回</Link>
|
||||
</FlexAJ>
|
||||
</Banner>
|
||||
<Div className="disposeList">
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ function Structure(props,ref){
|
|||
<Banner>
|
||||
<FlexAJ>
|
||||
<span>构建列表</span>
|
||||
<Link to={`/${owner}/${projectsId}/devops`} className="font-15 color-grey-9">返回</Link>
|
||||
<Link to={{pathname:`/${owner}/${projectsId}/devops`,state:{open_devops:true}}} className="font-15 color-grey-9">返回</Link>
|
||||
</FlexAJ>
|
||||
</Banner>
|
||||
<Div>
|
||||
|
|
|
|||
|
|
@ -275,7 +275,10 @@ function disposePipeline(props){
|
|||
...params
|
||||
}).then(result=>{
|
||||
if(result){
|
||||
props.history.push(`/${owner}/${projectsId}/devops`);
|
||||
props.history.push({
|
||||
pathname:`/${owner}/${projectsId}/devops`,
|
||||
state:{open_devops:true}
|
||||
});
|
||||
}
|
||||
setLoading(false);
|
||||
}).catch(error=>{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
import About from './About';
|
||||
import Dispose from './Dispose';
|
||||
|
||||
function SubIndex(props) {
|
||||
return(
|
||||
props && props.open_devops ?
|
||||
<Dispose {...props} />
|
||||
:
|
||||
<About {...props} />
|
||||
)
|
||||
}
|
||||
export default SubIndex;
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import axios from 'axios';
|
||||
// 获取分支列表
|
||||
export const getBranch = async (id,owner)=>{
|
||||
return (await axios.get(`/${owner}/${id}/branches.json`)).data;
|
||||
let res = await axios.get(`/${owner}/${id}/branches.json`);
|
||||
return res&&res.data;
|
||||
}
|
||||
// 获取标签列表
|
||||
export const getTag = async (id,owner)=>{
|
||||
|
|
|
|||
|
|
@ -204,8 +204,7 @@ class NewHeader extends Component {
|
|||
}else{
|
||||
str = match.path;
|
||||
}
|
||||
|
||||
if (url && str === url) {
|
||||
if (url && (str === url || (str === url+'/'))) {
|
||||
return true
|
||||
}else {
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -190,11 +190,11 @@ function NoticeContent({ visible, showNotification, resetUserInfo, current_user:
|
|||
className='hoverNotice-body' // 外部添加className加以区分
|
||||
onPullRefresh={() => { setNoticePage(noticePage + 1); }} //触发加载ajax的function
|
||||
// type={2} // 传送加载组件的状态
|
||||
count={noticeUnreadList.length} // 数据当前的总数量
|
||||
count={noticeUnreadList&¬iceUnreadList.length} // 数据当前的总数量
|
||||
pageSize={10} //
|
||||
>
|
||||
{
|
||||
noticeUnreadList.map(item => {
|
||||
Array.isArray(noticeUnreadList)&& noticeUnreadList.map(item => {
|
||||
return (
|
||||
<div key={item.id + Math.random()} className="noticeCont-back" onClick={() => { readItem(item) }}>
|
||||
<div className={`noticeCont ${item.notification_url?'pointer':''}`}>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.currentMenu{
|
||||
.ant-dropdown-menu.currentMenu{
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
padding:0px;
|
||||
|
|
@ -62,7 +62,8 @@
|
|||
color: #666;
|
||||
&:hover{
|
||||
color: #fff;
|
||||
background: #4CACFF;
|
||||
// background: #4CACFF;
|
||||
background: #829BFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -0,0 +1,92 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Modal, Button, } from 'antd';
|
||||
import { Base64 } from 'js-base64';
|
||||
import './index.scss';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { getImageUrl } from 'educoder'
|
||||
import axios from 'axios';
|
||||
|
||||
const identify = {
|
||||
manager: "管理员",
|
||||
developer: "开发者",
|
||||
reporter: "报告者",
|
||||
owner: "所有者",
|
||||
}
|
||||
function Invite({ history, current_user, match, projectDetail, showNotification }) {
|
||||
|
||||
if (!current_user.login) {
|
||||
let { pathname, search } = window.location;
|
||||
window.location.href = `/login?go_page=${pathname}${search}`;
|
||||
}
|
||||
let permission = projectDetail && projectDetail.permission;
|
||||
const { projectsId, owner } = match.params;
|
||||
let inviteString = window.location.search && window.location.search.split('?invite=')[1];
|
||||
let data = inviteString && JSON.parse(Base64.decode(inviteString));
|
||||
const [detail, setDetail] = useState({});
|
||||
const [visible, setVisible] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (permission && detail.role && detail.role == permission.toLocaleLowerCase() || permission == 'Owner') {
|
||||
showNotification(`您已经是${identify[detail.role]}了`)
|
||||
setTimeout(() => {
|
||||
history.push(`/${owner}/${projectsId}`);
|
||||
}, 2000)
|
||||
} else {
|
||||
setVisible(true)
|
||||
}
|
||||
}, [permission, detail.role]);
|
||||
|
||||
useEffect(() => {
|
||||
const url = `/${owner}/${projectsId}/project_invite_links/show_link.json?invite_sign=${data.sign}`;
|
||||
axios.get(url).then(res => {
|
||||
if (res && res.data) {
|
||||
setDetail(res.data);
|
||||
} else {
|
||||
showNotification('查询邀请链接失败');
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
function accept() {
|
||||
const url = `/${owner}/${projectsId}/project_invite_links/redirect_link.json?invite_sign=${data.sign}`;
|
||||
axios.post(url).then(res => {
|
||||
if (res && res.data.message == 'success') {
|
||||
if (detail.is_apply) {
|
||||
setVisible(false);
|
||||
Modal.success({ content: '提交申请成功,请等待该仓库管理员审核' });
|
||||
} else {
|
||||
history.push(`/${owner}/${projectsId}`);
|
||||
}
|
||||
}
|
||||
}).catch(error => { })
|
||||
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
{data && <Modal
|
||||
visible={visible}
|
||||
className="invite_development"
|
||||
title={<div className="ownerImage"><img src={detail.project && getImageUrl(detail.project.owner.image_url)} /></div>}
|
||||
width="548px"
|
||||
closable={true}
|
||||
onCancel={() => { setVisible(false); history.push(`/${current_user.login}`) }}
|
||||
centered
|
||||
okText={'接受'}
|
||||
cancelText={'拒绝'}
|
||||
onOk={accept}
|
||||
maskClosable={false}
|
||||
>
|
||||
<Link className="invite_project link" target="_blank" to={`/${data.ownerLogin}/${data.projectId}`}>{detail.project && detail.project.owner.name}/{detail.project && detail.project.name}</Link>
|
||||
<div className="invite_content">
|
||||
<Link className="link" to={`/${detail.user && detail.user.login}`}>{detail.user && detail.user.name}</Link> 邀请您以{identify[detail.role]}的身份加入此代码库
|
||||
是否接受邀请?
|
||||
</div>
|
||||
</Modal>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export default Invite;
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
.invite_development {
|
||||
font-family: PingFang SC;
|
||||
height: 366px;
|
||||
background-image: linear-gradient(
|
||||
359.37deg,
|
||||
#ebf3ff 0%,
|
||||
#eff5ff 55.01%,
|
||||
#cfdeff 100%
|
||||
);
|
||||
border: 1.5px solid #ffffff;
|
||||
border-radius: 4px;
|
||||
|
||||
.ant-modal-close{
|
||||
top:0 !important;
|
||||
}
|
||||
.ant-modal-close-x{
|
||||
font-size: 30px;
|
||||
color: #666;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
transform: scaleX(1.05);
|
||||
}
|
||||
.ant-modal-content {
|
||||
background-color: inherit;
|
||||
}
|
||||
.ant-modal-header {
|
||||
background: inherit;
|
||||
border: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.ownerImage {
|
||||
position: relative;
|
||||
top:-66px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: #e9f1ff;
|
||||
border: 1px solid #ffffff;
|
||||
border-radius: 50%;
|
||||
margin:0 auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
img{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.invite_project {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.invite_content {
|
||||
width: 422px;
|
||||
padding: 24px 48px;
|
||||
background-color: rgba(225, 231, 255, 0.71);
|
||||
border-radius: 4px 4px 0px 0px;
|
||||
margin: 10px auto;
|
||||
font-weight: 500;
|
||||
font-size: 17px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
color: #151d40;
|
||||
}
|
||||
.link {
|
||||
cursor: pointer;
|
||||
color: $primary-color;
|
||||
&:hover {
|
||||
color: $primary-color-hover;
|
||||
}
|
||||
}
|
||||
.ant-modal-footer {
|
||||
text-align: center;
|
||||
border: 0;
|
||||
padding-bottom: 55px;
|
||||
button {
|
||||
width: 150px;
|
||||
height: 42px;
|
||||
border-radius: 5px;
|
||||
font-size: 15px;
|
||||
&:first-child {
|
||||
background-color: rgba(196, 0, 14, 0.07);
|
||||
border: 1px solid;
|
||||
border-color: #f60011;
|
||||
color: #f60011;
|
||||
&:hover {
|
||||
opacity: 0.75;
|
||||
}
|
||||
}
|
||||
& + button {
|
||||
margin-left: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -192,7 +192,7 @@ function CoderDepot(props){
|
|||
const url = `/${owner}/${projectsId}/sub_entries.json`;
|
||||
axios.get(url, {
|
||||
params:{
|
||||
filepath:path,
|
||||
filepath:returnbar(path),
|
||||
ref:ref || branchName,
|
||||
type
|
||||
}
|
||||
|
|
@ -272,8 +272,9 @@ function CoderDepot(props){
|
|||
if(type!=="submodule"){
|
||||
let enBranch = branchName || defaultBranch;
|
||||
let checkvalue = turnbar(enBranch);
|
||||
let enPath = turnbar(path);
|
||||
setType(type);
|
||||
props.history.push(`/${owner}/${projectsId}${`/tree/${checkvalue}`}${path?`/${path}`:""}`);
|
||||
props.history.push(`/${owner}/${projectsId}${`/tree/${checkvalue}`}${enPath?`/${enPath}`:""}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -332,6 +333,8 @@ function CoderDepot(props){
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
let n = fileInfo && fileInfo.name;
|
||||
const mdFlag = n && n.substring(n.length-3,n.length) === ".md";
|
||||
|
||||
|
|
@ -442,6 +445,7 @@ function CoderDepot(props){
|
|||
issuesFlag &&
|
||||
<a onClick={createIssue}>+ 疑修</a>
|
||||
}
|
||||
|
||||
</div>
|
||||
{ fileOperate &&
|
||||
<Dropdown
|
||||
|
|
@ -492,6 +496,7 @@ function CoderDepot(props){
|
|||
dirInfo.map((item,key)=>{
|
||||
return(
|
||||
<Catalogue
|
||||
key={item.id||key}
|
||||
owner={owner}
|
||||
item={item}
|
||||
projectsId={projectsId}
|
||||
|
|
@ -521,7 +526,7 @@ function CoderDepot(props){
|
|||
(dirInfo && dirInfo.length === 0) && !fileInfo ? <Nodata _html="暂未发现文件"/> :""
|
||||
}
|
||||
{/* readme文件显示(显示文件详情时不显示readme文件) */}
|
||||
{ (readme && readme.content) ? <ReadMe ChangeFile={ChangeFile} readme={readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
|
||||
{ (readme && readme.replace_content) ? <ReadMe ChangeFile={ChangeFile} readme={readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
|
||||
</div>
|
||||
</LongWidth>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@ const typeIco = {
|
|||
}
|
||||
|
||||
function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId , platform }){
|
||||
// 只显示第一个换行符前的内容
|
||||
function getMessage(value){
|
||||
let str = value.indexOf('\n') > 0 && value.split('\n');
|
||||
return str[0];
|
||||
}
|
||||
return(
|
||||
<li>
|
||||
<span>
|
||||
|
|
@ -16,14 +21,14 @@ function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId , platform
|
|||
(!platform && item.image_type) ?
|
||||
<span><i className={`iconfont ${typeIco[`${item.type}`]} mr8`}></i>{item.name}</span>
|
||||
:
|
||||
<a onClick={()=>goToSubRoot(item.path,item.type,item.name)} className={item.type === "submodule" && "submoduleStyle"}>
|
||||
<a onClick={()=>goToSubRoot(item.path,item.type,item.name)} className={item.type === "submodule" ? "submoduleStyle":''}>
|
||||
<i className={`iconfont ${typeIco[`${item.type}`]} mr8`}></i>{item.name}
|
||||
</a>
|
||||
}
|
||||
</span>
|
||||
<span title="init project">
|
||||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.commit && item.commit.sha}`)}`} title={item.commit && item.commit.message}>
|
||||
{item.commit && item.commit.message}
|
||||
{getMessage(item.commit && item.commit.message)}
|
||||
</Link>
|
||||
</span>
|
||||
<span title={item.commit && item.commit.created_at}>{item.commit && item.commit.time_from_now}</span>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { result } from 'lodash';
|
||||
import React from 'react';
|
||||
import { returnbar } from 'educoder';
|
||||
|
||||
|
||||
function CoderDepotPath({treeValuePath , returnUlr , returnMain , getPathUrl , identifier}){
|
||||
|
|
@ -14,12 +14,12 @@ 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}>{item}</span>
|
||||
<span className="color-grey-6 subFileName" key={key}>{returnbar(item)}</span>
|
||||
:
|
||||
<a onClick={()=>returnUlr(`${getPathUrl(treeValuePath,key+1)}`)} className="color-blue subFileName">{item}</a>
|
||||
<a onClick={()=>returnUlr(`${getPathUrl(treeValuePath,key+1)}`)} className="color-blue subFileName">{returnbar(item)}</a>
|
||||
}
|
||||
</React.Fragment>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Link, Route, Switch } from 'react-router-dom';
|
|||
import { Content, AlignTop } from '../Component/layout';
|
||||
import DetailBanner from './sub/DetailBanner';
|
||||
import cookie from 'react-cookies';
|
||||
import { Base64 } from 'js-base64';
|
||||
import '../css/index.scss'
|
||||
import './list.scss';
|
||||
|
||||
|
|
@ -145,6 +146,14 @@ const WikiEdit = Loadable({
|
|||
loader: () => import('../Wiki/EditWiki'),
|
||||
loading: Loading,
|
||||
});
|
||||
const Invite = Loadable({
|
||||
loader: () => import('../Invite/Index'),
|
||||
loading: Loading,
|
||||
});
|
||||
const Review = Loadable({
|
||||
loader: () => import('../Newfile/codeReview'),
|
||||
loading: Loading,
|
||||
});
|
||||
/**
|
||||
* permission:Manager:管理员,Reporter:报告人员(只有读取权限),Developer:开发人员(除不能设置仓库信息外)
|
||||
*/
|
||||
|
|
@ -227,12 +236,12 @@ class Detail extends Component {
|
|||
})
|
||||
}
|
||||
|
||||
clearIssueCookies=(history)=>{
|
||||
clearIssueCookies = (history) => {
|
||||
const { pathname } = history;
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
const { projectsId, owner } = this.props.match.params;
|
||||
let currentIssue = pathname.indexOf(`/${owner}/${projectsId}/issues`) === -1;
|
||||
if (currentIssue) {
|
||||
cookie.save('states', undefined,{ expires: 0,path:`/` });
|
||||
cookie.save('states', undefined, { expires: 0, path: `/` });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -304,15 +313,15 @@ class Detail extends Component {
|
|||
},
|
||||
disconnected: () => {
|
||||
console.log("###### cannot connected! ######");
|
||||
},
|
||||
},
|
||||
received: data => {
|
||||
console.log(`###### ---received data--- ######`);
|
||||
console.log(data);
|
||||
if (data) {
|
||||
if(deleteFlag){
|
||||
if (deleteFlag) {
|
||||
this.props.showNotification("镜像同步成功!");
|
||||
window.location.reload();
|
||||
}else{
|
||||
} else {
|
||||
if (data.project && data.project.mirror_status === 2) {
|
||||
this.deleteProjectBack();
|
||||
}
|
||||
|
|
@ -326,20 +335,20 @@ class Detail extends Component {
|
|||
cable.subscriptions.consumer.disconnect();
|
||||
}
|
||||
},
|
||||
onerror:()=>{
|
||||
onerror: () => {
|
||||
console.log("###### cannot connected! ######");
|
||||
}
|
||||
});
|
||||
|
||||
this.timerChannel = setTimeout(this.reloadDetail,5000);
|
||||
this.timerChannel = setTimeout(this.reloadDetail, 5000);
|
||||
}
|
||||
|
||||
reloadDetail=()=>{
|
||||
if(this.state.firstSync||this.state.secondSync){
|
||||
reloadDetail = () => {
|
||||
if (this.state.firstSync || this.state.secondSync) {
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
deleteProjectBack = () => {
|
||||
const { history } = this.props;
|
||||
|
|
@ -364,22 +373,33 @@ class Detail extends Component {
|
|||
axios.get(url).then((result) => {
|
||||
if (result && result.data) {
|
||||
if (result.data.status === 404) {
|
||||
this.props.history.push('/nopage');
|
||||
if (window.location.pathname.includes('/invite')) {
|
||||
let inviteString = window.location.search && window.location.search.split('?invite=')[1];
|
||||
let data = inviteString && JSON.parse(Base64.decode(inviteString));
|
||||
const { project = {}, projectDetail = {} } = this.state
|
||||
this.setState({
|
||||
project: Object.assign(project, { author: { name: data.ownerName } }),
|
||||
projectDetail: Object.assign(projectDetail, { name: data.projectName })
|
||||
});
|
||||
} else {
|
||||
this.props.history.push('/nopage');
|
||||
}
|
||||
} else {
|
||||
this.setState({
|
||||
projectDetail: result.data,
|
||||
project_id: result.data.project_id,
|
||||
isManager: result.data.permission && (result.data.permission === "Manager" || result.data.permission === "Admin" || result.data.permission === "Owner"),
|
||||
isReporter: result.data.permission && result.data.permission === "Reporter",
|
||||
isDeveloper: result.data.permission && result.data.permission === "Developer",
|
||||
http_url: result.data.clone_url,
|
||||
praised: result.data.praised,
|
||||
watched: result.data.watched,
|
||||
watchers_count: result.data.watchers_count,
|
||||
praises_count: result.data.praises_count,
|
||||
forked_count: result.data.forked_count,
|
||||
defaultBranch: result.data.default_branch
|
||||
})
|
||||
}
|
||||
this.setState({
|
||||
projectDetail: result.data,
|
||||
project_id: result.data.project_id,
|
||||
isManager: result.data.permission && (result.data.permission === "Manager" || result.data.permission === "Admin" || result.data.permission === "Owner"),
|
||||
isReporter: result.data.permission && result.data.permission === "Reporter",
|
||||
isDeveloper: result.data.permission && result.data.permission === "Developer",
|
||||
http_url: result.data.clone_url,
|
||||
praised: result.data.praised,
|
||||
watched: result.data.watched,
|
||||
watchers_count: result.data.watchers_count,
|
||||
praises_count: result.data.praises_count,
|
||||
forked_count: result.data.forked_count,
|
||||
defaultBranch: result.data.default_branch
|
||||
})
|
||||
}
|
||||
}).catch((error) => { })
|
||||
}
|
||||
|
|
@ -464,7 +484,7 @@ class Detail extends Component {
|
|||
const url = `/${owner}/${projectsId}/forks.json`;
|
||||
axios.post(url).then(result => {
|
||||
if (result && result.data.status === 0) {
|
||||
if(result.data.message === "fork失败,你已拥有了这个项目"){
|
||||
if (result.data.message === "fork失败,你已拥有了这个项目") {
|
||||
this.props.history.push(`/${current_user && current_user.login}/${projectsId}`);
|
||||
return;
|
||||
}
|
||||
|
|
@ -490,7 +510,7 @@ class Detail extends Component {
|
|||
axios.post(url).then(result => {
|
||||
if (result && result.data && result.data.status === 0) {
|
||||
this.setState({
|
||||
secondSync:true
|
||||
secondSync: true
|
||||
})
|
||||
this.canvasChannel(true);
|
||||
} else {
|
||||
|
|
@ -527,10 +547,9 @@ class Detail extends Component {
|
|||
let pathname = checkPathname(projectsId, owner, url);
|
||||
|
||||
const { state } = this.props.history.location;
|
||||
|
||||
const common = {
|
||||
getDetail: this.getDetail,
|
||||
getBanner:this.getBanner,
|
||||
getBanner: this.getBanner,
|
||||
changeOpenDevops: this.changeOpenDevops,
|
||||
defaultBranch
|
||||
}
|
||||
|
|
@ -549,7 +568,7 @@ class Detail extends Component {
|
|||
<Link to={`/${owner}/${projectsId}`} className="projectN mt6">{projectDetail && projectDetail.name}</Link>
|
||||
</div>
|
||||
{projectDetail && projectDetail.private && <span className="privateTag mt6">私有</span>}
|
||||
{ !platform && <span className="privateTag red mt6">只读</span> }
|
||||
{!platform && <span className="privateTag red mt6">只读</span>}
|
||||
</AlignTop>
|
||||
<div className="mt8">
|
||||
{
|
||||
|
|
@ -644,6 +663,8 @@ class Detail extends Component {
|
|||
open_devops={open_devops}
|
||||
platform={platform}
|
||||
urlFlag={urlFlag}
|
||||
showNotification={this.props.showNotification}
|
||||
current_user={current_user}
|
||||
isManager={isManager}
|
||||
/>
|
||||
}
|
||||
|
|
@ -687,6 +708,12 @@ class Detail extends Component {
|
|||
() => (<WikiEdit {...this.props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
{/* wiki具体某一个地址 */}
|
||||
<Route path="/:owner/:projectsId/wiki/:wikiName"
|
||||
render={
|
||||
(props) => (<Wiki {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
{/* wiki */}
|
||||
<Route path="/:owner/:projectsId/wiki"
|
||||
render={
|
||||
|
|
@ -711,7 +738,7 @@ class Detail extends Component {
|
|||
(props) => (<Setting {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
|
||||
|
||||
{/*修改里程碑*/}
|
||||
<Route path="/:owner/:projectsId/milestones/:meilid/edit"
|
||||
render={
|
||||
|
|
@ -751,18 +778,18 @@ class Detail extends Component {
|
|||
{/* 修改详情 edit*/}
|
||||
<Route path="/:owner/:projectsId/issues/:orderId/edit"
|
||||
render={
|
||||
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} form_type={"edit"}/>)
|
||||
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} form_type={"edit"} />)
|
||||
}
|
||||
></Route>
|
||||
{/* 复制详情 copyetail*/}
|
||||
<Route path="/:owner/:projectsId/issues/:orderId/copyetail"
|
||||
render={
|
||||
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} form_type={"copy"}/>)
|
||||
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} form_type={"copy"} />)
|
||||
}
|
||||
></Route>
|
||||
|
||||
{/* 任务详情 */}
|
||||
<Route path="/:owner/:projectsId/issues/:orderId"
|
||||
|
||||
{/* 任务详情 */}
|
||||
<Route path="/:owner/:projectsId/issues/:orderId"
|
||||
render={
|
||||
(props) => (<OrderDetail {...this.props} {...this.state} {...props} {...common} />)
|
||||
}
|
||||
|
|
@ -795,6 +822,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} />)
|
||||
|
|
@ -854,6 +887,13 @@ class Detail extends Component {
|
|||
(props) => (<CoderDepot {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
{/* 邀请 */}
|
||||
<Route path="/:owner/:projectsId/invite"
|
||||
render={
|
||||
(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;
|
||||
|
|
@ -334,6 +334,14 @@
|
|||
.listtablebody{
|
||||
border-radius:0px 0px 4px 4px ;
|
||||
border: 1px solid #D0D0D0;
|
||||
li{
|
||||
a{
|
||||
color: #05101a;
|
||||
&:hover{
|
||||
color:$primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
li.listtablepath{
|
||||
a{color: #40a9ff;}
|
||||
p{
|
||||
|
|
|
|||
|
|
@ -306,6 +306,14 @@
|
|||
}
|
||||
.files-md{
|
||||
padding:20px;
|
||||
h1,h2, h3, h4, h5, h6{
|
||||
margin-bottom: .5em !important;
|
||||
}
|
||||
}
|
||||
.readBox{
|
||||
h1,h2, h3, h4, h5, h6{
|
||||
margin-bottom: .5em !important;
|
||||
}
|
||||
}
|
||||
/* 详情-代码 */
|
||||
.branch-wrapper{
|
||||
|
|
@ -512,7 +520,7 @@
|
|||
top: 0px;
|
||||
color: #999;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
line-height: 17px;
|
||||
}
|
||||
.addFile{
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@ import React, { useEffect, useState } from 'react';
|
|||
import { Skeleton , Tooltip} from 'antd';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { numFormat } from 'educoder';
|
||||
import QuitBox from './quit';
|
||||
import axios from 'axios';
|
||||
|
||||
function DetailBanner({ history,list , owner , projectsId , isManager , url , pathname , state , urlFlag , projectDetail , platform ,open_devops }){
|
||||
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(()=>{
|
||||
if(list){
|
||||
if(Array.isArray(list)){
|
||||
// 没有资源库banner但是通过连接进资源库页面时
|
||||
let a = list.filter(item=>item.menu_name === "resources");
|
||||
if((pathname && pathname==="source") && (a && a.length === 0)){
|
||||
|
|
@ -19,13 +22,25 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
|
|||
setMenuName(list);
|
||||
}
|
||||
},[list]);
|
||||
|
||||
function onSuccess(){
|
||||
const url = `/${owner}/${projectsId}/quit.json`;
|
||||
axios.post(url).then(result=>{
|
||||
if(result){
|
||||
showNotification("已成功退出仓库!");
|
||||
history.push(`/${current_user && current_user.login}`);
|
||||
}
|
||||
}).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}>
|
||||
{
|
||||
|
|
@ -68,8 +83,9 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
|
|||
</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} }}>
|
||||
|
|
@ -135,6 +151,10 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
|
|||
</Link>
|
||||
</li>
|
||||
}
|
||||
{
|
||||
item.menu_name === "quit" &&
|
||||
<a onClick={()=>setVisible(true)}><i className="iconfont icon-tuichuicon color-grey-3 mr5 font-14"></i>退出仓库</a>
|
||||
}
|
||||
</React.Fragment>
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
import React from 'react';
|
||||
import { AlignCenter } from '../../Component/layout';
|
||||
import Modals from '../../Component/PublicModal/Index';
|
||||
import { Button } from 'antd';
|
||||
|
||||
function QuitBox({ visible , onCancel ,onSuccess , name }) {
|
||||
return(
|
||||
<Modals
|
||||
visible={visible}
|
||||
onCancel={onCancel}
|
||||
title={"退出仓库"}
|
||||
btn={
|
||||
<div>
|
||||
<Button size={'large'} onClick={onCancel}>取消</Button>
|
||||
<Button type={"danger"} size={"large"} onClick={onSuccess}>确定</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="desc">
|
||||
<AlignCenter className="descMain">
|
||||
<i className="iconfont icon-jinggao1 mr10 font-20 red"></i>确定退出 {name} 仓库吗?</AlignCenter>
|
||||
<p style={{textAlign:"center"}}>请进行确认以防数据的丢失</p>
|
||||
</div>
|
||||
</Modals>
|
||||
)
|
||||
}
|
||||
export default QuitBox;
|
||||
|
|
@ -6,7 +6,7 @@ import MergeFooter from './merge_footer';
|
|||
import { returnbar , turnbar } from 'educoder';
|
||||
import { Base64 } from 'js-base64';
|
||||
|
||||
import '../Order/order.css';
|
||||
import '../Order/order.scss';
|
||||
import './merge.css';
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { Component } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Tag } from "antd";
|
||||
import { Tag, Tooltip } from "antd";
|
||||
import { AlignCenter } from '../Component/layout';
|
||||
import { getImageUrl, turnbar } from "educoder";
|
||||
import "./merge.css";
|
||||
|
|
@ -157,7 +157,7 @@ class MergeItem extends Component {
|
|||
"--"
|
||||
)}
|
||||
</li>
|
||||
<li>{item.version || "--"}</li>
|
||||
<li>{item.version ? <Tooltip placement="topLeft" title={item.version}>{item.version}</Tooltip> : "--"}</li>
|
||||
|
||||
<li>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import Commits from './Commits';
|
|||
import Comments from '../comments/comments';
|
||||
import Files from './Files';
|
||||
|
||||
import '../Order/order.css';
|
||||
import '../Order/order.scss';
|
||||
import './merge.css';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import {
|
|||
} from "antd";
|
||||
import "./merge.css";
|
||||
import RenderHtml from "../../components/render-html";
|
||||
import "../Order/order.css";
|
||||
import "../Order/order.scss";
|
||||
import MergeLinkFooter from "./MergeLinkFooter";
|
||||
|
||||
const TextArea = Input.TextArea;
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { Component } from "react";
|
||||
import { Input, Select , Spin, Alert } from "antd";
|
||||
import axios from "axios";
|
||||
import "../Order/order.css";
|
||||
import "../Order/order.scss";
|
||||
import "./merge.css";
|
||||
import MergeForm from "./merge_form";
|
||||
import MergeFooter from "./merge_footer";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { Component } from "react";
|
||||
import { Input, Select, Button, Spin, Empty } from "antd";
|
||||
import axios from "axios";
|
||||
import "../Order/order.css";
|
||||
import "../Order/order.scss";
|
||||
import "./merge.css";
|
||||
import MergeForm from "./merge_form";
|
||||
import MergeFooter from "./merge_footer";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { Component } from "react";
|
||||
import { Input, Dropdown, Menu, Icon, Pagination, Spin } from "antd";
|
||||
import "./merge.css";
|
||||
import "../Order/order.css";
|
||||
import "../Order/order.scss";
|
||||
import "../Order/index.scss";
|
||||
import NoneData from "./no_data";
|
||||
import MergeItem from "./MergeItem";
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Tabs } from 'antd';
|
|||
import Commits from './Commits';
|
||||
import Files from './Files';
|
||||
|
||||
import '../Order/order.css';
|
||||
import '../Order/order.scss';
|
||||
import './merge.css';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { Component } from "react";
|
|||
import { Button, Form, Menu, Input, Select, Tag, Checkbox, Spin } from "antd";
|
||||
import axios from "axios";
|
||||
|
||||
import "../Order/order.css";
|
||||
import "../Order/order.scss";
|
||||
import "./merge.css";
|
||||
import MDEditor from "../../modules/tpm/challengesnew/tpm-md-editor";
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -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
1361
src/forge/Newfile/extensions/alex-ext-public.typescript-language-features-worker.js
Executable file
File diff suppressed because it is too large
Load Diff
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,28 @@
|
|||
.noticeMenu{
|
||||
padding:0px 30px;
|
||||
.noticeMenu {
|
||||
padding: 0px 30px;
|
||||
display: flex;
|
||||
border-bottom: 1px solid #eee;
|
||||
li{
|
||||
li {
|
||||
font-size: 16px;
|
||||
padding:0px;
|
||||
margin-right:30px;
|
||||
padding: 0px;
|
||||
margin-right: 30px;
|
||||
height: 70px;
|
||||
line-height: 70px;
|
||||
position: relative;
|
||||
transform: none;
|
||||
a{
|
||||
a {
|
||||
display: flex;
|
||||
}
|
||||
&.active a span{
|
||||
color: #1890ff;
|
||||
&.active a span {
|
||||
color: $primary-color;
|
||||
}
|
||||
.unNum{
|
||||
.unNum {
|
||||
color: #d38900;
|
||||
font-size: 12px;
|
||||
border-radius: 13px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
padding:0px 4px;
|
||||
padding: 0px 4px;
|
||||
min-width: 23px;
|
||||
text-align: center;
|
||||
background-color: #ffe4b3;
|
||||
|
|
@ -32,30 +32,31 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.notifyList{
|
||||
padding:0px 30px;
|
||||
li{
|
||||
.notifyList {
|
||||
padding: 0px 30px;
|
||||
li {
|
||||
display: flex;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding:20px 0px;
|
||||
.notifyImg{
|
||||
padding: 20px 0px;
|
||||
.notifyImg {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 50%;
|
||||
margin-right: 15px;
|
||||
}
|
||||
.notifyFlex{
|
||||
flex:1;
|
||||
p{
|
||||
margin:0px;
|
||||
.notifyFlex {
|
||||
flex: 1;
|
||||
p {
|
||||
margin: 0px;
|
||||
max-width: 660px;
|
||||
}
|
||||
.notifyInfos{
|
||||
.notifyInfos {
|
||||
margin-bottom: 8px;
|
||||
|
||||
}
|
||||
}
|
||||
&:last-child{
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import { Modal } from 'antd';
|
||||
|
||||
import './order.css';
|
||||
import './order.scss';
|
||||
function AmplifyImg(props) {
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import Attachments from "../Upload/attachment";
|
|||
import RenderHtml from "../../components/render-html";
|
||||
import Comments from "../comments/comments";
|
||||
import Claims from "../claims/claims"
|
||||
import "./order.css";
|
||||
import "./order.scss";
|
||||
|
||||
class Detail extends Component {
|
||||
constructor(props) {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue