Skip to content

Commit e9c04c7

Browse files
authored
Merge pull request cangzhang#7 from cangzhang/feat/mr-detail
feat: complete mr detail webview logic
2 parents 185072c + 3da9d17 commit e9c04c7

File tree

13 files changed

+344
-81
lines changed

13 files changed

+344
-81
lines changed

package.json

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,25 @@
1212
],
1313
"main": "./out/extension",
1414
"activationEvents": [
15-
"onCommand:codingPlugin.helloWorld",
15+
"onCustomEditor:customEditor.mrDetail",
1616
"onView:codingPlugin.treeMR",
1717
"onView:codingPlugin.treeDepot",
1818
"onView:codingPlugin.webview"
1919
],
2020
"contributes": {
21-
"commands": [
21+
"customEditors": [
2222
{
23-
"command": "codingPlugin.helloWorld",
24-
"title": "Hello World"
25-
},
23+
"viewType": "customEditor.mrDetail",
24+
"displayName": "MR Detail",
25+
"selector": [
26+
{
27+
"fileNamePattern": "hosts"
28+
}
29+
],
30+
"priority": "default"
31+
}
32+
],
33+
"commands": [
2634
{
2735
"command": "codingPlugin.mrTreeItemClick",
2836
"title": "Click MR Tree Item"
@@ -37,16 +45,6 @@
3745
}
3846
],
3947
"menus": {
40-
"editor/context": [
41-
{
42-
"command": "codingPlugin.helloWorld",
43-
"group": "z_commands",
44-
"when": "editorTextFocus"
45-
},
46-
{
47-
"group": "z_commands"
48-
}
49-
],
5048
"view/item/context": [
5149
{
5250
"command": "codingPlugin.createDepot",

src/customEditors/mergeRequest.ts

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import hx from 'hbuilderx';
2+
import path from 'path';
3+
import toast from '../utils/toast';
4+
5+
interface IMessage {
6+
command: string;
7+
data: any;
8+
}
9+
10+
const { CustomDocument, CustomEditorProvider } = hx.CustomEditor;
11+
12+
class MRCustomDocument extends CustomDocument {
13+
constructor(uri: string) {
14+
super(uri);
15+
}
16+
17+
dispose() {
18+
super.dispose();
19+
}
20+
}
21+
22+
export default class MRCustomEditorProvider extends CustomEditorProvider {
23+
constructor(context: any) {
24+
super();
25+
this.context = context;
26+
this.panel = null;
27+
}
28+
29+
listen(webViewPanel: IWebviewPanel) {
30+
webViewPanel.webView.onDidReceiveMessage((message: IMessage) => {
31+
console.log('webview receive message => ', message);
32+
const { command, data } = message;
33+
34+
switch (command) {
35+
case 'webview.mrDetail':
36+
hx.env.openExternal(data);
37+
break;
38+
case 'webview.toast':
39+
toast.error(data);
40+
break;
41+
default:
42+
hx.commands.executeCommand(command);
43+
return;
44+
}
45+
});
46+
47+
webViewPanel.onDidDispose(function () {
48+
console.log('custom editor disposed');
49+
});
50+
}
51+
52+
update(data: any) {
53+
if (!this.panel) {
54+
setTimeout(() => {
55+
this.update(data);
56+
}, 500);
57+
return;
58+
}
59+
const webview = this.panel?.webView;
60+
const fileInfo = hx.Uri.file(path.resolve(__dirname, '../../out/webviews/main.js'));
61+
62+
const config = hx.workspace.getConfiguration();
63+
const colorScheme = config.get('editor.colorScheme');
64+
65+
const COLORS: Record<string, string> = {
66+
Monokai: 'themeDark',
67+
'Atom One Dark': 'themeDarkBlue',
68+
Default: 'themeLight',
69+
};
70+
71+
webview.html = `
72+
<html>
73+
<body class='${COLORS[colorScheme]}'>
74+
<div>
75+
<div id='root'></div>
76+
</div>
77+
<script>
78+
window.__CODING__ = '${JSON.stringify(data)}'
79+
</script>
80+
<script src='${fileInfo}'></script>
81+
</body>
82+
</html>
83+
`;
84+
}
85+
86+
openCustomDocument(uri: any) {
87+
return Promise.resolve(new MRCustomDocument(uri));
88+
}
89+
90+
resolveCustomEditor(document: any, webViewPanel: IWebviewPanel) {
91+
this.panel = webViewPanel;
92+
this.listen(webViewPanel);
93+
}
94+
95+
saveCustomDocument(document: any) {
96+
return true;
97+
}
98+
99+
saveCustomDocumentAs(document: any, destination: any) {
100+
return true;
101+
}
102+
}

src/extension.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,35 @@
11
import init from './init';
2-
import WebviewProvider from './webview';
32
import CodingServer from './services/codingServer';
3+
import WebviewProvider from './webviews';
44
import ACTIONS, { dispatch } from './utils/actions';
55
import { proxyCtx } from './utils/proxy';
66
import toast from './utils/toast';
77
import { readConfig } from './services/dcloud';
88

9-
const accessToken = '7e4d9d17f87875e731d536d13635a700ddf52b12';
9+
// const accessToken = '7e4d9d17f87875e731d536d13635a700ddf52b12';
10+
// const user = {
11+
// id: 8005956,
12+
// avatar: 'https://coding-net-production-static-ci.codehub.cn/WM-TEXT-AVATAR-lvVeBfbGLtCPdcsAOPod.jpg',
13+
// global_key: 'PDCOwrBjib',
14+
// name: 'uniquemo',
15+
// path: '/u/PDCOwrBjib',
16+
// team: 'uniquemo',
17+
// };
18+
19+
const accessToken = '6e15bbb9960810111c90086a6efc07a923dea5a3';
1020
const user = {
11-
id: 8005956,
21+
id: 8003868,
1222
avatar: 'https://coding-net-production-static-ci.codehub.cn/WM-TEXT-AVATAR-lvVeBfbGLtCPdcsAOPod.jpg',
13-
global_key: 'PDCOwrBjib',
14-
name: 'uniquemo',
15-
path: '/u/PDCOwrBjib',
16-
team: 'uniquemo',
23+
global_key: 'dHzOCagiSb',
24+
name: '莫泳欣',
25+
path: '/u/dHzOCagiSb',
26+
team: 'codingcorp',
1727
};
1828

1929
async function activate(context: IContext) {
2030
// TODO: 认证,拿到用户信息
21-
2231
const webviewProvider = new WebviewProvider();
32+
2333
const repoInfo = await CodingServer.getRepoParams();
2434
console.log('repoInfo ==> ', repoInfo);
2535
const token = await readConfig(`token`);

src/init.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import hx from 'hbuilderx';
22
import DepotTreeDataProvider from './trees/depot';
33
import MRTreeDataProvider from './trees/mr';
4+
import MRCustomEditorProvider from './customEditors/mergeRequest';
45

56
import toast from './utils/toast';
67
import ACTIONS, { dispatch } from './utils/actions';
@@ -10,23 +11,16 @@ import * as DCloudService from './services/dcloud';
1011
const { registerCommand } = hx.commands;
1112

1213
export function registerCommands(context: IContext) {
13-
const { codingServer, webviewProvider } = context;
14-
15-
context.subscriptions.push(
16-
registerCommand('codingPlugin.helloWorld', () => {
17-
toast.info('hello');
18-
}),
19-
);
14+
const { codingServer } = context;
2015

2116
context.subscriptions.push(
2217
registerCommand('codingPlugin.mrTreeItemClick', async function ([team, mrItem]: [string, IMRItem]) {
2318
const matchRes = mrItem.path.match(/\/p\/([^/]+)\/d\/([^/]+)\/git\/merge\/([0-9]+)/);
2419
if (matchRes) {
2520
const [, project, repo, mergeRequestIId] = matchRes;
26-
const result = await codingServer.getMrDetail({ team, project, repo, mergeRequestIId });
27-
webviewProvider.update({
21+
context.webviewProvider.update({
2822
session: codingServer.session,
29-
mrItem: result,
23+
mergeRequestIId,
3024
repoInfo: {
3125
team,
3226
project,
@@ -52,6 +46,12 @@ export function registerCommands(context: IContext) {
5246
const depot = await hx.window.showInputBox({
5347
prompt: '请输入仓库名',
5448
});
49+
50+
if (!depot) {
51+
toast.warn('仓库名不能为空');
52+
return;
53+
}
54+
5555
const team = codingServer.session?.user?.team;
5656
await codingServer.createDepot(team, depot, depot);
5757
toast.info('仓库创建成功');
@@ -91,6 +91,16 @@ export function clear(context: IContext) {
9191
context.subscriptions.forEach(({ dispose }) => dispose());
9292
}
9393

94+
export function registerCustomEditors(context: IContext) {
95+
const mrCustomEditor = new MRCustomEditorProvider(context);
96+
hx.window.registerCustomEditorProvider('customEditor.mrDetail', mrCustomEditor);
97+
98+
dispatch(ACTIONS.SET_MR_CUSTOM_EDITOR, {
99+
context,
100+
value: mrCustomEditor,
101+
});
102+
}
103+
94104
async function initCredentials(context: IContext) {
95105
try {
96106
let hbToken = await DCloudService.readConfig(`hbToken`);

src/typings/common.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ export interface ISessionData {
2727

2828
export interface IReviewer {
2929
reviewer: IUserInfo;
30+
value: number;
31+
volunteer: string;
3032
}
3133

3234
export interface IMRItem {

src/typings/hbuilderx.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ interface IContext {
99
subscriptions: any[];
1010
ctx: {
1111
[key: string]: any;
12-
},
12+
};
1313
[key: string]: any;
1414
}
1515

1616
interface IWebviewPanel {
1717
webView: any;
1818
postMessage: (message: any) => void;
19+
onDidDispose: (cb: () => void) => void;
20+
dispose: () => void;
1921
}
2022

2123
interface ITreeItem {

src/utils/actions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const enum ACTIONS {
22
SET_DEPOTS = 'SET_DEPOTS',
33
SET_SELECTED_DEPOT = 'SET_SELECTED_DEPOT',
44
SET_CTX = 'SET_CTX',
5+
SET_MR_CUSTOM_EDITOR = 'SET_MR_CUSTOM_EDITOR',
56
}
67

78
interface IPayload {
@@ -20,6 +21,9 @@ export const dispatch = (type: ACTIONS, { context, value }: IPayload) => {
2021
case ACTIONS.SET_CTX:
2122
context.ctx = value;
2223
break;
24+
case ACTIONS.SET_MR_CUSTOM_EDITOR:
25+
context.mrCustomEditor = value;
26+
break;
2327
default:
2428
return;
2529
}

src/utils/mr.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import hx from 'hbuilderx';
2+
import os from 'os';
13
import { IRepoInfo, IDepot, IUserInfo } from '../typings/common';
24

35
export const getMrListParams = (selectedDepot: IDepot, depots: IDepot[], user: IUserInfo): IRepoInfo | undefined => {
@@ -17,3 +19,21 @@ export const getMrListParams = (selectedDepot: IDepot, depots: IDepot[], user: I
1719
}
1820
}
1921
};
22+
23+
export const getHostsPath = () => {
24+
const operatingSystem = os.platform();
25+
let file;
26+
switch (operatingSystem) {
27+
case 'win32':
28+
break;
29+
case 'darwin':
30+
default:
31+
file = '/etc/hosts';
32+
}
33+
return file;
34+
};
35+
36+
export const openHosts = () => {
37+
const hostsPath = getHostsPath();
38+
hx.workspace.openTextDocument(hostsPath);
39+
};

src/webview.ts renamed to src/webviews/index.ts

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import hx from 'hbuilderx';
22
import path from 'path';
3-
import toast from './utils/toast';
3+
import toast from '../utils/toast';
44

55
interface IMessage {
66
command: string;
@@ -44,18 +44,29 @@ export default class WebviewProvider {
4444

4545
update(data: any) {
4646
const webview = this.panel.webView;
47-
const fileInfo = hx.Uri.file(path.resolve(__dirname, '../out/webviews/main.js'));
47+
const fileInfo = hx.Uri.file(path.resolve(__dirname, '../../out/webviews/main.js'));
48+
49+
const config = hx.workspace.getConfiguration();
50+
const colorScheme = config.get('editor.colorScheme');
51+
52+
const COLORS: Record<string, string> = {
53+
Monokai: 'themeDark',
54+
'Atom One Dark': 'themeDarkBlue',
55+
Default: 'themeLight',
56+
};
4857

4958
webview.html = `
50-
<body>
51-
<div>
52-
<div id='root'></div>
53-
</div>
54-
<script>
55-
window.__CODING__ = '${JSON.stringify(data)}'
56-
</script>
57-
<script src='${fileInfo}'></script>
58-
</body>
59+
<html>
60+
<body class='${COLORS[colorScheme]}'>
61+
<div>
62+
<div id='root'></div>
63+
</div>
64+
<script>
65+
window.__CODING__ = '${JSON.stringify(data)}'
66+
</script>
67+
<script src='${fileInfo}'></script>
68+
</body>
69+
</html>
5970
`;
6071
}
6172
}

webpack.config.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ module.exports = {
88
path: path.resolve(__dirname, 'out/webviews'),
99
filename: '[name].js',
1010
},
11-
// devtool: 'cheap-module-source-map',
1211
resolve: {
1312
extensions: ['.js', '.ts', '.tsx', '.json'],
1413
},

0 commit comments

Comments
 (0)